WIP: Brush assets project #106303
|
@ -445,8 +445,9 @@ static bool restore_coords(
|
||||||
MutableSpan<float3> positions = ss->vert_positions;
|
MutableSpan<float3> positions = ss->vert_positions;
|
||||||
|
|
||||||
if (ss->shapekey_active) {
|
if (ss->shapekey_active) {
|
||||||
MutableSpan<float3> vertCos(static_cast<float3 *>(ss->shapekey_active->data),
|
float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active);
|
||||||
ss->shapekey_active->totelem);
|
const Span key_positions(reinterpret_cast<const float3 *>(vertCos),
|
||||||
|
ss->shapekey_active->totelem);
|
||||||
|
|
||||||
if (!unode.orig_position.is_empty()) {
|
if (!unode.orig_position.is_empty()) {
|
||||||
if (ss->deform_modifiers_active) {
|
if (ss->deform_modifiers_active) {
|
||||||
|
@ -467,11 +468,13 @@ static bool restore_coords(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Propagate new coords to keyblock. */
|
/* 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 */
|
/* PBVH uses its own vertex array, so coords should be */
|
||||||
/* propagated to PBVH here. */
|
/* 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 {
|
else {
|
||||||
if (!unode.orig_position.is_empty()) {
|
if (!unode.orig_position.is_empty()) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "BLI_color.hh"
|
#include "BLI_color.hh"
|
||||||
#include "BLI_enumerable_thread_specific.hh"
|
#include "BLI_enumerable_thread_specific.hh"
|
||||||
|
#include "BLI_math_matrix.hh"
|
||||||
#include "BLI_path_util.h"
|
#include "BLI_path_util.h"
|
||||||
#include "BLI_task.hh"
|
#include "BLI_task.hh"
|
||||||
|
|
||||||
|
@ -234,8 +235,8 @@ void obj_parallel_chunked_output(FormatHandler &fh, int tot_count, const Functio
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Give each chunk its own temporary output buffer, and process them in parallel. */
|
/* Give each chunk its own temporary output buffer, and process them in parallel. */
|
||||||
std::vector<FormatHandler> buffers(chunk_count);
|
Array<FormatHandler> buffers(chunk_count);
|
||||||
blender::threading::parallel_for(IndexRange(chunk_count), 1, [&](IndexRange range) {
|
threading::parallel_for(IndexRange(chunk_count), 1, [&](IndexRange range) {
|
||||||
for (const int r : range) {
|
for (const int r : range) {
|
||||||
int i_start = r * chunk_size;
|
int i_start = r * chunk_size;
|
||||||
int i_end = std::min(i_start + chunk_size, tot_count);
|
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 Mesh *mesh = obj_mesh_data.get_mesh();
|
||||||
const StringRef name = mesh->active_color_attribute;
|
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()) {
|
if (write_colors && !name.is_empty()) {
|
||||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||||
const VArray<ColorGeometry4f> attribute = *attributes.lookup_or_default<ColorGeometry4f>(
|
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());
|
BLI_assert(tot_count == attribute.size());
|
||||||
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {
|
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);
|
ColorGeometry4f linear = attribute.get(i);
|
||||||
float srgb[3];
|
float srgb[3];
|
||||||
linearrgb_to_srgb_v3_v3(srgb, linear);
|
linearrgb_to_srgb_v3_v3(srgb, linear);
|
||||||
|
@ -275,7 +280,7 @@ void OBJWriter::write_vertex_coords(FormatHandler &fh,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {
|
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]);
|
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
|
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 Span<float2> uv_coords = r_obj_mesh_data.get_uv_coords();
|
||||||
const int tot_count = uv_coords.size();
|
obj_parallel_chunked_output(fh, uv_coords.size(), [&](FormatHandler &buf, int i) {
|
||||||
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {
|
|
||||||
const float2 &uv_vertex = uv_coords[i];
|
const float2 &uv_vertex = uv_coords[i];
|
||||||
buf.write_obj_uv(uv_vertex[0], uv_vertex[1]);
|
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)
|
void OBJWriter::write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data)
|
||||||
{
|
{
|
||||||
/* Poly normals should be calculated earlier via store_normal_coords_and_indices. */
|
/* Poly normals should be calculated earlier via store_normal_coords_and_indices. */
|
||||||
const Vector<float3> &normal_coords = obj_mesh_data.get_normal_coords();
|
const Span<float3> normal_coords = obj_mesh_data.get_normal_coords();
|
||||||
const int tot_count = normal_coords.size();
|
obj_parallel_chunked_output(fh, normal_coords.size(), [&](FormatHandler &buf, int i) {
|
||||||
obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) {
|
|
||||||
const float3 &normal = normal_coords[i];
|
const float3 &normal = normal_coords[i];
|
||||||
buf.write_obj_normal(normal[0], normal[1], normal[2]);
|
buf.write_obj_normal(normal[0], normal[1], normal[2]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,12 +14,12 @@
|
||||||
#include "BKE_mesh.hh"
|
#include "BKE_mesh.hh"
|
||||||
#include "BKE_mesh_mapping.hh"
|
#include "BKE_mesh_mapping.hh"
|
||||||
#include "BKE_object.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_listbase.h"
|
||||||
#include "BLI_map.hh"
|
#include "BLI_map.hh"
|
||||||
|
#include "BLI_math_matrix.h"
|
||||||
|
#include "BLI_math_matrix.hh"
|
||||||
|
#include "BLI_math_rotation.h"
|
||||||
#include "BLI_sort.hh"
|
#include "BLI_sort.hh"
|
||||||
|
|
||||||
#include "DEG_depsgraph_query.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);
|
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;
|
owned_export_mesh_ = nullptr;
|
||||||
}
|
}
|
||||||
export_mesh_ = nullptr;
|
export_mesh_ = nullptr;
|
||||||
loop_to_uv_index_.clear_and_shrink();
|
loop_to_uv_index_ = {};
|
||||||
uv_coords_.clear_and_shrink();
|
uv_coords_.clear_and_shrink();
|
||||||
loop_to_normal_index_.clear_and_shrink();
|
loop_to_normal_index_ = {};
|
||||||
normal_coords_.clear_and_shrink();
|
normal_coords_.clear_and_shrink();
|
||||||
poly_order_.clear_and_shrink();
|
poly_order_ = {};
|
||||||
if (poly_smooth_groups_) {
|
if (poly_smooth_groups_) {
|
||||||
MEM_freeN(poly_smooth_groups_);
|
MEM_freeN(poly_smooth_groups_);
|
||||||
poly_smooth_groups_ = nullptr;
|
poly_smooth_groups_ = nullptr;
|
||||||
|
@ -146,23 +147,27 @@ void OBJMesh::triangulate_mesh_eval()
|
||||||
|
|
||||||
void OBJMesh::set_world_axes_transform(const Object &obj_eval,
|
void OBJMesh::set_world_axes_transform(const Object &obj_eval,
|
||||||
const eIOAxis forward,
|
const eIOAxis forward,
|
||||||
const eIOAxis up)
|
const eIOAxis up,
|
||||||
|
const float global_scale)
|
||||||
{
|
{
|
||||||
float axes_transform[3][3];
|
float3x3 axes_transform;
|
||||||
unit_m3(axes_transform);
|
|
||||||
/* +Y-forward and +Z-up are the default Blender axis settings. */
|
/* +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);
|
mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, axes_transform.ptr());
|
||||||
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. */
|
const float4x4 object_to_world(obj_eval.object_to_world);
|
||||||
mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, obj_eval.object_to_world[3]);
|
const float3x3 transform = axes_transform * float3x3(object_to_world);
|
||||||
world_and_axes_transform_[3][3] = obj_eval.object_to_world[3][3];
|
|
||||||
|
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. */
|
/* Normals need inverse transpose of the regular matrix to handle non-uniform scale. */
|
||||||
float normal_matrix[3][3];
|
world_and_axes_normal_transform_ = math::transpose(math::invert(transform));
|
||||||
copy_m3_m4(normal_matrix, world_and_axes_transform_);
|
|
||||||
invert_m3_m3(world_and_axes_normal_transform_, normal_matrix);
|
mirrored_transform_ = math::is_negative(world_and_axes_normal_transform_);
|
||||||
transpose_m3(world_and_axes_normal_transform_);
|
|
||||||
mirrored_transform_ = is_negative_m3(world_and_axes_normal_transform_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int OBJMesh::tot_vertices() const
|
int OBJMesh::tot_vertices() const
|
||||||
|
@ -227,7 +232,7 @@ void OBJMesh::calc_poly_order()
|
||||||
}
|
}
|
||||||
const VArraySpan<int> material_indices_span(material_indices);
|
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()) {
|
for (const int i : material_indices_span.index_range()) {
|
||||||
poly_order_[i] = i;
|
poly_order_[i] = i;
|
||||||
}
|
}
|
||||||
|
@ -258,14 +263,6 @@ const char *OBJMesh::get_object_mesh_name() const
|
||||||
return export_mesh_->id.name + 2;
|
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
|
Span<int> OBJMesh::calc_poly_vertex_indices(const int face_index) const
|
||||||
{
|
{
|
||||||
return mesh_corner_verts_.slice(mesh_faces_[face_index]);
|
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_to_index.reserve(export_mesh_->verts_num);
|
||||||
uv_coords_.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++) {
|
for (int index = 0; index < int(uv_map.size()); index++) {
|
||||||
float2 uv = uv_map[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 OBJMesh::calc_poly_normal(const int face_index) const
|
||||||
{
|
{
|
||||||
float3 r_poly_normal = bke::mesh::face_normal_calc(
|
const Span<int> face_verts = mesh_corner_verts_.slice(mesh_faces_[face_index]);
|
||||||
mesh_positions_, mesh_corner_verts_.slice(mesh_faces_[face_index]));
|
const float3 normal = bke::mesh::face_normal_calc(mesh_positions_, face_verts);
|
||||||
mul_m3_v3(world_and_axes_normal_transform_, r_poly_normal);
|
return math::normalize(world_and_axes_normal_transform_ * normal);
|
||||||
normalize_v3(r_poly_normal);
|
|
||||||
return r_poly_normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Round \a f to \a round_digits decimal digits. */
|
/** 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;
|
Map<float3, int> normal_to_index;
|
||||||
/* We don't know how many unique normals there will be, but this is a guess. */
|
/* We don't know how many unique normals there will be, but this is a guess. */
|
||||||
normal_to_index.reserve(export_mesh_->faces_num);
|
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);
|
loop_to_normal_index_.fill(-1);
|
||||||
|
|
||||||
Span<float3> corner_normals;
|
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]);
|
bool need_per_loop_normals = !corner_normals.is_empty() || !(sharp_faces_[face_index]);
|
||||||
if (need_per_loop_normals) {
|
if (need_per_loop_normals) {
|
||||||
for (const int corner : face) {
|
for (const int corner : face) {
|
||||||
float3 loop_normal;
|
|
||||||
BLI_assert(corner < export_mesh_->corners_num);
|
BLI_assert(corner < export_mesh_->corners_num);
|
||||||
copy_v3_v3(loop_normal, corner_normals[corner]);
|
const float3 normal = math::normalize(world_and_axes_normal_transform_ *
|
||||||
mul_m3_v3(world_and_axes_normal_transform_, loop_normal);
|
corner_normals[corner]);
|
||||||
normalize_v3(loop_normal);
|
const float3 rounded = round_float3_to_n_digits(normal, round_digits);
|
||||||
float3 rounded_loop_normal = round_float3_to_n_digits(loop_normal, round_digits);
|
int loop_norm_index = normal_to_index.lookup_default(rounded, -1);
|
||||||
int loop_norm_index = normal_to_index.lookup_default(rounded_loop_normal, -1);
|
|
||||||
if (loop_norm_index == -1) {
|
if (loop_norm_index == -1) {
|
||||||
loop_norm_index = cur_normal_index++;
|
loop_norm_index = cur_normal_index++;
|
||||||
normal_to_index.add(rounded_loop_normal, loop_norm_index);
|
normal_to_index.add(rounded, loop_norm_index);
|
||||||
normal_coords_.append(rounded_loop_normal);
|
normal_coords_.append(rounded);
|
||||||
}
|
}
|
||||||
loop_to_normal_index_[corner] = loop_norm_index;
|
loop_to_normal_index_[corner] = loop_norm_index;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include "BLI_math_matrix_types.hh"
|
||||||
#include "BLI_math_vector_types.hh"
|
#include "BLI_math_vector_types.hh"
|
||||||
#include "BLI_offset_indices.hh"
|
#include "BLI_offset_indices.hh"
|
||||||
#include "BLI_utility_mixins.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
|
* Final transform of an object obtained from export settings (up_axis, forward_axis) and the
|
||||||
* object's world transform matrix.
|
* object's world transform matrix.
|
||||||
*/
|
*/
|
||||||
float world_and_axes_transform_[4][4];
|
float4x4 world_and_axes_transform_;
|
||||||
float world_and_axes_normal_transform_[3][3];
|
float3x3 world_and_axes_normal_transform_;
|
||||||
bool mirrored_transform_;
|
bool mirrored_transform_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Per-loop UV index.
|
* Per-loop UV index.
|
||||||
*/
|
*/
|
||||||
Vector<int> loop_to_uv_index_;
|
Array<int> loop_to_uv_index_;
|
||||||
/*
|
/*
|
||||||
* UV vertices.
|
* UV vertices.
|
||||||
*/
|
*/
|
||||||
|
@ -60,7 +61,7 @@ class OBJMesh : NonCopyable {
|
||||||
/**
|
/**
|
||||||
* Per-loop normal index.
|
* Per-loop normal index.
|
||||||
*/
|
*/
|
||||||
Vector<int> loop_to_normal_index_;
|
Array<int> loop_to_normal_index_;
|
||||||
/*
|
/*
|
||||||
* Normal coords.
|
* Normal coords.
|
||||||
*/
|
*/
|
||||||
|
@ -81,7 +82,7 @@ class OBJMesh : NonCopyable {
|
||||||
/**
|
/**
|
||||||
* Order in which the polygons should be written into the file (sorted by material index).
|
* Order in which the polygons should be written into the file (sorted by material index).
|
||||||
*/
|
*/
|
||||||
Vector<int> poly_order_;
|
Array<int> poly_order_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Array<const Material *> materials;
|
Array<const Material *> materials;
|
||||||
|
@ -132,10 +133,11 @@ class OBJMesh : NonCopyable {
|
||||||
*/
|
*/
|
||||||
const char *get_object_mesh_name() const;
|
const char *get_object_mesh_name() const;
|
||||||
|
|
||||||
/**
|
const float4x4 &get_world_axes_transform() const
|
||||||
* Calculate coordinates of the vertex at the given index.
|
{
|
||||||
*/
|
return world_and_axes_transform_;
|
||||||
float3 calc_vertex_coords(int vert_index, float global_scale) const;
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate vertex indices of all vertices of the polygon at the given index.
|
* 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.
|
* 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
|
} // 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)};
|
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,
|
OBJWriter &obj_writer,
|
||||||
MTLWriter *mtl_writer,
|
MTLWriter *mtl_writer,
|
||||||
const OBJExportParams &export_params)
|
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,
|
* we have to have the output text buffer for each object,
|
||||||
* and write them all into the file at the end. */
|
* and write them all into the file at the end. */
|
||||||
size_t count = exportable_as_mesh.size();
|
size_t count = exportable_as_mesh.size();
|
||||||
std::vector<FormatHandler> buffers(count);
|
Array<FormatHandler> buffers(count);
|
||||||
|
|
||||||
/* Serial: gather material indices, ensure normals & edges. */
|
/* Serial: gather material indices, ensure normals & edges. */
|
||||||
Vector<Vector<int>> mtlindices;
|
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. */
|
/* 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) {
|
for (const int i : range) {
|
||||||
OBJMesh &obj = *exportable_as_mesh[i];
|
OBJMesh &obj = *exportable_as_mesh[i];
|
||||||
if (export_params.export_normals) {
|
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. */
|
/* 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) {
|
for (const int i : range) {
|
||||||
OBJMesh &obj = *exportable_as_mesh[i];
|
OBJMesh &obj = *exportable_as_mesh[i];
|
||||||
auto &fh = buffers[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.
|
* 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)
|
const OBJWriter &obj_writer)
|
||||||
{
|
{
|
||||||
FormatHandler fh;
|
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,
|
auto [exportable_as_mesh, exportable_as_nurbs] = filter_supported_objects(depsgraph,
|
||||||
export_params);
|
export_params);
|
||||||
|
|
||||||
write_mesh_objects(
|
write_mesh_objects(exportable_as_mesh, *frame_writer, mtl_writer.get(), export_params);
|
||||||
std::move(exportable_as_mesh), *frame_writer, mtl_writer.get(), export_params);
|
|
||||||
if (mtl_writer) {
|
if (mtl_writer) {
|
||||||
mtl_writer->write_header(export_params.blen_filepath);
|
mtl_writer->write_header(export_params.blen_filepath);
|
||||||
char dest_dir[PATH_MAX];
|
char dest_dir[PATH_MAX];
|
||||||
|
@ -298,7 +297,7 @@ void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, co
|
||||||
dest_dir,
|
dest_dir,
|
||||||
export_params.export_pbr_extensions);
|
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)
|
bool append_frame_to_filename(const char *filepath, const int frame, char *r_filepath_with_frames)
|
||||||
|
|
|
@ -930,18 +930,15 @@ enum wmConfirmPosition {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wmConfirmDetails {
|
struct wmConfirmDetails {
|
||||||
char title[1024];
|
std::string title;
|
||||||
char message[1024];
|
std::string message;
|
||||||
char message2[1024];
|
std::string message2;
|
||||||
char confirm_button[256];
|
std::string confirm_text;
|
||||||
char cancel_button[256];
|
|
||||||
int icon;
|
int icon;
|
||||||
wmConfirmSize size;
|
wmConfirmSize size;
|
||||||
wmConfirmPosition position;
|
wmConfirmPosition position;
|
||||||
bool confirm_default;
|
|
||||||
bool cancel_default;
|
bool cancel_default;
|
||||||
bool mouse_move_quit;
|
bool mouse_move_quit;
|
||||||
bool red_alert;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3629,8 +3629,8 @@ static void wm_clear_recent_files_confirm(bContext * /*C*/,
|
||||||
wmOperator * /*op*/,
|
wmOperator * /*op*/,
|
||||||
wmConfirmDetails *confirm)
|
wmConfirmDetails *confirm)
|
||||||
{
|
{
|
||||||
STRNCPY(confirm->message, IFACE_("Remove all items from the recent files list"));
|
confirm->message = IFACE_("Remove all items from the recent files list");
|
||||||
STRNCPY(confirm->confirm_button, IFACE_("Remove All"));
|
confirm->confirm_text = IFACE_("Remove All");
|
||||||
confirm->position = WM_WARNING_POSITION_CENTER;
|
confirm->position = WM_WARNING_POSITION_CENTER;
|
||||||
confirm->size = WM_WARNING_SIZE_LARGE;
|
confirm->size = WM_WARNING_SIZE_LARGE;
|
||||||
confirm->cancel_default = true;
|
confirm->cancel_default = true;
|
||||||
|
|
|
@ -1217,16 +1217,13 @@ static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_
|
||||||
|
|
||||||
wmConfirmDetails confirm = {{0}};
|
wmConfirmDetails confirm = {{0}};
|
||||||
|
|
||||||
STRNCPY(confirm.title, WM_operatortype_description(C, op->type, op->ptr).c_str());
|
confirm.title = WM_operatortype_description(C, op->type, op->ptr);
|
||||||
STRNCPY(confirm.confirm_button, WM_operatortype_name(op->type, op->ptr).c_str());
|
confirm.confirm_text = WM_operatortype_name(op->type, op->ptr);
|
||||||
STRNCPY(confirm.cancel_button, IFACE_("Cancel"));
|
|
||||||
confirm.icon = ALERT_ICON_WARNING;
|
confirm.icon = ALERT_ICON_WARNING;
|
||||||
confirm.size = WM_WARNING_SIZE_SMALL;
|
confirm.size = WM_WARNING_SIZE_SMALL;
|
||||||
confirm.position = WM_WARNING_POSITION_MOUSE;
|
confirm.position = WM_WARNING_POSITION_MOUSE;
|
||||||
confirm.confirm_default = true;
|
|
||||||
confirm.cancel_default = false;
|
confirm.cancel_default = false;
|
||||||
confirm.mouse_move_quit = false;
|
confirm.mouse_move_quit = false;
|
||||||
confirm.red_alert = false;
|
|
||||||
|
|
||||||
/* uiBlock.flag */
|
/* uiBlock.flag */
|
||||||
int block_flags = UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT;
|
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();
|
const uiStyle *style = UI_style_get_dpi();
|
||||||
int text_width = std::max(
|
int text_width = std::max(
|
||||||
120 * UI_SCALE_FAC,
|
120 * UI_SCALE_FAC,
|
||||||
BLF_width(style->widget.uifont_id, confirm.title, ARRAY_SIZE(confirm.title)));
|
BLF_width(style->widget.uifont_id, confirm.title.c_str(), confirm.title.length()));
|
||||||
if (confirm.message[0]) {
|
if (!confirm.message.empty()) {
|
||||||
text_width = std::max(
|
text_width = std::max(text_width,
|
||||||
text_width,
|
int(BLF_width(style->widget.uifont_id,
|
||||||
int(BLF_width(style->widget.uifont_id, confirm.message, ARRAY_SIZE(confirm.message))));
|
confirm.message.c_str(),
|
||||||
|
confirm.message.length())));
|
||||||
}
|
}
|
||||||
if (confirm.message2[0]) {
|
if (!confirm.message2.empty()) {
|
||||||
text_width = std::max(
|
text_width = std::max(text_width,
|
||||||
text_width,
|
int(BLF_width(style->widget.uifont_id,
|
||||||
int(BLF_width(style->widget.uifont_id, confirm.message2, ARRAY_SIZE(confirm.message2))));
|
confirm.message2.c_str(),
|
||||||
|
confirm.message2.length())));
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool small = confirm.size == WM_WARNING_SIZE_SMALL;
|
const bool small = confirm.size == WM_WARNING_SIZE_SMALL;
|
||||||
const int padding = (small ? 7 : 14) * UI_SCALE_FAC;
|
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 int dialog_width = icon_size + text_width + (style->columnspace * 2.5);
|
||||||
const float split_factor = (float)icon_size / (float)(dialog_width - style->columnspace);
|
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. */
|
/* The rest of the content on the right. */
|
||||||
layout = uiLayoutColumn(split_block, true);
|
layout = uiLayoutColumn(split_block, true);
|
||||||
|
|
||||||
if (confirm.title[0]) {
|
if (!confirm.title.empty()) {
|
||||||
if (!confirm.message[0]) {
|
if (confirm.message.empty()) {
|
||||||
uiItemS(layout);
|
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);
|
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,
|
UI_BTYPE_BUT,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
confirm.confirm_button,
|
confirm.confirm_text.c_str(),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -1333,7 +1334,7 @@ static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_
|
||||||
UI_BTYPE_BUT,
|
UI_BTYPE_BUT,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
confirm.cancel_button,
|
IFACE_("Cancel"),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -1351,7 +1352,7 @@ static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_
|
||||||
UI_BTYPE_BUT,
|
UI_BTYPE_BUT,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
confirm.confirm_button,
|
confirm.confirm_text.c_str(),
|
||||||
0,
|
0,
|
||||||
0,
|
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_func_set(cancel_but, wm_operator_block_cancel, op, block);
|
||||||
UI_but_drawflag_disable(confirm_but, UI_BUT_TEXT_LEFT);
|
UI_but_drawflag_disable(confirm_but, UI_BUT_TEXT_LEFT);
|
||||||
UI_but_drawflag_disable(cancel_but, UI_BUT_TEXT_LEFT);
|
UI_but_drawflag_disable(cancel_but, UI_BUT_TEXT_LEFT);
|
||||||
|
UI_but_flag_enable(confirm.cancel_default ? cancel_but : confirm_but, UI_BUT_ACTIVE_DEFAULT);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (confirm.position == WM_WARNING_POSITION_MOUSE) {
|
if (confirm.position == WM_WARNING_POSITION_MOUSE) {
|
||||||
int bounds_offset[2];
|
int bounds_offset[2];
|
||||||
|
|
|
@ -136,6 +136,7 @@ def main():
|
||||||
from modules import render_report
|
from modules import render_report
|
||||||
report = render_report.Report("Eevee Next", output_dir, oiiotool)
|
report = render_report.Report("Eevee Next", output_dir, oiiotool)
|
||||||
report.set_pixelated(True)
|
report.set_pixelated(True)
|
||||||
|
report.set_engine_name('eevee_next')
|
||||||
report.set_reference_dir("eevee_next_renders")
|
report.set_reference_dir("eevee_next_renders")
|
||||||
report.set_reference_override_dir(reference_override_dir)
|
report.set_reference_override_dir(reference_override_dir)
|
||||||
report.set_compare_engine('cycles', 'CPU')
|
report.set_compare_engine('cycles', 'CPU')
|
||||||
|
|
|
@ -76,6 +76,7 @@ def test_get_images(output_dir, filepath, reference_dir, reference_override_dir)
|
||||||
class Report:
|
class Report:
|
||||||
__slots__ = (
|
__slots__ = (
|
||||||
'title',
|
'title',
|
||||||
|
'engine_name',
|
||||||
'output_dir',
|
'output_dir',
|
||||||
'global_dir',
|
'global_dir',
|
||||||
'reference_dir',
|
'reference_dir',
|
||||||
|
@ -104,6 +105,7 @@ class Report:
|
||||||
self.compare_engine = None
|
self.compare_engine = None
|
||||||
self.fail_threshold = 0.016
|
self.fail_threshold = 0.016
|
||||||
self.fail_percent = 1
|
self.fail_percent = 1
|
||||||
|
self.engine_name = self.title.lower().replace(" ", "_")
|
||||||
self.device = device
|
self.device = device
|
||||||
self.blacklist = blacklist
|
self.blacklist = blacklist
|
||||||
|
|
||||||
|
@ -142,6 +144,9 @@ class Report:
|
||||||
def set_compare_engine(self, other_engine, other_device=None):
|
def set_compare_engine(self, other_engine, other_device=None):
|
||||||
self.compare_engine = (other_engine, other_device)
|
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):
|
def run(self, dirpath, blender, arguments_cb, batch=False):
|
||||||
# Run tests and output report.
|
# Run tests and output report.
|
||||||
dirname = os.path.basename(dirpath)
|
dirname = os.path.basename(dirpath)
|
||||||
|
@ -232,7 +237,7 @@ class Report:
|
||||||
if failed:
|
if failed:
|
||||||
message = """<div class="alert alert-danger" role="alert">"""
|
message = """<div class="alert alert-danger" role="alert">"""
|
||||||
message += """<p>Run this command to regenerate reference (ground truth) images:</p>"""
|
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 """ \
|
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 """ \
|
"""passing test cases will not be updated. Be sure to commit the new reference """ \
|
||||||
"""images to the SVN repository afterwards.</p>"""
|
"""images to the SVN repository afterwards.</p>"""
|
||||||
|
|
Loading…
Reference in New Issue