Geometry Nodes: Sample Materials #106666

Open
Iliya Katushenock wants to merge 5 commits from mod_moder/blender:sample_material into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
13 changed files with 234 additions and 112 deletions
Showing only changes of commit 48149de89c - Show all commits

View File

@ -1088,7 +1088,7 @@ if(WITH_CYCLES AND (WITH_CYCLES_DEVICE_ONEAPI OR (WITH_CYCLES_EMBREE AND EMBREE_
${SYCL_ROOT_DIR}/bin/sycl[0-9].dll
)
foreach(sycl_runtime_library IN LISTS _sycl_runtime_libraries_glob)
string(REPLACE ".dll" "_d.dll" sycl_runtime_library_debug ${sycl_runtime_library})
string(REPLACE ".dll" "d.dll" sycl_runtime_library_debug ${sycl_runtime_library})
list(APPEND _sycl_runtime_libraries RELEASE ${sycl_runtime_library})
list(APPEND _sycl_runtime_libraries DEBUG ${sycl_runtime_library_debug})
endforeach()

View File

@ -4,6 +4,19 @@
* \ingroup GHOST
*/
/* NOTE(@ideasman42): 2023-04-07, see: !106608.
* Even though Ubuntu's Unity (desktop-environment)
* is no longer in widespread use, DBUS API's defined by: `libunity.so`
* are still supported by some KDE/GNOME docks (as close as it gets to a standard it seems).
* So when `libunity.so` is available, it can still be used to update a progress bar.
*
* Over time `libunity.so` has become less common on the Linux Desktop.
* (it's no longer installed by default on most distributions, or even easily available).
* So long term Blender should be updated to talk to DBUS directly,
* perhaps as a dynamically loaded library which is used when available.
*
* This would allow X11/WAYLAND to share their task-bar implementation too. */
#include "GHOST_TaskbarX11.hh"
#include <cassert>

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import contextlib
@contextlib.contextmanager
def operator_context(layout, op_context):
"""Context manager that temporarily overrides the operator context.
>>> with operator_context(layout, 'INVOKE_REGION_CHANNELS'):
... layout.operator("anim.channels_delete")
"""
orig_context = layout.operator_context
layout.operator_context = op_context
try:
yield
finally:
layout.operator_context = orig_context

View File

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from bpy.types import Header, Menu, Panel
from bl_ui_utils.layout import operator_context
from bl_ui.space_dopesheet import (
DopesheetFilterPopoverBase,
dopesheet_filter,
@ -267,15 +268,13 @@ class GRAPH_MT_key(Menu):
layout.operator_menu_enum("graph.easing_type", "type", text="Easing Type")
layout.separator()
operator_context = layout.operator_context
layout.operator("graph.decimate", text="Decimate (Ratio)").mode = 'RATIO'
# Using the modal operation doesn't make sense for this variant
# as we do not have a modal mode for it, so just execute it.
layout.operator_context = 'EXEC_REGION_WIN'
layout.operator("graph.decimate", text="Decimate (Allowed Change)").mode = 'ERROR'
layout.operator_context = operator_context
with operator_context(layout, 'EXEC_REGION_WIN'):
layout.operator("graph.decimate", text="Decimate (Allowed Change)").mode = 'ERROR'
layout.menu("GRAPH_MT_slider", text="Slider Operators")

View File

@ -555,8 +555,8 @@ class NODE_MT_context_menu(Menu):
layout.operator("node.group_edit", text="Edit").exit = False
layout.operator("node.group_ungroup", text="Ungroup")
if is_nested:
layout.operator("node.tree_path_parent", text="Exit Group", icon='FILE_PARENT')
if is_nested:
layout.operator("node.tree_path_parent", text="Exit Group", icon='FILE_PARENT')
layout.separator()

View File

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Header, Menu, Panel
from bl_ui_utils.layout import operator_context
from bpy.app.translations import (
pgettext_iface as iface_,
@ -673,9 +674,8 @@ class TOPBAR_MT_window(Menu):
# - From the top-bar, the text replaces the file-menu (not so bad but strange).
# - From menu-search it replaces the area that the user may want to screen-shot.
# Setting the context to screen causes the status to show in the global status-bar.
layout.operator_context = 'INVOKE_SCREEN'
layout.operator("screen.screenshot_area")
layout.operator_context = operator_context_default
with operator_context(layout, 'INVOKE_SCREEN'):
layout.operator("screen.screenshot_area")
if sys.platform[:3] == "win":
layout.separator()

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bl_ui_utils.layout import operator_context
from bpy.types import (
Header,
Menu,
@ -2831,17 +2832,15 @@ class VIEW3D_MT_object_parent(Menu):
def draw(self, _context):
layout = self.layout
operator_context_default = layout.operator_context
layout.operator_enum("object.parent_set", "type")
layout.separator()
layout.operator_context = 'EXEC_REGION_WIN'
layout.operator("object.parent_no_inverse_set").keep_transform = False
props = layout.operator("object.parent_no_inverse_set", text="Make Parent without Inverse (Keep Transform)")
props.keep_transform = True
layout.operator_context = operator_context_default
with operator_context(layout, 'EXEC_REGION_WIN'):
layout.operator("object.parent_no_inverse_set").keep_transform = False
props = layout.operator("object.parent_no_inverse_set", text="Make Parent without Inverse (Keep Transform)")
props.keep_transform = True
layout.separator()

View File

@ -4217,6 +4217,16 @@ void CustomData_blend_write_prepare(CustomData &data,
}
data.totlayer = layers_to_write.size();
data.maxlayer = data.totlayer;
/* Note: data->layers may be null, this happens when adding
* a legacy MPoly struct to a mesh with no other face attributes.
* This leaves us with no unique ID for DNA to identify the old
* data with when loading the file.
*/
if (!data.layers && layers_to_write.size() > 0) {
/* We just need an address that's unique. */
data.layers = reinterpret_cast<CustomDataLayer *>(&data.layers);
}
}
int CustomData_sizeof(const eCustomDataType type)

View File

@ -1240,7 +1240,7 @@ void BKE_mesh_legacy_sharp_faces_from_flags(Mesh *mesh)
using namespace blender;
using namespace blender::bke;
MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (attributes.contains("sharp_face")) {
if (attributes.contains("sharp_face") || !CustomData_get_layer(&mesh->pdata, CD_MPOLY)) {
return;
}
const Span<MPoly> polys(static_cast<const MPoly *>(CustomData_get_layer(&mesh->pdata, CD_MPOLY)),

View File

@ -20,7 +20,7 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
BMUVOffsets BM_uv_map_get_offsets_n(const BMesh *bm, int layer)
BMUVOffsets BM_uv_map_get_offsets_n(const BMesh *bm, const int layer)
{
using namespace blender;
using namespace blender::bke;
@ -46,8 +46,7 @@ BMUVOffsets BM_uv_map_get_offsets_n(const BMesh *bm, int layer)
BMUVOffsets BM_uv_map_get_offsets(const BMesh *bm)
{
return BM_uv_map_get_offsets_n(bm,
CustomData_get_active_layer_index(&bm->ldata, CD_PROP_FLOAT2));
return BM_uv_map_get_offsets_n(bm, CustomData_get_active_layer(&bm->ldata, CD_PROP_FLOAT2));
}
static void uv_aspect(const BMLoop *l,

View File

@ -87,8 +87,15 @@ class PackIsland {
void add_polygon(const blender::Span<float2> uvs, MemArena *arena, Heap *heap);
void finalize_geometry(const UVPackIsland_Params &params, MemArena *arena, Heap *heap);
void build_transformation(const float scale, const float angle, float r_matrix[2][2]);
void build_inverse_transformation(const float scale, const float angle, float r_matrix[2][2]);
void build_transformation(const float scale, const float rotation, float r_matrix[2][2]) const;
void build_inverse_transformation(const float scale,
const float rotation,
float r_matrix[2][2]) const;
float2 get_diagonal_support(const float scale, const float rotation, const float margin) const;
float2 get_diagonal_support_d4(const float scale,
const float rotation,
const float margin) const;
/** Center of AABB and inside-or-touching the convex hull. */
float2 pivot_;

View File

@ -25,6 +25,27 @@
namespace blender::geometry {
/* Store information about an island's placement such as translation, rotation and reflection. */
class uv_phi {
public:
uv_phi();
bool is_valid() const;
float2 translation;
float rotation;
/* bool reflect; */
};
uv_phi::uv_phi() : translation(-1.0f, -1.0f), rotation(0.0f)
{
/* Initialize invalid. */
}
bool uv_phi::is_valid() const
{
return translation.x != -1.0f;
}
void mul_v2_m2_add_v2v2(float r[2], const float mat[2][2], const float a[2], const float b[2])
{
/* Compute `r = mat * (a + b)` with high precision.
@ -192,6 +213,7 @@ class UVAABBIsland {
float2 uv_placement;
int64_t index;
float angle;
float aspect_y;
};
/**
@ -320,10 +342,10 @@ class Occupancy {
const bool write) const;
/* Write or Query an island on the bitmap. */
float trace_island(PackIsland *island,
float trace_island(const PackIsland *island,
const uv_phi phi,
const float scale,
const float margin,
const float2 &uv,
const bool write) const;
int bitmap_radix; /* Width and Height of `bitmap`. */
@ -439,28 +461,60 @@ float Occupancy::trace_triangle(const float2 &uv0,
return -1.0f; /* Available. */
}
float Occupancy::trace_island(PackIsland *island,
float2 PackIsland::get_diagonal_support_d4(const float scale,
const float rotation,
const float margin) const
{
if (rotation == 0.0f) {
return half_diagonal_ * scale + margin; /* Fast path for common case. */
}
/* TODO: BLI_assert rotation is a "Dihedral Group D4" transform. */
float matrix[2][2];
build_transformation(scale, rotation, matrix);
float diagonal_rotated[2];
mul_v2_m2v2(diagonal_rotated, matrix, half_diagonal_);
return float2(fabsf(diagonal_rotated[0]) + margin, fabsf(diagonal_rotated[1]) + margin);
}
float2 PackIsland::get_diagonal_support(const float scale,
const float rotation,
const float margin) const
{
/* Only "D4" transforms are currently supported. */
return get_diagonal_support_d4(scale, rotation, margin);
}
float Occupancy::trace_island(const PackIsland *island,
const uv_phi phi,
const float scale,
const float margin,
const float2 &uv,
const bool write) const
{
float2 diagonal_support = island->get_diagonal_support(scale, phi.rotation, margin);
if (!write) {
if (uv.x < island->half_diagonal_.x * scale + margin ||
uv.y < island->half_diagonal_.y * scale + margin) {
if (phi.translation.x < diagonal_support.x || phi.translation.y < diagonal_support.y) {
return terminal; /* Occupied. */
}
}
const float2 delta = uv - island->pivot_ * scale;
float matrix[2][2];
island->build_transformation(scale, phi.rotation, matrix);
float2 pivot_transformed;
mul_v2_m2v2(pivot_transformed, matrix, island->pivot_);
float2 delta = phi.translation - pivot_transformed;
uint vert_count = uint(island->triangle_vertices_.size()); /* `uint` is faster than `int`. */
for (uint i = 0; i < vert_count; i += 3) {
uint j = (i + triangle_hint_) % vert_count;
float extent = trace_triangle(delta + island->triangle_vertices_[j] * scale,
delta + island->triangle_vertices_[j + 1] * scale,
delta + island->triangle_vertices_[j + 2] * scale,
margin,
write);
float2 uv0;
float2 uv1;
float2 uv2;
mul_v2_m2v2(uv0, matrix, island->triangle_vertices_[j]);
mul_v2_m2v2(uv1, matrix, island->triangle_vertices_[j + 1]);
mul_v2_m2v2(uv2, matrix, island->triangle_vertices_[j + 2]);
float extent = trace_triangle(uv0 + delta, uv1 + delta, uv2 + delta, margin, write);
if (!write && extent >= 0.0f) {
triangle_hint_ = j;
@ -470,46 +524,51 @@ float Occupancy::trace_island(PackIsland *island,
return -1.0f; /* Available. */
}
static float2 find_best_fit_for_island(PackIsland *island,
int scan_line,
static uv_phi find_best_fit_for_island(const PackIsland *island,
const int scan_line,
Occupancy &occupancy,
const float scale,
const int angle_90_multiple,
const float margin,
const float target_aspect_y)
{
const float bitmap_scale = 1.0f / occupancy.bitmap_scale_reciprocal;
const float half_x_scaled = island->half_diagonal_.x * scale;
const float half_y_scaled = island->half_diagonal_.y * scale;
const float sqrt_target_aspect_y = sqrtf(target_aspect_y);
int scan_line_x = int(scan_line * sqrt_target_aspect_y);
int scan_line_y = int(scan_line / sqrt_target_aspect_y);
const int scan_line_x = int(scan_line * sqrt_target_aspect_y);
const int scan_line_y = int(scan_line / sqrt_target_aspect_y);
uv_phi phi;
phi.rotation = DEG2RADF(angle_90_multiple * 90);
float matrix[2][2];
island->build_transformation(scale, phi.rotation, matrix);
/* Caution, margin is zero for support_diagonal as we're tracking the top-right corner. */
float2 support_diagonal = island->get_diagonal_support_d4(scale, phi.rotation, 0.0f);
/* Scan using an "Alpaca"-style search, first horizontally using "less-than". */
int t = int(ceilf((2 * half_x_scaled + margin) * occupancy.bitmap_scale_reciprocal));
int t = int(ceilf((2 * support_diagonal.x + margin) * occupancy.bitmap_scale_reciprocal));
while (t < scan_line_x) {
const float2 probe(t * bitmap_scale - half_x_scaled,
scan_line_y * bitmap_scale - half_y_scaled);
const float extent = occupancy.trace_island(island, scale, margin, probe, false);
phi.translation = float2(t * bitmap_scale, scan_line_y * bitmap_scale) - support_diagonal;
const float extent = occupancy.trace_island(island, phi, scale, margin, false);
if (extent < 0.0f) {
return probe; /* Success. */
return phi; /* Success. */
}
t = t + std::max(1, int(extent));
}
/* Then scan vertically using "less-than-or-equal" */
t = int(ceilf((2 * half_y_scaled + margin) * occupancy.bitmap_scale_reciprocal));
t = int(ceilf((2 * support_diagonal.y + margin) * occupancy.bitmap_scale_reciprocal));
while (t <= scan_line_y) {
const float2 probe(scan_line_x * bitmap_scale - half_x_scaled,
t * bitmap_scale - half_y_scaled);
const float extent = occupancy.trace_island(island, scale, margin, probe, false);
phi.translation = float2(scan_line_x * bitmap_scale, t * bitmap_scale) - support_diagonal;
const float extent = occupancy.trace_island(island, phi, scale, margin, false);
if (extent < 0.0f) {
return probe; /* Success. */
return phi; /* Success. */
}
t = t + std::max(1, int(extent));
}
return float2(-1, -1); /* Unable to find a place to fit. */
return uv_phi(); /* Unable to find a place to fit. */
}
static float guess_initial_scale(const Span<PackIsland *> islands,
@ -544,7 +603,7 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
const Span<PackIsland *> islands,
const float scale,
const float margin,
const float target_aspect_y,
const UVPackIsland_Params &params,
float *r_max_u,
float *r_max_v)
{
@ -552,6 +611,7 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
float max_u = 0.0f;
float max_v = 0.0f;
blender::Array<uv_phi> phis(island_indices.size());
int scan_line = 0;
int i = 0;
@ -563,12 +623,22 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
while (i < island_indices.size()) {
PackIsland *island = islands[island_indices[i]->index];
const float2 best = find_best_fit_for_island(
island, scan_line, occupancy, scale, margin, target_aspect_y);
uv_phi phi;
if (best.x <= -1.0f) {
int max_90_multiple = params.rotate && (i < 50) ? 4 : 1;
for (int angle_90_multiple = 0; angle_90_multiple < max_90_multiple; angle_90_multiple++) {
phi = find_best_fit_for_island(
island, scan_line, occupancy, scale, angle_90_multiple, margin, params.target_aspect_y);
if (phi.is_valid()) {
break;
}
}
if (!phi.is_valid()) {
/* Unable to find a fit on this scan_line. */
island = nullptr; /* Just mark it as null, we won't use it further. */
if (i < 10) {
scan_line++;
}
@ -580,8 +650,8 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
* choice is 2. */
scan_line += 2;
}
if (scan_line <
occupancy.bitmap_radix * sqrtf(std::min(target_aspect_y, 1.0f / target_aspect_y))) {
if (scan_line < occupancy.bitmap_radix *
sqrtf(std::min(params.target_aspect_y, 1.0f / params.target_aspect_y))) {
continue; /* Try again on next scan_line. */
}
@ -591,21 +661,27 @@ static void pack_island_xatlas(const Span<UVAABBIsland *> island_indices,
/* Redraw already placed islands. (Greedy.) */
for (int j = 0; j < i; j++) {
PackIsland *other = islands[island_indices[j]->index];
float2 where = (other->pre_translate + other->pivot_) * scale;
occupancy.trace_island(islands[island_indices[j]->index], scale, margin, where, true);
occupancy.trace_island(islands[island_indices[j]->index], phis[j], scale, margin, true);
}
continue;
}
/* Place island. */
island->angle = 0.0f;
island->pre_translate = best / scale - island->pivot_;
occupancy.trace_island(island, scale, margin, best, true);
phis[i] = phi; /* Place island. */
occupancy.trace_island(island, phi, scale, margin, true);
i++; /* Next island. */
max_u = std::max(best.x + island->half_diagonal_.x * scale + margin, max_u);
max_v = std::max(best.y + island->half_diagonal_.y * scale + margin, max_v);
island->angle = phi.rotation;
float matrix_inverse[2][2];
island->build_inverse_transformation(scale, phi.rotation, matrix_inverse);
mul_v2_m2v2(island->pre_translate, matrix_inverse, phi.translation);
island->pre_translate -= island->pivot_;
float2 support = island->get_diagonal_support(scale, phi.rotation, margin);
float2 top_right = phi.translation + support;
max_u = std::max(top_right.x, max_u);
max_v = std::max(top_right.y, max_v);
if (i < 128 || (i & 31) == 16) {
scan_line = 0; /* Restart completely. */
@ -692,8 +768,9 @@ static void pack_islands_alpaca_rotate(const Span<UVAABBIsland *> islands,
/* Visit every island in order. */
for (UVAABBIsland *island : islands) {
float min_dsm = std::min(island->uv_diagonal.x, island->uv_diagonal.y);
float max_dsm = std::max(island->uv_diagonal.x, island->uv_diagonal.y);
const float uvdiag_x = island->uv_diagonal.x * island->aspect_y;
float min_dsm = std::min(uvdiag_x, island->uv_diagonal.y);
float max_dsm = std::max(uvdiag_x, island->uv_diagonal.y);
if (min_dsm < hole_diagonal.x && max_dsm < hole_diagonal.y) {
/* Place island in the hole. */
@ -701,20 +778,20 @@ static void pack_islands_alpaca_rotate(const Span<UVAABBIsland *> islands,
island->uv_placement.y = hole[1];
if (hole_rotate == (min_dsm == island->uv_diagonal.x)) {
island->angle = DEG2RADF(90.0f);
island->uv_placement.x += max_dsm * 0.5f;
island->uv_placement.y += min_dsm * 0.5f;
island->uv_placement.x += island->uv_diagonal.y * 0.5f / island->aspect_y;
island->uv_placement.y += island->uv_diagonal.x * 0.5f * island->aspect_y;
}
else {
island->angle = 0.0f;
island->uv_placement.x += min_dsm * 0.5f;
island->uv_placement.y += max_dsm * 0.5f;
island->uv_placement.x += island->uv_diagonal.x * 0.5f;
island->uv_placement.y += island->uv_diagonal.y * 0.5f;
}
/* Update space left in the hole. */
float p[6];
p[0] = hole[0];
p[1] = hole[1];
p[2] = hole[0] + (hole_rotate ? max_dsm : min_dsm);
p[2] = hole[0] + (hole_rotate ? max_dsm : min_dsm) / island->aspect_y;
p[3] = hole[1] + (hole_rotate ? min_dsm : max_dsm);
p[4] = hole[0] + (hole_rotate ? hole_diagonal.y : hole_diagonal.x);
p[5] = hole[1] + (hole_rotate ? hole_diagonal.x : hole_diagonal.y);
@ -731,7 +808,7 @@ static void pack_islands_alpaca_rotate(const Span<UVAABBIsland *> islands,
restart = (next_v1 < v0 + min_dsm);
}
else {
restart = (next_u1 < u0 + min_dsm);
restart = (next_u1 < u0 + min_dsm / island->aspect_y);
}
if (restart) {
update_hole_rotate(hole, hole_diagonal, hole_rotate, u0, v0, next_u1, next_v1);
@ -744,27 +821,27 @@ static void pack_islands_alpaca_rotate(const Span<UVAABBIsland *> islands,
/* Place the island. */
island->uv_placement.x = u0;
island->uv_placement.y = v0;
if (zigzag == (min_dsm == island->uv_diagonal.x)) {
if (zigzag == (min_dsm == uvdiag_x)) {
island->angle = DEG2RADF(90.0f);
island->uv_placement.x += max_dsm * 0.5f;
island->uv_placement.y += min_dsm * 0.5f;
island->uv_placement.x += island->uv_diagonal.y * 0.5f / island->aspect_y;
island->uv_placement.y += island->uv_diagonal.x * 0.5f * island->aspect_y;
}
else {
island->angle = 0.0f;
island->uv_placement.x += min_dsm * 0.5f;
island->uv_placement.y += max_dsm * 0.5f;
island->uv_placement.x += island->uv_diagonal.x * 0.5f;
island->uv_placement.y += island->uv_diagonal.y * 0.5f;
}
/* Move according to the "Alpaca rules", with rotation. */
if (zigzag) {
/* Move upwards. */
v0 += min_dsm;
next_u1 = max_ff(next_u1, u0 + max_dsm);
next_u1 = max_ff(next_u1, u0 + max_dsm / island->aspect_y);
next_v1 = max_ff(next_v1, v0);
}
else {
/* Move sideways. */
u0 += min_dsm;
u0 += min_dsm / island->aspect_y;
next_v1 = max_ff(next_v1, v0 + max_dsm);
next_u1 = max_ff(next_u1, u0);
}
@ -804,9 +881,6 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
* - Combine results.
*/
/* Workaround bug in #pack_islands_alpaca_rotate with non-square islands. */
bool contains_non_square_islands = false;
/* First, copy information from our input into the AABB structure. */
Array<UVAABBIsland *> aabbs(islands.size());
for (const int64_t i : islands.index_range()) {
@ -815,10 +889,8 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
aabb->index = i;
aabb->uv_diagonal.x = pack_island->half_diagonal_.x * 2 * scale + 2 * margin;
aabb->uv_diagonal.y = pack_island->half_diagonal_.y * 2 * scale + 2 * margin;
aabb->aspect_y = pack_island->aspect_y;
aabbs[i] = aabb;
if (pack_island->aspect_y != 1.0f) {
contains_non_square_islands = true;
}
}
/* Sort from "biggest" to "smallest". */
@ -826,9 +898,9 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
if (params.rotate) {
std::stable_sort(aabbs.begin(), aabbs.end(), [](const UVAABBIsland *a, const UVAABBIsland *b) {
/* Choose the AABB with the longest large edge. */
float a_u = a->uv_diagonal.x;
float a_u = a->uv_diagonal.x * a->aspect_y;
float a_v = a->uv_diagonal.y;
float b_u = b->uv_diagonal.x;
float b_u = b->uv_diagonal.x * b->aspect_y;
float b_v = b->uv_diagonal.y;
if (a_u > a_v) {
std::swap(a_u, a_v);
@ -874,7 +946,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
islands,
scale,
margin,
params.target_aspect_y,
params,
&max_u,
&max_v);
break;
@ -892,7 +964,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
/* At this stage, `max_u` and `max_v` contain the box_pack/xatlas UVs. */
/* Call Alpaca. */
if (params.rotate && !contains_non_square_islands) {
if (params.rotate) {
pack_islands_alpaca_rotate(
aabbs.as_mutable_span().drop_front(max_box_pack), params.target_aspect_y, &max_u, &max_v);
}
@ -1089,7 +1161,9 @@ void pack_islands(const Span<PackIsland *> &islands,
/** \} */
void PackIsland::build_transformation(const float scale, const float angle, float (*r_matrix)[2])
void PackIsland::build_transformation(const float scale,
const float angle,
float (*r_matrix)[2]) const
{
const float cos_angle = cosf(angle);
const float sin_angle = sinf(angle);
@ -1101,7 +1175,7 @@ void PackIsland::build_transformation(const float scale, const float angle, floa
void PackIsland::build_inverse_transformation(const float scale,
const float angle,
float (*r_matrix)[2])
float (*r_matrix)[2]) const
{
/* TODO: Generate inverse transform directly. */
build_transformation(scale, angle, r_matrix);

View File

@ -99,8 +99,14 @@ void MTLFrameBuffer::bind(bool enabled_srgb)
return;
}
/* Ensure local MTLAttachment data is up to date. */
this->update_attachments(true);
/* Ensure local MTLAttachment data is up to date.
* NOTE: We only refresh viewport/scissor region when attachments are updated during bind.
* This is to ensure state is consistent with the OpenGL backend. */
if (dirty_attachments_) {
this->update_attachments(true);
this->viewport_reset();
this->scissor_reset();
}
/* Ensure SRGB state is up-to-date and valid. */
bool srgb_state_changed = enabled_srgb_ != enabled_srgb;
@ -465,6 +471,11 @@ void MTLFrameBuffer::read(eGPUFrameBufferBits planes,
BLI_assert(area[2] > 0);
BLI_assert(area[3] > 0);
/* Early exit if requested read region area is zero. */
if (area[2] <= 0 || area[3] <= 0) {
return;
}
switch (planes) {
case GPU_DEPTH_BIT: {
if (this->has_depth_attachment()) {
@ -742,10 +753,6 @@ void MTLFrameBuffer::update_attachments(bool update_viewport)
height_ = 0;
}
/* Reset viewport and Scissor. */
this->viewport_reset();
this->scissor_reset();
/* We have now updated our internal structures. */
dirty_attachments_ = false;
}
@ -760,15 +767,18 @@ void MTLFrameBuffer::apply_state()
}
/* Ensure viewport has been set. NOTE: This should no longer happen, but kept for safety to
* track bugs. */
if (viewport_[2] == 0 || viewport_[3] == 0) {
* track bugs. If viewport size is zero, use framebuffer size. */
int viewport_w = viewport_[2];
int viewport_h = viewport_[3];
if (viewport_w == 0 || viewport_h == 0) {
MTL_LOG_WARNING(
"Viewport had width and height of (0,0) -- Updating -- DEBUG Safety check\n");
viewport_reset();
viewport_w = width_;
viewport_h = height_;
}
/* Update Context State. */
mtl_ctx->set_viewport(viewport_[0], viewport_[1], viewport_[2], viewport_[3]);
mtl_ctx->set_viewport(viewport_[0], viewport_[1], viewport_w, viewport_h);
mtl_ctx->set_scissor(scissor_[0], scissor_[1], scissor_[2], scissor_[3]);
mtl_ctx->set_scissor_enabled(scissor_test_);
@ -895,8 +905,6 @@ bool MTLFrameBuffer::add_color_attachment(gpu::MTLTexture *texture,
if (width_ == 0 || height_ == 0) {
this->size_set(width_of_miplayer, height_of_miplayer);
this->scissor_reset();
this->viewport_reset();
BLI_assert(width_ > 0);
BLI_assert(height_ > 0);
}
@ -1017,8 +1025,6 @@ bool MTLFrameBuffer::add_depth_attachment(gpu::MTLTexture *texture, int miplevel
/* Update Frame-buffer Resolution. */
if (width_ == 0 || height_ == 0) {
this->size_set(width_of_miplayer, height_of_miplayer);
this->scissor_reset();
this->viewport_reset();
BLI_assert(width_ > 0);
BLI_assert(height_ > 0);
}
@ -1139,8 +1145,6 @@ bool MTLFrameBuffer::add_stencil_attachment(gpu::MTLTexture *texture, int miplev
/* Update Frame-buffer Resolution. */
if (width_ == 0 || height_ == 0) {
this->size_set(width_of_miplayer, height_of_miplayer);
this->scissor_reset();
this->viewport_reset();
BLI_assert(width_ > 0);
BLI_assert(height_ > 0);
}
@ -1225,10 +1229,8 @@ void MTLFrameBuffer::ensure_render_target_size()
if (colour_attachment_count_ == 0 && !this->has_depth_attachment() &&
!this->has_stencil_attachment()) {
/* Reset Viewport and Scissor for NULL framebuffer. */
/* Reset size for empty framebuffer. */
this->size_set(0, 0);
this->scissor_reset();
this->viewport_reset();
}
}