Brush Assets: Switch to a single "Brush" active tool #117491
|
@ -2777,7 +2777,7 @@ class VIEW3D_MT_object_animation(Menu):
|
|||
layout = self.layout
|
||||
|
||||
layout.operator("anim.keyframe_insert", text="Insert Keyframe")
|
||||
layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set")
|
||||
layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set").always_prompt = True
|
||||
layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframes...")
|
||||
layout.operator("anim.keyframe_clear_v3d", text="Clear Keyframes...")
|
||||
layout.operator("anim.keying_set_active_set", text="Change Keying Set...")
|
||||
|
@ -3042,7 +3042,7 @@ class VIEW3D_MT_object_context_menu(Menu):
|
|||
layout.separator()
|
||||
|
||||
layout.operator("anim.keyframe_insert", text="Insert Keyframe")
|
||||
layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set")
|
||||
layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set").always_prompt = True
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
@ -4160,7 +4160,7 @@ class VIEW3D_MT_pose_context_menu(Menu):
|
|||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
|
||||
layout.operator("anim.keyframe_insert", text="Insert Keyframe")
|
||||
layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set")
|
||||
layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe with Keying Set").always_prompt = True
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
|
|
@ -19,6 +19,11 @@ struct ReportList;
|
|||
struct UserDef;
|
||||
struct WorkspaceConfigFileData;
|
||||
|
||||
/**
|
||||
* The suffix used for blendfiles managed by the asset system.
|
||||
*/
|
||||
#define BLENDER_ASSET_FILE_SUFFIX ".asset.blend"
|
||||
|
||||
/**
|
||||
* Check whether given path ends with a blend file compatible extension
|
||||
* (`.blend`, `.ble` or `.blend.gz`).
|
||||
|
|
|
@ -142,6 +142,14 @@ struct Main {
|
|||
* could try to use more refined detection on load. */
|
||||
bool has_forward_compatibility_issues;
|
||||
|
||||
/**
|
||||
* The currently opened .blend file was created as an asset library storage.
|
||||
*
|
||||
* This is used to warn the user when they try to save it from Blender UI, since this will likely
|
||||
* break the automatic management from the asset library system.
|
||||
*/
|
||||
bool is_asset_repository;
|
||||
|
||||
/** Commit timestamp from `buildinfo`. */
|
||||
uint64_t build_commit_timestamp;
|
||||
/** Commit Hash from `buildinfo`. */
|
||||
|
@ -299,6 +307,17 @@ void BKE_main_merge(Main *bmain_dst, Main **r_bmain_src, MainMergeReport &report
|
|||
*/
|
||||
bool BKE_main_is_empty(Main *bmain);
|
||||
|
||||
/**
|
||||
* Check whether the bmain has issues, e.g. for reporting in the status bar.
|
||||
*/
|
||||
bool BKE_main_has_issues(const Main *bmain);
|
||||
|
||||
/**
|
||||
* Check whether user confirmation should be required when overwriting this `bmain` into its source
|
||||
* blendfile.
|
||||
*/
|
||||
bool BKE_main_needs_overwrite_confirm(const Main *bmain);
|
||||
|
||||
void BKE_main_lock(Main *bmain);
|
||||
void BKE_main_unlock(Main *bmain);
|
||||
|
||||
|
|
|
@ -853,6 +853,9 @@ static void setup_app_data(bContext *C,
|
|||
* nullptr curscreen)... */
|
||||
else if (ELEM(nullptr, bfd->curscreen, bfd->curscene)) {
|
||||
BKE_report(reports->reports, RPT_WARNING, "Library file, loading empty scene");
|
||||
if (blender::StringRefNull(bfd->main->filepath).endswith(BLENDER_ASSET_FILE_SUFFIX)) {
|
||||
bfd->main->is_asset_repository = true;
|
||||
}
|
||||
mode = LOAD_UI_OFF;
|
||||
}
|
||||
else if (G.fileflags & G_FILE_NO_UI) {
|
||||
|
|
|
@ -444,6 +444,16 @@ bool BKE_main_is_empty(Main *bmain)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool BKE_main_has_issues(const Main *bmain)
|
||||
{
|
||||
return bmain->has_forward_compatibility_issues || bmain->is_asset_repository;
|
||||
}
|
||||
|
||||
bool BKE_main_needs_overwrite_confirm(const Main *bmain)
|
||||
{
|
||||
return bmain->has_forward_compatibility_issues || bmain->is_asset_repository;
|
||||
}
|
||||
|
||||
void BKE_main_lock(Main *bmain)
|
||||
{
|
||||
BLI_spin_lock((SpinLock *)bmain->lock);
|
||||
|
|
|
@ -1381,7 +1381,13 @@ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA *
|
|||
else if (prop_type == PROP_STRING) {
|
||||
char type_id[MAX_ID_NAME - 2];
|
||||
RNA_property_string_get(op->ptr, prop, type_id);
|
||||
ks = ANIM_keyingset_get_from_idname(scene, type_id);
|
||||
|
||||
if (strcmp(type_id, "__ACTIVE__") == 0) {
|
||||
ks = ANIM_keyingset_get_from_enum_type(scene, scene->active_keyingset);
|
||||
}
|
||||
else {
|
||||
ks = ANIM_keyingset_get_from_idname(scene, type_id);
|
||||
}
|
||||
|
||||
if (ks == nullptr) {
|
||||
BKE_reportf(op->reports, RPT_ERROR, "Keying set '%s' not found", type_id);
|
||||
|
|
|
@ -6558,13 +6558,47 @@ void uiTemplateInputStatus(uiLayout *layout, bContext *C)
|
|||
}
|
||||
}
|
||||
|
||||
static void ui_template_status_info_warnings_messages(Main *bmain,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
std::string &warning_message,
|
||||
std::string ®ular_message,
|
||||
std::string &tooltip_message)
|
||||
{
|
||||
tooltip_message = "";
|
||||
char statusbar_info_flag = U.statusbar_flag;
|
||||
|
||||
if (bmain->has_forward_compatibility_issues) {
|
||||
warning_message = ED_info_statusbar_string_ex(
|
||||
bmain, scene, view_layer, STATUSBAR_SHOW_VERSION);
|
||||
statusbar_info_flag &= ~STATUSBAR_SHOW_VERSION;
|
||||
|
||||
char writer_ver_str[12];
|
||||
BKE_blender_version_blendfile_string_from_values(
|
||||
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1);
|
||||
tooltip_message += fmt::format(RPT_("File saved by newer Blender\n({}), expect loss of data"),
|
||||
writer_ver_str);
|
||||
}
|
||||
if (bmain->is_asset_repository) {
|
||||
if (!tooltip_message.empty()) {
|
||||
tooltip_message += "\n\n";
|
||||
}
|
||||
tooltip_message += RPT_(
|
||||
"This file is managed by the Blender asset system\n"
|
||||
"By editing it as a regular blend file, it will no longer\n"
|
||||
"be possible to update its assets through the asset browser");
|
||||
}
|
||||
|
||||
regular_message = ED_info_statusbar_string_ex(bmain, scene, view_layer, statusbar_info_flag);
|
||||
}
|
||||
|
||||
void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
|
||||
if (!bmain->has_forward_compatibility_issues) {
|
||||
if (!BKE_main_has_issues(bmain)) {
|
||||
const char *status_info_txt = ED_info_statusbar_string(bmain, scene, view_layer);
|
||||
uiItemL(layout, status_info_txt, ICON_NONE);
|
||||
return;
|
||||
|
@ -6573,13 +6607,13 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
|
|||
/* Blender version part is shown as warning area when there are forward compatibility issues with
|
||||
* currently loaded .blend file. */
|
||||
|
||||
const char *status_info_txt = ED_info_statusbar_string_ex(
|
||||
bmain, scene, view_layer, (U.statusbar_flag & ~STATUSBAR_SHOW_VERSION));
|
||||
uiItemL(layout, status_info_txt, ICON_NONE);
|
||||
std::string warning_message;
|
||||
std::string regular_message;
|
||||
std::string tooltip_message;
|
||||
ui_template_status_info_warnings_messages(
|
||||
bmain, scene, view_layer, warning_message, regular_message, tooltip_message);
|
||||
|
||||
status_info_txt = ED_info_statusbar_string_ex(bmain, scene, view_layer, STATUSBAR_SHOW_VERSION);
|
||||
|
||||
uiBut *but;
|
||||
uiItemL(layout, regular_message.c_str(), ICON_NONE);
|
||||
|
||||
const uiStyle *style = UI_style_get();
|
||||
uiLayout *ui_abs = uiLayoutAbsolute(layout, false);
|
||||
|
@ -6587,27 +6621,28 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
|
|||
eUIEmbossType previous_emboss = UI_block_emboss_get(block);
|
||||
|
||||
UI_fontstyle_set(&style->widgetlabel);
|
||||
int width = int(
|
||||
BLF_width(style->widgetlabel.uifont_id, status_info_txt, strlen(status_info_txt)));
|
||||
width = max_ii(width, int(10 * UI_SCALE_FAC));
|
||||
const int width = max_ii(int(BLF_width(style->widgetlabel.uifont_id,
|
||||
warning_message.c_str(),
|
||||
warning_message.length())),
|
||||
int(10 * UI_SCALE_FAC));
|
||||
|
||||
UI_block_align_begin(block);
|
||||
|
||||
/* Background for icon. */
|
||||
but = uiDefBut(block,
|
||||
UI_BTYPE_ROUNDBOX,
|
||||
0,
|
||||
"",
|
||||
0,
|
||||
0,
|
||||
UI_UNIT_X + (6 * UI_SCALE_FAC),
|
||||
UI_UNIT_Y,
|
||||
nullptr,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0,
|
||||
0,
|
||||
"");
|
||||
uiBut *but = uiDefBut(block,
|
||||
UI_BTYPE_ROUNDBOX,
|
||||
0,
|
||||
"",
|
||||
0,
|
||||
0,
|
||||
UI_UNIT_X + (6 * UI_SCALE_FAC),
|
||||
UI_UNIT_Y,
|
||||
nullptr,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0,
|
||||
0,
|
||||
"");
|
||||
/* UI_BTYPE_ROUNDBOX's bg color is set in but->col. */
|
||||
UI_GetThemeColorType4ubv(TH_INFO_WARNING, SPACE_INFO, but->col);
|
||||
|
||||
|
@ -6634,14 +6669,13 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
|
|||
UI_block_align_end(block);
|
||||
UI_block_emboss_set(block, UI_EMBOSS_NONE);
|
||||
|
||||
/* The report icon itself. */
|
||||
static char compat_error_msg[256];
|
||||
char writer_ver_str[12];
|
||||
BKE_blender_version_blendfile_string_from_values(
|
||||
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1);
|
||||
SNPRINTF(compat_error_msg,
|
||||
RPT_("File saved by newer Blender\n(%s), expect loss of data"),
|
||||
writer_ver_str);
|
||||
/* Tool tips have to be static currently.
|
||||
* FIXME This is a horrible requirement from uiBut, should probably just store an std::string for
|
||||
* the tooltip as well? */
|
||||
static char tooltip_static_storage[256];
|
||||
BLI_strncpy(tooltip_static_storage, tooltip_message.c_str(), sizeof(tooltip_static_storage));
|
||||
|
||||
/* The warning icon itself. */
|
||||
but = uiDefIconBut(block,
|
||||
UI_BTYPE_BUT,
|
||||
0,
|
||||
|
@ -6655,25 +6689,27 @@ void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
|
|||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
compat_error_msg);
|
||||
tooltip_static_storage);
|
||||
UI_GetThemeColorType4ubv(TH_INFO_WARNING_TEXT, SPACE_INFO, but->col);
|
||||
but->col[3] = 255; /* This theme color is RBG only, so have to set alpha here. */
|
||||
|
||||
/* The report message. */
|
||||
but = uiDefBut(block,
|
||||
UI_BTYPE_BUT,
|
||||
0,
|
||||
status_info_txt,
|
||||
UI_UNIT_X,
|
||||
0,
|
||||
short(width + UI_UNIT_X),
|
||||
UI_UNIT_Y,
|
||||
nullptr,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
compat_error_msg);
|
||||
/* The warning message, if any. */
|
||||
if (!warning_message.empty()) {
|
||||
but = uiDefBut(block,
|
||||
UI_BTYPE_BUT,
|
||||
0,
|
||||
warning_message.c_str(),
|
||||
UI_UNIT_X,
|
||||
0,
|
||||
short(width + UI_UNIT_X),
|
||||
UI_UNIT_Y,
|
||||
nullptr,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
tooltip_static_storage);
|
||||
}
|
||||
|
||||
UI_block_emboss_set(block, previous_emboss);
|
||||
}
|
||||
|
|
|
@ -445,8 +445,9 @@ static bool restore_coords(
|
|||
MutableSpan<float3> positions = ss->vert_positions;
|
||||
|
||||
if (ss->shapekey_active) {
|
||||
MutableSpan<float3> vertCos(static_cast<float3 *>(ss->shapekey_active->data),
|
||||
ss->shapekey_active->totelem);
|
||||
float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active);
|
||||
const Span key_positions(reinterpret_cast<const float3 *>(vertCos),
|
||||
ss->shapekey_active->totelem);
|
||||
|
||||
if (!unode.orig_position.is_empty()) {
|
||||
if (ss->deform_modifiers_active) {
|
||||
|
@ -467,11 +468,13 @@ static bool restore_coords(
|
|||
}
|
||||
|
||||
/* Propagate new coords to keyblock. */
|
||||
SCULPT_vertcos_to_key(ob, ss->shapekey_active, vertCos);
|
||||
SCULPT_vertcos_to_key(ob, ss->shapekey_active, key_positions);
|
||||
|
||||
/* PBVH uses its own vertex array, so coords should be */
|
||||
/* propagated to PBVH here. */
|
||||
BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos);
|
||||
BKE_pbvh_vert_coords_apply(ss->pbvh, key_positions);
|
||||
|
||||
MEM_freeN(vertCos);
|
||||
}
|
||||
else {
|
||||
if (!unode.orig_position.is_empty()) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_enumerable_thread_specific.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_task.hh"
|
||||
|
||||
|
@ -234,8 +235,8 @@ void obj_parallel_chunked_output(FormatHandler &fh, int tot_count, const Functio
|
|||
return;
|
||||
}
|
||||
/* Give each chunk its own temporary output buffer, and process them in parallel. */
|
||||
std::vector<FormatHandler> buffers(chunk_count);
|
||||
blender::threading::parallel_for(IndexRange(chunk_count), 1, [&](IndexRange range) {
|
||||
Array<FormatHandler> buffers(chunk_count);
|
||||
threading::parallel_for(IndexRange(chunk_count), 1, [&](IndexRange range) {
|
||||
for (const int r : range) {
|
||||
int i_start = r * chunk_size;
|
||||
int i_end = std::min(i_start + chunk_size, tot_count);
|
||||
|
@ -259,6 +260,10 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh,
|
|||
|
||||
const Mesh *mesh = obj_mesh_data.get_mesh();
|
||||
const StringRef name = mesh->active_color_attribute;
|
||||
|
||||
const float4x4 transform = obj_mesh_data.get_world_axes_transform();
|
||||
const Span<float3> positions = obj_mesh_data.get_mesh()->vert_positions();
|
||||
|
||||
if (write_colors && !name.is_empty()) {
|
||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||
const VArray<ColorGeometry4f> attribute = *attributes.lookup_or_default<ColorGeometry4f>(
|
||||
|
@ -266,7 +271,7 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh,
|
|||
|
||||
BLI_assert(tot_count == attribute.size());
|
||||
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {
|
||||
float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.global_scale);
|
||||
const float3 vertex = math::transform_point(transform, positions[i]);
|
||||
ColorGeometry4f linear = attribute.get(i);
|
||||
float srgb[3];
|
||||
linearrgb_to_srgb_v3_v3(srgb, linear);
|
||||
|
@ -275,7 +280,7 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh,
|
|||
}
|
||||
else {
|
||||
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {
|
||||
float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.global_scale);
|
||||
const float3 vertex = math::transform_point(transform, positions[i]);
|
||||
buf.write_obj_vertex(vertex[0], vertex[1], vertex[2]);
|
||||
});
|
||||
}
|
||||
|
@ -283,9 +288,8 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh,
|
|||
|
||||
void OBJWriter::write_uv_coords(FormatHandler &fh, OBJMesh &r_obj_mesh_data) const
|
||||
{
|
||||
const Vector<float2> &uv_coords = r_obj_mesh_data.get_uv_coords();
|
||||
const int tot_count = uv_coords.size();
|
||||
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {
|
||||
const Span<float2> uv_coords = r_obj_mesh_data.get_uv_coords();
|
||||
obj_parallel_chunked_output(fh, uv_coords.size(), [&](FormatHandler &buf, int i) {
|
||||
const float2 &uv_vertex = uv_coords[i];
|
||||
buf.write_obj_uv(uv_vertex[0], uv_vertex[1]);
|
||||
});
|
||||
|
@ -294,9 +298,8 @@ void OBJWriter::write_uv_coords(FormatHandler &fh, OBJMesh &r_obj_mesh_data) con
|
|||
void OBJWriter::write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data)
|
||||
{
|
||||
/* Poly normals should be calculated earlier via store_normal_coords_and_indices. */
|
||||
const Vector<float3> &normal_coords = obj_mesh_data.get_normal_coords();
|
||||
const int tot_count = normal_coords.size();
|
||||
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {
|
||||
const Span<float3> normal_coords = obj_mesh_data.get_normal_coords();
|
||||
obj_parallel_chunked_output(fh, normal_coords.size(), [&](FormatHandler &buf, int i) {
|
||||
const float3 &normal = normal_coords[i];
|
||||
buf.write_obj_normal(normal[0], normal[1], normal[2]);
|
||||
});
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
#include "BKE_mesh.hh"
|
||||
#include "BKE_mesh_mapping.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_sort.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
@ -70,7 +70,8 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj
|
|||
this->materials[i] = BKE_object_material_get_eval(obj_eval, i + 1);
|
||||
}
|
||||
|
||||
set_world_axes_transform(*obj_eval, export_params.forward_axis, export_params.up_axis);
|
||||
set_world_axes_transform(
|
||||
*obj_eval, export_params.forward_axis, export_params.up_axis, export_params.global_scale);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,11 +104,11 @@ void OBJMesh::clear()
|
|||
owned_export_mesh_ = nullptr;
|
||||
}
|
||||
export_mesh_ = nullptr;
|
||||
loop_to_uv_index_.clear_and_shrink();
|
||||
loop_to_uv_index_ = {};
|
||||
uv_coords_.clear_and_shrink();
|
||||
loop_to_normal_index_.clear_and_shrink();
|
||||
loop_to_normal_index_ = {};
|
||||
normal_coords_.clear_and_shrink();
|
||||
poly_order_.clear_and_shrink();
|
||||
poly_order_ = {};
|
||||
if (poly_smooth_groups_) {
|
||||
MEM_freeN(poly_smooth_groups_);
|
||||
poly_smooth_groups_ = nullptr;
|
||||
|
@ -146,23 +147,27 @@ void OBJMesh::triangulate_mesh_eval()
|
|||
|
||||
void OBJMesh::set_world_axes_transform(const Object &obj_eval,
|
||||
const eIOAxis forward,
|
||||
const eIOAxis up)
|
||||
const eIOAxis up,
|
||||
const float global_scale)
|
||||
{
|
||||
float axes_transform[3][3];
|
||||
unit_m3(axes_transform);
|
||||
float3x3 axes_transform;
|
||||
/* +Y-forward and +Z-up are the default Blender axis settings. */
|
||||
mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform);
|
||||
mul_m4_m3m4(world_and_axes_transform_, axes_transform, obj_eval.object_to_world);
|
||||
/* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */
|
||||
mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, obj_eval.object_to_world[3]);
|
||||
world_and_axes_transform_[3][3] = obj_eval.object_to_world[3][3];
|
||||
mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform.ptr());
|
||||
|
||||
const float4x4 object_to_world(obj_eval.object_to_world);
|
||||
const float3x3 transform = axes_transform * float3x3(object_to_world);
|
||||
|
||||
world_and_axes_transform_ = float4x4(transform);
|
||||
world_and_axes_transform_.location() = axes_transform * object_to_world.location();
|
||||
world_and_axes_transform_[3][3] = object_to_world[3][3];
|
||||
|
||||
world_and_axes_transform_ = math::from_scale<float4x4>(float3(global_scale)) *
|
||||
world_and_axes_transform_;
|
||||
|
||||
/* Normals need inverse transpose of the regular matrix to handle non-uniform scale. */
|
||||
float normal_matrix[3][3];
|
||||
copy_m3_m4(normal_matrix, world_and_axes_transform_);
|
||||
invert_m3_m3(world_and_axes_normal_transform_, normal_matrix);
|
||||
transpose_m3(world_and_axes_normal_transform_);
|
||||
mirrored_transform_ = is_negative_m3(world_and_axes_normal_transform_);
|
||||
world_and_axes_normal_transform_ = math::transpose(math::invert(transform));
|
||||
|
||||
mirrored_transform_ = math::is_negative(world_and_axes_normal_transform_);
|
||||
}
|
||||
|
||||
int OBJMesh::tot_vertices() const
|
||||
|
@ -227,7 +232,7 @@ void OBJMesh::calc_poly_order()
|
|||
}
|
||||
const VArraySpan<int> material_indices_span(material_indices);
|
||||
|
||||
poly_order_.resize(material_indices_span.size());
|
||||
poly_order_.reinitialize(material_indices_span.size());
|
||||
for (const int i : material_indices_span.index_range()) {
|
||||
poly_order_[i] = i;
|
||||
}
|
||||
|
@ -258,14 +263,6 @@ const char *OBJMesh::get_object_mesh_name() const
|
|||
return export_mesh_->id.name + 2;
|
||||
}
|
||||
|
||||
float3 OBJMesh::calc_vertex_coords(const int vert_index, const float global_scale) const
|
||||
{
|
||||
float3 r_coords = mesh_positions_[vert_index];
|
||||
mul_m4_v3(world_and_axes_transform_, r_coords);
|
||||
mul_v3_fl(r_coords, global_scale);
|
||||
return r_coords;
|
||||
}
|
||||
|
||||
Span<int> OBJMesh::calc_poly_vertex_indices(const int face_index) const
|
||||
{
|
||||
return mesh_corner_verts_.slice(mesh_faces_[face_index]);
|
||||
|
@ -292,7 +289,7 @@ void OBJMesh::store_uv_coords_and_indices()
|
|||
uv_to_index.reserve(export_mesh_->verts_num);
|
||||
uv_coords_.reserve(export_mesh_->verts_num);
|
||||
|
||||
loop_to_uv_index_.resize(uv_map.size());
|
||||
loop_to_uv_index_.reinitialize(uv_map.size());
|
||||
|
||||
for (int index = 0; index < int(uv_map.size()); index++) {
|
||||
float2 uv = uv_map[index];
|
||||
|
@ -317,11 +314,9 @@ Span<int> OBJMesh::calc_poly_uv_indices(const int face_index) const
|
|||
|
||||
float3 OBJMesh::calc_poly_normal(const int face_index) const
|
||||
{
|
||||
float3 r_poly_normal = bke::mesh::face_normal_calc(
|
||||
mesh_positions_, mesh_corner_verts_.slice(mesh_faces_[face_index]));
|
||||
mul_m3_v3(world_and_axes_normal_transform_, r_poly_normal);
|
||||
normalize_v3(r_poly_normal);
|
||||
return r_poly_normal;
|
||||
const Span<int> face_verts = mesh_corner_verts_.slice(mesh_faces_[face_index]);
|
||||
const float3 normal = bke::mesh::face_normal_calc(mesh_positions_, face_verts);
|
||||
return math::normalize(world_and_axes_normal_transform_ * normal);
|
||||
}
|
||||
|
||||
/** Round \a f to \a round_digits decimal digits. */
|
||||
|
@ -352,7 +347,7 @@ void OBJMesh::store_normal_coords_and_indices()
|
|||
Map<float3, int> normal_to_index;
|
||||
/* We don't know how many unique normals there will be, but this is a guess. */
|
||||
normal_to_index.reserve(export_mesh_->faces_num);
|
||||
loop_to_normal_index_.resize(export_mesh_->corners_num);
|
||||
loop_to_normal_index_.reinitialize(export_mesh_->corners_num);
|
||||
loop_to_normal_index_.fill(-1);
|
||||
|
||||
Span<float3> corner_normals;
|
||||
|
@ -368,17 +363,15 @@ void OBJMesh::store_normal_coords_and_indices()
|
|||
bool need_per_loop_normals = !corner_normals.is_empty() || !(sharp_faces_[face_index]);
|
||||
if (need_per_loop_normals) {
|
||||
for (const int corner : face) {
|
||||
float3 loop_normal;
|
||||
BLI_assert(corner < export_mesh_->corners_num);
|
||||
copy_v3_v3(loop_normal, corner_normals[corner]);
|
||||
mul_m3_v3(world_and_axes_normal_transform_, loop_normal);
|
||||
normalize_v3(loop_normal);
|
||||
float3 rounded_loop_normal = round_float3_to_n_digits(loop_normal, round_digits);
|
||||
int loop_norm_index = normal_to_index.lookup_default(rounded_loop_normal, -1);
|
||||
const float3 normal = math::normalize(world_and_axes_normal_transform_ *
|
||||
corner_normals[corner]);
|
||||
const float3 rounded = round_float3_to_n_digits(normal, round_digits);
|
||||
int loop_norm_index = normal_to_index.lookup_default(rounded, -1);
|
||||
if (loop_norm_index == -1) {
|
||||
loop_norm_index = cur_normal_index++;
|
||||
normal_to_index.add(rounded_loop_normal, loop_norm_index);
|
||||
normal_coords_.append(rounded_loop_normal);
|
||||
normal_to_index.add(rounded, loop_norm_index);
|
||||
normal_coords_.append(rounded);
|
||||
}
|
||||
loop_to_normal_index_[corner] = loop_norm_index;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <optional>
|
||||
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_offset_indices.hh"
|
||||
#include "BLI_utility_mixins.hh"
|
||||
|
@ -44,14 +45,14 @@ class OBJMesh : NonCopyable {
|
|||
* Final transform of an object obtained from export settings (up_axis, forward_axis) and the
|
||||
* object's world transform matrix.
|
||||
*/
|
||||
float world_and_axes_transform_[4][4];
|
||||
float world_and_axes_normal_transform_[3][3];
|
||||
float4x4 world_and_axes_transform_;
|
||||
float3x3 world_and_axes_normal_transform_;
|
||||
bool mirrored_transform_;
|
||||
|
||||
/**
|
||||
* Per-loop UV index.
|
||||
*/
|
||||
Vector<int> loop_to_uv_index_;
|
||||
Array<int> loop_to_uv_index_;
|
||||
/*
|
||||
* UV vertices.
|
||||
*/
|
||||
|
@ -60,7 +61,7 @@ class OBJMesh : NonCopyable {
|
|||
/**
|
||||
* Per-loop normal index.
|
||||
*/
|
||||
Vector<int> loop_to_normal_index_;
|
||||
Array<int> loop_to_normal_index_;
|
||||
/*
|
||||
* Normal coords.
|
||||
*/
|
||||
|
@ -81,7 +82,7 @@ class OBJMesh : NonCopyable {
|
|||
/**
|
||||
* Order in which the polygons should be written into the file (sorted by material index).
|
||||
*/
|
||||
Vector<int> poly_order_;
|
||||
Array<int> poly_order_;
|
||||
|
||||
public:
|
||||
Array<const Material *> materials;
|
||||
|
@ -132,10 +133,11 @@ class OBJMesh : NonCopyable {
|
|||
*/
|
||||
const char *get_object_mesh_name() const;
|
||||
|
||||
/**
|
||||
* Calculate coordinates of the vertex at the given index.
|
||||
*/
|
||||
float3 calc_vertex_coords(int vert_index, float global_scale) const;
|
||||
const float4x4 &get_world_axes_transform() const
|
||||
{
|
||||
return world_and_axes_transform_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate vertex indices of all vertices of the polygon at the given index.
|
||||
*/
|
||||
|
@ -221,6 +223,9 @@ class OBJMesh : NonCopyable {
|
|||
/**
|
||||
* Set the final transform after applying axes settings and an Object's world transform.
|
||||
*/
|
||||
void set_world_axes_transform(const Object &obj_eval, eIOAxis forward, eIOAxis up);
|
||||
void set_world_axes_transform(const Object &obj_eval,
|
||||
eIOAxis forward,
|
||||
eIOAxis up,
|
||||
float global_scale);
|
||||
};
|
||||
} // namespace blender::io::obj
|
||||
|
|
|
@ -138,7 +138,7 @@ filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_par
|
|||
return {std::move(r_exportable_meshes), std::move(r_exportable_nurbs)};
|
||||
}
|
||||
|
||||
static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_mesh,
|
||||
static void write_mesh_objects(const Span<std::unique_ptr<OBJMesh>> exportable_as_mesh,
|
||||
OBJWriter &obj_writer,
|
||||
MTLWriter *mtl_writer,
|
||||
const OBJExportParams &export_params)
|
||||
|
@ -147,7 +147,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
|
|||
* we have to have the output text buffer for each object,
|
||||
* and write them all into the file at the end. */
|
||||
size_t count = exportable_as_mesh.size();
|
||||
std::vector<FormatHandler> buffers(count);
|
||||
Array<FormatHandler> buffers(count);
|
||||
|
||||
/* Serial: gather material indices, ensure normals & edges. */
|
||||
Vector<Vector<int>> mtlindices;
|
||||
|
@ -163,7 +163,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
|
|||
}
|
||||
|
||||
/* Parallel over meshes: store normal coords & indices, uv coords and indices. */
|
||||
blender::threading::parallel_for(IndexRange(count), 1, [&](IndexRange range) {
|
||||
threading::parallel_for(IndexRange(count), 1, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
OBJMesh &obj = *exportable_as_mesh[i];
|
||||
if (export_params.export_normals) {
|
||||
|
@ -189,7 +189,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
|
|||
}
|
||||
|
||||
/* Parallel over meshes: main result writing. */
|
||||
blender::threading::parallel_for(IndexRange(count), 1, [&](IndexRange range) {
|
||||
threading::parallel_for(IndexRange(count), 1, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
OBJMesh &obj = *exportable_as_mesh[i];
|
||||
auto &fh = buffers[i];
|
||||
|
@ -239,7 +239,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
|
|||
/**
|
||||
* Export NURBS Curves in parameter form, not as vertices and edges.
|
||||
*/
|
||||
static void write_nurbs_curve_objects(const Vector<std::unique_ptr<OBJCurve>> &exportable_as_nurbs,
|
||||
static void write_nurbs_curve_objects(const Span<std::unique_ptr<OBJCurve>> exportable_as_nurbs,
|
||||
const OBJWriter &obj_writer)
|
||||
{
|
||||
FormatHandler fh;
|
||||
|
@ -280,8 +280,7 @@ void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, co
|
|||
auto [exportable_as_mesh, exportable_as_nurbs] = filter_supported_objects(depsgraph,
|
||||
export_params);
|
||||
|
||||
write_mesh_objects(
|
||||
std::move(exportable_as_mesh), *frame_writer, mtl_writer.get(), export_params);
|
||||
write_mesh_objects(exportable_as_mesh, *frame_writer, mtl_writer.get(), export_params);
|
||||
if (mtl_writer) {
|
||||
mtl_writer->write_header(export_params.blen_filepath);
|
||||
char dest_dir[PATH_MAX];
|
||||
|
@ -298,7 +297,7 @@ void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, co
|
|||
dest_dir,
|
||||
export_params.export_pbr_extensions);
|
||||
}
|
||||
write_nurbs_curve_objects(std::move(exportable_as_nurbs), *frame_writer);
|
||||
write_nurbs_curve_objects(exportable_as_nurbs, *frame_writer);
|
||||
}
|
||||
|
||||
bool append_frame_to_filename(const char *filepath, const int frame, char *r_filepath_with_frames)
|
||||
|
|
|
@ -930,18 +930,15 @@ enum wmConfirmPosition {
|
|||
};
|
||||
|
||||
struct wmConfirmDetails {
|
||||
char title[1024];
|
||||
char message[1024];
|
||||
char message2[1024];
|
||||
char confirm_button[256];
|
||||
char cancel_button[256];
|
||||
std::string title;
|
||||
std::string message;
|
||||
std::string message2;
|
||||
std::string confirm_text;
|
||||
int icon;
|
||||
wmConfirmSize size;
|
||||
wmConfirmPosition position;
|
||||
bool confirm_default;
|
||||
bool cancel_default;
|
||||
bool mouse_move_quit;
|
||||
bool red_alert;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -3552,8 +3552,8 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *
|
|||
}
|
||||
|
||||
if (blendfile_path[0] != '\0') {
|
||||
if (CTX_data_main(C)->has_forward_compatibility_issues) {
|
||||
wm_save_file_forwardcompat_dialog(C, op);
|
||||
if (BKE_main_needs_overwrite_confirm(CTX_data_main(C))) {
|
||||
wm_save_file_overwrite_dialog(C, op);
|
||||
ret = OPERATOR_INTERFACE;
|
||||
}
|
||||
else {
|
||||
|
@ -3629,8 +3629,8 @@ static void wm_clear_recent_files_confirm(bContext * /*C*/,
|
|||
wmOperator * /*op*/,
|
||||
wmConfirmDetails *confirm)
|
||||
{
|
||||
STRNCPY(confirm->message, IFACE_("Remove all items from the recent files list"));
|
||||
STRNCPY(confirm->confirm_button, IFACE_("Remove All"));
|
||||
confirm->message = IFACE_("Remove all items from the recent files list");
|
||||
confirm->confirm_text = IFACE_("Remove All");
|
||||
confirm->position = WM_WARNING_POSITION_CENTER;
|
||||
confirm->size = WM_WARNING_SIZE_LARGE;
|
||||
confirm->cancel_default = true;
|
||||
|
@ -3907,49 +3907,62 @@ static void wm_free_operator_properties_callback(void *user_data)
|
|||
IDP_FreeProperty(properties);
|
||||
}
|
||||
|
||||
static const char *save_file_forwardcompat_dialog_name = "save_file_forwardcompat_popup";
|
||||
static const char *save_file_overwrite_dialog_name = "save_file_overwrite_popup";
|
||||
|
||||
static void file_forwardcompat_detailed_info_show(uiLayout *parent_layout, Main *bmain)
|
||||
static void file_overwrite_detailed_info_show(uiLayout *parent_layout, Main *bmain)
|
||||
{
|
||||
uiLayout *layout = uiLayoutColumn(parent_layout, true);
|
||||
/* Trick to make both lines of text below close enough to look like they are part of a same
|
||||
* block. */
|
||||
uiLayoutSetScaleY(layout, 0.70f);
|
||||
|
||||
char writer_ver_str[16];
|
||||
char current_ver_str[16];
|
||||
if (bmain->versionfile == BLENDER_VERSION) {
|
||||
BKE_blender_version_blendfile_string_from_values(
|
||||
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, bmain->subversionfile);
|
||||
BKE_blender_version_blendfile_string_from_values(
|
||||
current_ver_str, sizeof(current_ver_str), BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION);
|
||||
}
|
||||
else {
|
||||
BKE_blender_version_blendfile_string_from_values(
|
||||
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1);
|
||||
BKE_blender_version_blendfile_string_from_values(
|
||||
current_ver_str, sizeof(current_ver_str), BLENDER_VERSION, -1);
|
||||
if (bmain->has_forward_compatibility_issues) {
|
||||
char writer_ver_str[16];
|
||||
char current_ver_str[16];
|
||||
if (bmain->versionfile == BLENDER_VERSION) {
|
||||
BKE_blender_version_blendfile_string_from_values(
|
||||
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, bmain->subversionfile);
|
||||
BKE_blender_version_blendfile_string_from_values(
|
||||
current_ver_str, sizeof(current_ver_str), BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION);
|
||||
}
|
||||
else {
|
||||
BKE_blender_version_blendfile_string_from_values(
|
||||
writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1);
|
||||
BKE_blender_version_blendfile_string_from_values(
|
||||
current_ver_str, sizeof(current_ver_str), BLENDER_VERSION, -1);
|
||||
}
|
||||
|
||||
char message_line1[256];
|
||||
char message_line2[256];
|
||||
SNPRINTF(message_line1,
|
||||
RPT_("This file was saved by a newer version of Blender (%s)"),
|
||||
writer_ver_str);
|
||||
SNPRINTF(message_line2,
|
||||
RPT_("Saving it with this Blender (%s) may cause loss of data"),
|
||||
current_ver_str);
|
||||
uiItemL(layout, message_line1, ICON_NONE);
|
||||
uiItemL(layout, message_line2, ICON_NONE);
|
||||
}
|
||||
|
||||
char message_line1[256];
|
||||
char message_line2[256];
|
||||
SNPRINTF(message_line1,
|
||||
RPT_("This file was saved by a newer version of Blender (%s)"),
|
||||
writer_ver_str);
|
||||
SNPRINTF(message_line2,
|
||||
RPT_("Saving it with this Blender (%s) may cause loss of data"),
|
||||
current_ver_str);
|
||||
uiItemL(layout, message_line1, ICON_NONE);
|
||||
uiItemL(layout, message_line2, ICON_NONE);
|
||||
if (bmain->is_asset_repository) {
|
||||
if (bmain->has_forward_compatibility_issues) {
|
||||
uiItemS_ex(layout, 1.4f);
|
||||
}
|
||||
|
||||
uiItemL(layout, RPT_("This file is managed by the Blender asset system"), ICON_NONE);
|
||||
uiItemL(
|
||||
layout, RPT_("By overwriting it as a regular blend file, it will no longer "), ICON_NONE);
|
||||
uiItemL(layout, RPT_("be possible to update its assets through the asset browser"), ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void save_file_forwardcompat_cancel(bContext *C, void *arg_block, void * /*arg_data*/)
|
||||
static void save_file_overwrite_cancel(bContext *C, void *arg_block, void * /*arg_data*/)
|
||||
{
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
UI_popup_block_close(C, win, static_cast<uiBlock *>(arg_block));
|
||||
}
|
||||
|
||||
static void save_file_forwardcompat_cancel_button(uiBlock *block, wmGenericCallback *post_action)
|
||||
static void save_file_overwrite_cancel_button(uiBlock *block, wmGenericCallback *post_action)
|
||||
{
|
||||
uiBut *but = uiDefIconTextBut(block,
|
||||
UI_BTYPE_BUT,
|
||||
|
@ -3966,11 +3979,11 @@ static void save_file_forwardcompat_cancel_button(uiBlock *block, wmGenericCallb
|
|||
0,
|
||||
0,
|
||||
"");
|
||||
UI_but_func_set(but, save_file_forwardcompat_cancel, block, post_action);
|
||||
UI_but_func_set(but, save_file_overwrite_cancel, block, post_action);
|
||||
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
|
||||
}
|
||||
|
||||
static void save_file_forwardcompat_overwrite(bContext *C, void *arg_block, void *arg_data)
|
||||
static void save_file_overwrite_confirm(bContext *C, void *arg_block, void *arg_data)
|
||||
{
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
|
||||
|
@ -3993,8 +4006,7 @@ static void save_file_forwardcompat_overwrite(bContext *C, void *arg_block, void
|
|||
WM_generic_callback_free(callback);
|
||||
}
|
||||
|
||||
static void save_file_forwardcompat_overwrite_button(uiBlock *block,
|
||||
wmGenericCallback *post_action)
|
||||
static void save_file_overwrite_confirm_button(uiBlock *block, wmGenericCallback *post_action)
|
||||
{
|
||||
uiBut *but = uiDefIconTextBut(block,
|
||||
UI_BTYPE_BUT,
|
||||
|
@ -4011,20 +4023,37 @@ static void save_file_forwardcompat_overwrite_button(uiBlock *block,
|
|||
0,
|
||||
0,
|
||||
"");
|
||||
UI_but_func_set(but, save_file_forwardcompat_overwrite, block, post_action);
|
||||
UI_but_func_set(but, save_file_overwrite_confirm, block, post_action);
|
||||
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
|
||||
UI_but_flag_enable(but, UI_BUT_REDALERT);
|
||||
}
|
||||
|
||||
static void save_file_forwardcompat_saveas(bContext *C, void *arg_block, void * /*arg_data*/)
|
||||
static void save_file_overwrite_saveas(bContext *C, void *arg_block, void * /*arg_data*/)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
UI_popup_block_close(C, win, static_cast<uiBlock *>(arg_block));
|
||||
|
||||
WM_operator_name_call(C, "WM_OT_save_as_mainfile", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
|
||||
PointerRNA props_ptr;
|
||||
wmOperatorType *ot = WM_operatortype_find("WM_OT_save_as_mainfile", false);
|
||||
WM_operator_properties_create_ptr(&props_ptr, ot);
|
||||
|
||||
if (bmain->is_asset_repository) {
|
||||
/* If needed, substitute the 'proposed' Save As filepath by replacing the `.asset.blend` part
|
||||
* of it by just `.blend`. */
|
||||
std::string filepath = BKE_main_blendfile_path(bmain);
|
||||
if (blender::StringRef(filepath).endswith(BLENDER_ASSET_FILE_SUFFIX)) {
|
||||
filepath.replace(
|
||||
filepath.rfind(BLENDER_ASSET_FILE_SUFFIX), strlen(BLENDER_ASSET_FILE_SUFFIX), ".blend");
|
||||
RNA_string_set(&props_ptr, "filepath", filepath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr);
|
||||
WM_operator_properties_free(&props_ptr);
|
||||
}
|
||||
|
||||
static void save_file_forwardcompat_saveas_button(uiBlock *block, wmGenericCallback *post_action)
|
||||
static void save_file_overwrite_saveas_button(uiBlock *block, wmGenericCallback *post_action)
|
||||
{
|
||||
uiBut *but = uiDefIconTextBut(block,
|
||||
UI_BTYPE_BUT,
|
||||
|
@ -4041,19 +4070,17 @@ static void save_file_forwardcompat_saveas_button(uiBlock *block, wmGenericCallb
|
|||
0,
|
||||
0,
|
||||
"");
|
||||
UI_but_func_set(but, save_file_forwardcompat_saveas, block, post_action);
|
||||
UI_but_func_set(but, save_file_overwrite_saveas, block, post_action);
|
||||
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
|
||||
UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
|
||||
}
|
||||
|
||||
static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C,
|
||||
ARegion *region,
|
||||
void *arg1)
|
||||
static uiBlock *block_create_save_file_overwrite_dialog(bContext *C, ARegion *region, void *arg1)
|
||||
{
|
||||
wmGenericCallback *post_action = static_cast<wmGenericCallback *>(arg1);
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
uiBlock *block = UI_block_begin(C, region, save_file_forwardcompat_dialog_name, UI_EMBOSS);
|
||||
uiBlock *block = UI_block_begin(C, region, save_file_overwrite_dialog_name, UI_EMBOSS);
|
||||
UI_block_flag_enable(
|
||||
block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT);
|
||||
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
|
||||
|
@ -4061,8 +4088,27 @@ static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C,
|
|||
uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_WARNING);
|
||||
|
||||
/* Title. */
|
||||
uiItemL_ex(
|
||||
layout, RPT_("Overwrite file with an older Blender version?"), ICON_NONE, true, false);
|
||||
if (bmain->has_forward_compatibility_issues) {
|
||||
if (bmain->is_asset_repository) {
|
||||
uiItemL_ex(
|
||||
layout,
|
||||
RPT_("Convert asset blend file to regular blend file with an older Blender version?"),
|
||||
ICON_NONE,
|
||||
true,
|
||||
false);
|
||||
}
|
||||
else {
|
||||
uiItemL_ex(
|
||||
layout, RPT_("Overwrite file with an older Blender version?"), ICON_NONE, true, false);
|
||||
}
|
||||
}
|
||||
else if (bmain->is_asset_repository) {
|
||||
uiItemL_ex(
|
||||
layout, RPT_("Convert asset blend file to regular blend file?"), ICON_NONE, true, false);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
/* Filename. */
|
||||
const char *blendfile_path = BKE_main_blendfile_path(CTX_data_main(C));
|
||||
|
@ -4079,7 +4125,7 @@ static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C,
|
|||
uiItemL(layout, filename, ICON_NONE);
|
||||
|
||||
/* Detailed message info. */
|
||||
file_forwardcompat_detailed_info_show(layout, bmain);
|
||||
file_overwrite_detailed_info_show(layout, bmain);
|
||||
|
||||
uiItemS_ex(layout, 4.0f);
|
||||
|
||||
|
@ -4089,7 +4135,7 @@ static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C,
|
|||
uiLayoutSetScaleY(split, 1.2f);
|
||||
|
||||
uiLayoutColumn(split, false);
|
||||
save_file_forwardcompat_overwrite_button(block, post_action);
|
||||
save_file_overwrite_confirm_button(block, post_action);
|
||||
|
||||
uiLayout *split_right = uiLayoutSplit(split, 0.1f, true);
|
||||
|
||||
|
@ -4097,25 +4143,25 @@ static uiBlock *block_create_save_file_forwardcompat_dialog(bContext *C,
|
|||
/* Empty space. */
|
||||
|
||||
uiLayoutColumn(split_right, false);
|
||||
save_file_forwardcompat_cancel_button(block, post_action);
|
||||
save_file_overwrite_cancel_button(block, post_action);
|
||||
|
||||
uiLayoutColumn(split_right, false);
|
||||
save_file_forwardcompat_saveas_button(block, post_action);
|
||||
save_file_overwrite_saveas_button(block, post_action);
|
||||
|
||||
UI_block_bounds_set_centered(block, 14 * UI_SCALE_FAC);
|
||||
return block;
|
||||
}
|
||||
|
||||
void wm_save_file_forwardcompat_dialog(bContext *C, wmOperator *op)
|
||||
void wm_save_file_overwrite_dialog(bContext *C, wmOperator *op)
|
||||
{
|
||||
if (!UI_popup_block_name_exists(CTX_wm_screen(C), save_file_forwardcompat_dialog_name)) {
|
||||
if (!UI_popup_block_name_exists(CTX_wm_screen(C), save_file_overwrite_dialog_name)) {
|
||||
wmGenericCallback *callback = MEM_cnew<wmGenericCallback>(__func__);
|
||||
callback->exec = nullptr;
|
||||
callback->user_data = IDP_CopyProperty(op->properties);
|
||||
callback->free_user_data = wm_free_operator_properties_callback;
|
||||
|
||||
UI_popup_block_invoke(
|
||||
C, block_create_save_file_forwardcompat_dialog, callback, free_post_file_close_action);
|
||||
C, block_create_save_file_overwrite_dialog, callback, free_post_file_close_action);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4245,7 +4291,7 @@ static void wm_block_file_close_discard_button(uiBlock *block, wmGenericCallback
|
|||
|
||||
static void wm_block_file_close_save_button(uiBlock *block,
|
||||
wmGenericCallback *post_action,
|
||||
const bool has_forwardcompat_issues)
|
||||
const bool needs_overwrite_confirm)
|
||||
{
|
||||
uiBut *but = uiDefIconTextBut(
|
||||
block,
|
||||
|
@ -4253,7 +4299,7 @@ static void wm_block_file_close_save_button(uiBlock *block,
|
|||
0,
|
||||
ICON_NONE,
|
||||
/* Forward compatibility issues force using 'save as' operator instead of 'save' one. */
|
||||
has_forwardcompat_issues ? IFACE_("Save As...") : IFACE_("Save"),
|
||||
needs_overwrite_confirm ? IFACE_("Save As...") : IFACE_("Save"),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
@ -4289,7 +4335,7 @@ static uiBlock *block_create__close_file_dialog(bContext *C, ARegion *region, vo
|
|||
|
||||
uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_QUESTION);
|
||||
|
||||
const bool has_forwardcompat_issues = bmain->has_forward_compatibility_issues;
|
||||
const bool needs_overwrite_confirm = BKE_main_needs_overwrite_confirm(bmain);
|
||||
|
||||
/* Title. */
|
||||
uiItemL_ex(layout, RPT_("Save changes before closing?"), ICON_NONE, true, false);
|
||||
|
@ -4306,8 +4352,8 @@ static uiBlock *block_create__close_file_dialog(bContext *C, ARegion *region, vo
|
|||
uiItemL(layout, filename, ICON_NONE);
|
||||
|
||||
/* Potential forward compatibility issues message. */
|
||||
if (has_forwardcompat_issues) {
|
||||
file_forwardcompat_detailed_info_show(layout, bmain);
|
||||
if (needs_overwrite_confirm) {
|
||||
file_overwrite_detailed_info_show(layout, bmain);
|
||||
}
|
||||
|
||||
/* Image Saving Warnings. */
|
||||
|
@ -4416,7 +4462,7 @@ static uiBlock *block_create__close_file_dialog(bContext *C, ARegion *region, vo
|
|||
uiLayoutSetScaleY(split, 1.2f);
|
||||
|
||||
uiLayoutColumn(split, false);
|
||||
wm_block_file_close_save_button(block, post_action, has_forwardcompat_issues);
|
||||
wm_block_file_close_save_button(block, post_action, needs_overwrite_confirm);
|
||||
|
||||
uiLayoutColumn(split, false);
|
||||
wm_block_file_close_discard_button(block, post_action);
|
||||
|
@ -4442,7 +4488,7 @@ static uiBlock *block_create__close_file_dialog(bContext *C, ARegion *region, vo
|
|||
wm_block_file_close_cancel_button(block, post_action);
|
||||
|
||||
uiLayoutColumn(split_right, false);
|
||||
wm_block_file_close_save_button(block, post_action, has_forwardcompat_issues);
|
||||
wm_block_file_close_save_button(block, post_action, needs_overwrite_confirm);
|
||||
}
|
||||
|
||||
UI_block_bounds_set_centered(block, 14 * UI_SCALE_FAC);
|
||||
|
|
|
@ -1217,16 +1217,13 @@ static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_
|
|||
|
||||
wmConfirmDetails confirm = {{0}};
|
||||
|
||||
STRNCPY(confirm.title, WM_operatortype_description(C, op->type, op->ptr).c_str());
|
||||
STRNCPY(confirm.confirm_button, WM_operatortype_name(op->type, op->ptr).c_str());
|
||||
STRNCPY(confirm.cancel_button, IFACE_("Cancel"));
|
||||
confirm.title = WM_operatortype_description(C, op->type, op->ptr);
|
||||
confirm.confirm_text = WM_operatortype_name(op->type, op->ptr);
|
||||
confirm.icon = ALERT_ICON_WARNING;
|
||||
confirm.size = WM_WARNING_SIZE_SMALL;
|
||||
confirm.position = WM_WARNING_POSITION_MOUSE;
|
||||
confirm.confirm_default = true;
|
||||
confirm.cancel_default = false;
|
||||
confirm.mouse_move_quit = false;
|
||||
confirm.red_alert = false;
|
||||
|
||||
/* uiBlock.flag */
|
||||
int block_flags = UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT;
|
||||
|
@ -1248,21 +1245,23 @@ static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_
|
|||
const uiStyle *style = UI_style_get_dpi();
|
||||
int text_width = std::max(
|
||||
120 * UI_SCALE_FAC,
|
||||
BLF_width(style->widget.uifont_id, confirm.title, ARRAY_SIZE(confirm.title)));
|
||||
if (confirm.message[0]) {
|
||||
text_width = std::max(
|
||||
text_width,
|
||||
int(BLF_width(style->widget.uifont_id, confirm.message, ARRAY_SIZE(confirm.message))));
|
||||
BLF_width(style->widget.uifont_id, confirm.title.c_str(), confirm.title.length()));
|
||||
if (!confirm.message.empty()) {
|
||||
text_width = std::max(text_width,
|
||||
int(BLF_width(style->widget.uifont_id,
|
||||
confirm.message.c_str(),
|
||||
confirm.message.length())));
|
||||
}
|
||||
if (confirm.message2[0]) {
|
||||
text_width = std::max(
|
||||
text_width,
|
||||
int(BLF_width(style->widget.uifont_id, confirm.message2, ARRAY_SIZE(confirm.message2))));
|
||||
if (!confirm.message2.empty()) {
|
||||
text_width = std::max(text_width,
|
||||
int(BLF_width(style->widget.uifont_id,
|
||||
confirm.message2.c_str(),
|
||||
confirm.message2.length())));
|
||||
}
|
||||
|
||||
const bool small = confirm.size == WM_WARNING_SIZE_SMALL;
|
||||
const int padding = (small ? 7 : 14) * UI_SCALE_FAC;
|
||||
const short icon_size = (small ? (confirm.message[0] ? 48 : 32) : 64) * UI_SCALE_FAC;
|
||||
const short icon_size = (small ? (confirm.message.empty() ? 32 : 48) : 64) * UI_SCALE_FAC;
|
||||
const int dialog_width = icon_size + text_width + (style->columnspace * 2.5);
|
||||
const float split_factor = (float)icon_size / (float)(dialog_width - style->columnspace);
|
||||
|
||||
|
@ -1281,17 +1280,19 @@ static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_
|
|||
/* The rest of the content on the right. */
|
||||
layout = uiLayoutColumn(split_block, true);
|
||||
|
||||
if (confirm.title[0]) {
|
||||
if (!confirm.message[0]) {
|
||||
if (!confirm.title.empty()) {
|
||||
if (confirm.message.empty()) {
|
||||
uiItemS(layout);
|
||||
}
|
||||
uiItemL_ex(layout, confirm.title, ICON_NONE, true, false);
|
||||
uiItemL_ex(layout, confirm.title.c_str(), ICON_NONE, true, false);
|
||||
}
|
||||
if (confirm.message[0]) {
|
||||
uiItemL(layout, confirm.message, ICON_NONE);
|
||||
|
||||
if (!confirm.message.empty()) {
|
||||
uiItemL(layout, confirm.message.c_str(), ICON_NONE);
|
||||
}
|
||||
if (confirm.message2[0]) {
|
||||
uiItemL(layout, confirm.message2, ICON_NONE);
|
||||
|
||||
if (!confirm.message2.empty()) {
|
||||
uiItemL(layout, confirm.message2.c_str(), ICON_NONE);
|
||||
}
|
||||
|
||||
uiItemS_ex(layout, small ? 0.5f : 4.0f);
|
||||
|
@ -1315,7 +1316,7 @@ static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_
|
|||
UI_BTYPE_BUT,
|
||||
0,
|
||||
0,
|
||||
confirm.confirm_button,
|
||||
confirm.confirm_text.c_str(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
@ -1333,7 +1334,7 @@ static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_
|
|||
UI_BTYPE_BUT,
|
||||
0,
|
||||
0,
|
||||
confirm.cancel_button,
|
||||
IFACE_("Cancel"),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
@ -1351,7 +1352,7 @@ static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_
|
|||
UI_BTYPE_BUT,
|
||||
0,
|
||||
0,
|
||||
confirm.confirm_button,
|
||||
confirm.confirm_text.c_str(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
@ -1369,18 +1370,7 @@ static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_
|
|||
UI_but_func_set(cancel_but, wm_operator_block_cancel, op, block);
|
||||
UI_but_drawflag_disable(confirm_but, UI_BUT_TEXT_LEFT);
|
||||
UI_but_drawflag_disable(cancel_but, UI_BUT_TEXT_LEFT);
|
||||
|
||||
if (confirm.red_alert) {
|
||||
UI_but_flag_enable(confirm_but, UI_BUT_REDALERT);
|
||||
}
|
||||
else {
|
||||
if (confirm.cancel_default) {
|
||||
UI_but_flag_enable(cancel_but, UI_BUT_ACTIVE_DEFAULT);
|
||||
}
|
||||
else if (confirm.confirm_default) {
|
||||
UI_but_flag_enable(confirm_but, UI_BUT_ACTIVE_DEFAULT);
|
||||
}
|
||||
}
|
||||
UI_but_flag_enable(confirm.cancel_default ? cancel_but : confirm_but, UI_BUT_ACTIVE_DEFAULT);
|
||||
|
||||
if (confirm.position == WM_WARNING_POSITION_MOUSE) {
|
||||
int bounds_offset[2];
|
||||
|
|
|
@ -97,7 +97,7 @@ bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWind
|
|||
*
|
||||
* Important to ask confirmation, as this is a very common scenario of data loss.
|
||||
*/
|
||||
void wm_save_file_forwardcompat_dialog(bContext *C, wmOperator *op);
|
||||
void wm_save_file_overwrite_dialog(bContext *C, wmOperator *op);
|
||||
|
||||
void WM_OT_save_homefile(wmOperatorType *ot);
|
||||
void WM_OT_save_userpref(wmOperatorType *ot);
|
||||
|
|
|
@ -136,6 +136,7 @@ def main():
|
|||
from modules import render_report
|
||||
report = render_report.Report("Eevee Next", output_dir, oiiotool)
|
||||
report.set_pixelated(True)
|
||||
report.set_engine_name('eevee_next')
|
||||
report.set_reference_dir("eevee_next_renders")
|
||||
report.set_reference_override_dir(reference_override_dir)
|
||||
report.set_compare_engine('cycles', 'CPU')
|
||||
|
|
|
@ -76,6 +76,7 @@ def test_get_images(output_dir, filepath, reference_dir, reference_override_dir)
|
|||
class Report:
|
||||
__slots__ = (
|
||||
'title',
|
||||
'engine_name',
|
||||
'output_dir',
|
||||
'global_dir',
|
||||
'reference_dir',
|
||||
|
@ -104,6 +105,7 @@ class Report:
|
|||
self.compare_engine = None
|
||||
self.fail_threshold = 0.016
|
||||
self.fail_percent = 1
|
||||
self.engine_name = self.title.lower().replace(" ", "_")
|
||||
self.device = device
|
||||
self.blacklist = blacklist
|
||||
|
||||
|
@ -142,6 +144,9 @@ class Report:
|
|||
def set_compare_engine(self, other_engine, other_device=None):
|
||||
self.compare_engine = (other_engine, other_device)
|
||||
|
||||
def set_engine_name(self, engine_name):
|
||||
self.engine_name = engine_name
|
||||
|
||||
def run(self, dirpath, blender, arguments_cb, batch=False):
|
||||
# Run tests and output report.
|
||||
dirname = os.path.basename(dirpath)
|
||||
|
@ -232,7 +237,7 @@ class Report:
|
|||
if failed:
|
||||
message = """<div class="alert alert-danger" role="alert">"""
|
||||
message += """<p>Run this command to regenerate reference (ground truth) images:</p>"""
|
||||
message += """<p><tt>BLENDER_TEST_UPDATE=1 ctest -R %s</tt></p>""" % self.title.lower()
|
||||
message += """<p><tt>BLENDER_TEST_UPDATE=1 ctest -R %s</tt></p>""" % self.engine_name
|
||||
message += """<p>This then happens for new and failing tests; reference images of """ \
|
||||
"""passing test cases will not be updated. Be sure to commit the new reference """ \
|
||||
"""images to the SVN repository afterwards.</p>"""
|
||||
|
|
Loading…
Reference in New Issue