1
1

Compare commits

...

80 Commits

Author SHA1 Message Date
560e015a5b Fix and cleanup: Pack to correct/Specified UDIM
After recent changes made in master branch, it is now possible to display
UDIM grid and tiled images simultaneously in the UV Editor.
This commit updates the pack islands to correct/specified UDIM
implementation to work with the new behavior. Also includes some code
and comment cleanups.
2021-09-26 00:40:51 +05:30
f87ed1547c UV grid: Resolve merge conflicts
Resolves merge conflicts that broke the subdividing and dynamic grid
implementations
2021-09-22 23:08:30 +05:30
1b9dd08d02 Merge branch 'master' into soc-2021-uv-editor-improvements 2021-09-22 21:07:15 +05:30
0c2bc843f5 Merge branch 'master' into soc-2021-uv-editor-improvements 2021-08-16 10:34:46 +05:30
98deceb5c1 Cleanup and fix: Dynamic grid and offset operator
* Minor fix for dynamic grid
* Cleanup UV offset operator
2021-08-16 10:04:49 +05:30
da8963af2d Cleanup and fixes: UV grid types
* Code and comment cleanup
* Refactor subdividing grid code to allow creating grid of different
  dimensions different from the previous 4x4 grid
* Change subdividing grid dimensions to start from 8x8
* Refactor code used to calculate increment snapping value for the UV
  editor
2021-08-16 06:44:00 +05:30
72ee339710 Merge branch 'master' into soc-2021-uv-editor-improvements 2021-08-09 06:31:32 +05:30
1c74abfa4b Cleanup: license headers
These were removed globally in 65ec7ec524.

Some files re-introduced these conventions since.
2021-08-06 11:39:49 +05:30
f6e594f1ee Cleanup: tab indentation for CMake / GNUmakefile 2021-08-06 11:39:49 +05:30
8c3128baae Windows: Add icons and icons_geom to make.bat
This adds support for building the icons from make.bat
unlike bash there is no passing environment variables
on the command line.

The scripts go out of their way to locate both blender
and inkscape however if they are not found, the user is
given a helpful error message telling them how to set
the variables.

Although some extra help can be given there, if your
normal build is a 2019 full build running

`make 2019 full icons`

will help it find the blender executable as well.

finally if you know the name of your build folder
running

`make builddir build_windows_Lite_x64_vc16_Release icons`

will also work, if all fails you can point directly to
the blender executable by running

`set BLENDER_BIN=c:\where\blender\lives\blender.exe`

before running `make icons` or `make icons_geom`

The python scripts needed some small modifications since
without the PATHEXT, SystemRoot and SystemDrive
environment variables python will not initialize properly
on windows. (Not blender related, even mainline python
won't start without those)
2021-08-06 11:39:48 +05:30
798214c1f6 PyDoc: Update GPU Example of draw_view3d
This function was changed in rBc8004ab4078c98c54a70113c12bbb186403e90cf but didnt update the example.

Part of T84227
2021-08-06 11:39:48 +05:30
e981df9fbd PyDoc: Improve description of texture.evaluate
Inspired by the old 2.49 docs: https://docs.blender.org/api/249PythonDoc/Texture.Texture-class.html#evaluate
2021-08-06 11:39:48 +05:30
112a532f41 Cleanup: make format 2021-08-06 11:39:48 +05:30
aa0b05ef70 Win32 IME: Rename SetInputLanguage()
GHOST_ImeWin32::SetInputLanguage() has a confusing name because it does
not set the input language. It actually retrieves the current input
locale from the OS and caches the value of the current input language
ID. Therefore this patch renames it to "UpdateInputLanguage"

Differential Revision: https://developer.blender.org/D12134

Reviewed by Ray Molenkamp
2021-08-06 11:39:47 +05:30
c3e996a118 Win32 IME: Remove ime_status_
This removes one member of GHOST_ImeWin32 that is not used and cannot
be used in the future. It is holding the result of ImmIsIME, which is
whether an input language supports IME. It does not indicate that one
is in use, turned on, composing, in English mode, etc.

see D12131 for more information.

Differential Revision: https://developer.blender.org/D12131

Reviewed by Ray Molenkamp
2021-08-06 11:39:47 +05:30
c7a2086253 Cycles: make object Fast GI Approximation panel a subpanel of Shading 2021-08-06 11:39:47 +05:30
0ac3da0e45 Cleanup: rename restrict to hide/visibility in Object, Collection, MaskLayer
This makes the internal naming consistent with the public API. And also gives
us a visibility_flag rather than restrictflag that can be extended with more
flags.
2021-08-06 11:39:46 +05:30
Romain Toumi
a39edbfb19 Fix Cycles material slots list being too short
Bring it in line with Eevee.

Differential Revision: https://developer.blender.org/D11982
2021-08-06 11:39:45 +05:30
e6a68e9511 VSE: Allow Wingdings and Symbol Fonts
This patch makes us less restrictive on the allowed types of FreeType
font character maps we allow, rather than primarily unicode-only. This
allows us to use some legacy, symbol, specialty, and proprietary fonts
like Wingdings. Note we were a little less restrictive with vfonts,
used for 3D Text Objects, so this patch primarily helps VSE.

See D12124 for details and examples.

Differential Revision: https://developer.blender.org/D12124

Reviewed by Brecht Van Lommel
2021-08-06 11:39:45 +05:30
1ea018eb4d UI: VFont Display Names
When displaying the names of fonts for 3D Text objects, use the same
format as shown in File Browser: Family name + Style name. They are
currently shown with Postscript Name, which doesn't match well.

see D12069 for more details.

Differential Revision: https://developer.blender.org/D12069

Reviewed by Campbell Barton
2021-08-06 11:39:45 +05:30
08697cff10 Cycles: More flexible GI Approximation AO distance control
The goal: allow to easily use AO approximation in scenes which combines
both small and large scale objects.

The idea: use per-object AO distance which will allow to override world
settings. Instancer object will "propagate" its AO distance to all its
instances unless the instance defines own distance (this allows to
modify AO distance in the shot files, without requiring to modify props
used in the shots.

Available from the new Fats GI Approximation panel in object properties.

Differential Revision: https://developer.blender.org/D12112
2021-08-06 11:39:44 +05:30
395056561b LibOverride RNA API: add removal of properties and operations.
This should complete the basics of RNA API for library overrides.

Ref. T86656.
2021-08-06 11:39:44 +05:30
6669c559e3 LibOverride: Add RNA API to reset/delete overrides.
Ref. T86656.
2021-08-06 11:39:44 +05:30
cacfdcd041 Added some TODO remarks. 2021-08-06 11:39:43 +05:30
4362228562 GPencil: New Brush option to define Caps type
This is used to set the default caps type for the stroke. Before always was rounded and only could be changed later in Edit mode

Two new buttons has been added to topbar.

NOTE: New icons are been designed (T90414)

The buttons are expanded to list in Properties panel.

Reviewed By: mendio, HooglyBoogly

Differential Revision: https://developer.blender.org/D11999
2021-08-06 11:39:43 +05:30
4ea6595af0 Fix T90427: Center View to Mouse broken
rBfb87d236edb7 made the values returned by `projmat_dimensions` more
standardized following the documentations. But the functions in Blender
that called `projmat_dimensions` followed a proposal that these values
corresponded to a distance of 1m of clip.

Adjust these functions to follow the new algorithm.
2021-08-06 11:39:42 +05:30
8506edc0b8 BLI: add double version of 'scaleform'
No functional changes. New utility.
2021-08-06 11:39:42 +05:30
5c4bd878a2 Fix T90421: edit-mode auto-smooth crash when angle set to 180degrees
Error in 39b2a7bb7e
which failed to set edge flags with single threaded calculation,
used for low poly models.
2021-08-06 11:39:41 +05:30
Gavin Li
ccf4103c1a Fix transparent faces on certain AMD cards
This patch fixes an issue with missing faces when assigning a material slot other than the first to faces on AMD TAHITI cards. Refer to T78390 and T74024 for a description of this issue.

This patch also incorporates fix from T78390 for KAVERI.

{F9029258}

Reviewed By: fclem

Differential Revision: https://developer.blender.org/D9305
2021-08-06 11:39:41 +05:30
76e4ffdb90 Cleanup: remove *.rej from cb67bfdba2 2021-08-06 11:39:41 +05:30
97f82a2224 Tweak to recent liboverride API addition: naming.
Rename new API function introduced in recent rB3b0fab6dfaa0 to match our
convention to put the action (verb) at the end of names:
`operations_update`.

Sorry for not catching that during review.
2021-08-06 11:39:40 +05:30
2581039d55 Cleanup: inconsistent parameter name 2021-08-06 11:39:40 +05:30
1e6fef3aa1 Cleanup: initialize variable to quiet warning 2021-08-06 11:39:39 +05:30
446f488685 Outliner/LibOverrides: Fix logic of checks for drag'n'drop of Collections.
Previous check was too blunt, preventing e.g. re-organization of
collection overrides inside a local parent collection, which is
perfectly valid operation.

Reported by @hjalti from the studio, thanks!
2021-08-06 11:39:39 +05:30
91a2f5583e Fix compile error without WITH_OCEANSIM enabled
Was changed in 218df99410.
2021-08-06 11:39:39 +05:30
Pratik Borhade
aa33073004 Fix T87635: Rename shader node "Specular" to "Specular BSDF"
Node name edited in Specular node definition

Reviewed By: fclem

Maniphest Tasks: T87635

Differential Revision: https://developer.blender.org/D11022
2021-08-06 11:39:38 +05:30
Gottfried Hofmann
bb5373ad7b Expose Color Management as argument for gpu.types.GPUOffScreen.draw_view3d()
Fix for https://developer.blender.org/T84227

The problem was that https://developer.blender.org/rBe0ffb911a22bb03755687f45fc1a996870e059a8 turned color management for offscreen rendering off by default, which makes it non-color-managed in some cases. So the idea here is that script authors get the choice wether they want color managed non-color-managed output. Thus this patch introduces a new argument do_color_management as a bool to gpu.types.GPUOffScreen.draw_view3d().

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D11645
2021-08-06 11:39:38 +05:30
Anthony Edlin
791cb92b96 Make loopcut drawing consistent between gizmo and operator.
Loopcut drawing from gizmo had thicker lines because
it was using line smoothing without alpha blend, compared
to thin jagged lines from operator.

Make the drawing anti aliased and consistent by using
3D_POLYLINE/3D_POINT shaders, and making sure alpha
blending is on.

Reviewed By: #eevee_viewport, fclem

Differential Revision: https://developer.blender.org/D11333
2021-08-06 11:39:38 +05:30
3f0d85de05 Viewport normal drawing with constant length
Patch for: T37878

{F10169694}

Reviewed By: fclem

Differential Revision: https://developer.blender.org/D11487
2021-08-06 11:39:37 +05:30
506a2f43b6 Modifier: warn if the ocean simulation fails to allocate memory
While most modifies don't handle out of memory cases, ocean simulation
could attempt huge allocations: 2048 gb at the maximum resolution.

Resolves T83952.
2021-08-06 11:39:35 +05:30
1f13ff614d Override: API update_operations.
The update_operations function will update the override structure of the
local object. When working with overrides the override structure is only
updated when the work-file is stored. When using scripts you might want
to enforce the update of override properties and operations.

This function removes a hack on the test cases.

Reviewed By: mont29

Maniphest Tasks: T86656

Differential Revision: https://developer.blender.org/D10848
2021-08-06 11:39:35 +05:30
c6e1b2f015 T90371: Asset: Drop Material Tooltip.
This patch changes the drop named material tooltip to give feedback to
the user what is going to happen when they invoke the change.

There are 3 states:
* "": Operator will be canceled as not all data is present (dropping on
  background.)
* "Drop <named material> on <object name> (slot <slot number>, replacing
  <current material in slot>).
* "Drop <named material> on <object name> (slot <slot number).

Reviewed By: Severin

Maniphest Tasks: T90371

Differential Revision: https://developer.blender.org/D12106
2021-08-06 11:39:34 +05:30
790c6740dc Cleanup: use C comments for descriptive text 2021-08-06 11:39:34 +05:30
16cd543e4f Cleanup: add comment to fix for T90417 2021-08-06 11:39:33 +05:30
Johnny Matthews
f36013a78d Geometry Nodes: Curve Set Spline Type
This node sets the selected (or all) splines in curve to a chosen target
spline type. Poly, Bezier, and NURB splines can be converted to any of
the other types. This is meant to be a building block node, useful in
many procedural situations.

In the future the node could be optimized with multi-threading, or by
avoiding copying in many cases, either by retrieving the curve for write
access or by passing the raw vectors to the new splines where possible.

With edits from Hans Goudey (@HooglyBoogly)

Differential Revision: https://developer.blender.org/D12013
2021-08-06 11:39:32 +05:30
11ef414ba3 Fix T90417: font loading creates duplicate ID names
Also repair any errors in existing files.

Error from e0dd3fe587.
2021-08-06 11:39:31 +05:30
39df796ec9 Cleanup: de-duplicate ID renaming utility for versioning 2021-08-06 11:39:30 +05:30
e17731fc9c Icons: add license headers to utilities 2021-08-06 11:39:29 +05:30
65c36dc583 Icons: resolve various issues for generating icons
- INKSCAPE_BIN environment variable was ignored by
  alert_icons_update & prvicons_update.
- `make icons` wasn't regenerating alert icons.
- Updating SVG icons failed using blender built with ASAN.
2021-08-06 11:39:28 +05:30
8804c698eb Icons: update alert icon script
Missed from c549d736cf.
2021-08-06 11:39:28 +05:30
d6ddacabc1 Cleanup: Allow early exit if operator cancelled
Cancel the pack islands operator early, in case there are no UV
selections to pack
2021-08-04 22:48:41 +05:30
9974edc857 Merge branch 'master' into soc-2021-uv-editor-improvements 2021-08-04 06:13:00 +05:30
7d5ed35602 Merge branch 'master' into soc-2021-uv-editor-improvements 2021-07-17 21:40:01 +05:30
cd75125c48 UV: Keymaps for offsetting selected UVs
Adds keymaps to offset selected UVs by a fixed distance in a specified direction.
Refer T78405
2021-07-17 21:26:51 +05:30
e1abd5947f UV: Absolute grid snap for UV editor
Adds a UI toggle for absolute grid snap when using Increment snapping in
UV editor. This implementation mimics the behavior observed with the
same toggle in the 3D viewport.
2021-07-10 17:32:07 +05:30
8d642bbba6 Merge branch 'master' into soc-2021-uv-editor-improvements 2021-07-08 23:59:20 +05:30
5777ec9af9 Merge branch 'master' into soc-2021-uv-editor-improvements 2021-07-08 15:48:19 +05:30
86023928ba UV: Increment snapping based on new UV grid types
Since the default UV editor grid has been replaced with a new
subdividing grid and dynamic grid (T78389) has also been implemented,
increment snapping value needs to change according to the grid
configuration in use.

This commit ensures that the increment snapping value is changed
according to the grid dimensions currently in use.
Example - For a NxN grid the increment value is set as 1/N
2021-07-04 22:51:34 +05:30
708f375f76 Cleanup: Refactor reusable code into functions
New functions for :
* Calculating current zoom factor used for determining the grid
  resolution in UV/Image editor
* Calculating grid steps for determining the grid spacings in UV/Image
  editor
2021-07-04 20:19:58 +05:30
28c85e60cb Cleanup: Use struct pointer
Replace struct variables to use pointers instead
2021-07-04 15:29:24 +05:30
d615f4d65e Fix: Pack islands to area operator
* Correct packing area coordinates for cases when user sets the maximum
  coordinates to be lower than the minimum coordinates
* Cancel operator when scale option is disabled and packing area is not
  big enough for selected islands. Also display warning message in UI
  when this happens
2021-07-03 14:29:56 +05:30
eb88ce5146 Merge branch 'master' into soc-2021-uv-editor-improvements 2021-07-01 18:29:10 +05:30
1f65001cae Change the max limit for Dynamic grid
The max limit for dynamic grid was set at 12. This commit changes that
to 5000
2021-07-01 12:02:33 +05:30
8a57e48a8f Minor Cleanup
* Remove printf statements
* Use enums
2021-06-30 21:20:18 +05:30
be270d8c8a Merge branch 'master' into soc-2021-uv-editor-improvements 2021-06-30 18:45:04 +05:30
39aa006260 UV: Replace default grid with subdividing grid
Replaces the default static grid with a dynamically subdividing grid.
This means that zooming in the UV editor will add more divisions to
the grid and vice versa when zooming out.
2021-06-30 11:55:18 +05:30
1965df11f4 UV: Dynamic Grid
Adds the option to replace the default grid in the UV editor with a NxN
grid.

Refer T78389
2021-06-26 14:02:50 +05:30
ad5983895a Merge branch 'master' into soc-2021-uv-editor-improvements 2021-06-25 19:11:12 +05:30
37e185980a UV: Display packing area coordinates
Adds properties for displaying packing area coordinates in the pack
islands to area operator.
Also fixes the issue of modified packing coordinates when the user zooms
in/out in the editor before redoing the operator from the properties
panel in UI.
2021-06-23 21:10:59 +05:30
7e1e4889c6 Fix: Release memory before cancelling operator 2021-06-23 20:58:07 +05:30
62d2e8130f Cleanup : UV pack operators
* Remove printf statements
* Use float constants instead of double
* Cleanup comments
* enum to make code better readable
2021-06-23 20:42:04 +05:30
2b37edebdf Merge branch 'master' into soc-2021-uv-editor-improvements 2021-06-21 19:10:47 +05:30
e5ab28d392 UV : Pack islands to box area
Adds a new operator to the UV editor - Pack islands to area
Allows the users to pack selected UV islands to a specified
area in the UV editor

Refer T78398
2021-06-19 22:10:34 +05:30
2771b931b5 Merge branch 'master' into soc-2021-uv-editor-improvements 2021-06-17 14:12:33 +05:30
f76eca3af2 Merge branch 'master' into soc-2021-uv-editor-improvements 2021-06-14 17:14:18 +05:30
279a67ecc8 Minor fix : Correct calculation of nearest UDIM
Corrects the logic for calculating the distance between selected UVs and
UDIM tiles
2021-06-11 20:50:38 +05:30
1a89001151 UV : Pack islands to correct/specified UDIM
Adds 2 features to the pack islands operator

 * Packing selected UVs to the closest UDIM
 * Packing selected UVs to user specified UDIM
2021-06-11 19:36:24 +05:30
2126fc815d Merge branch 'master' into soc-2021-uv-editor-improvements 2021-06-10 15:45:47 +05:30
790d11899a Merge branch 'master' into soc-2021-uv-editor-improvements 2021-06-08 20:58:04 +05:30
6a422b6624 Test commit. Add missing tooltips for pivot options in UV Editor. 2021-06-08 19:39:20 +05:30
23 changed files with 1163 additions and 32 deletions

View File

@@ -437,6 +437,7 @@ class IMAGE_MT_uvs(Menu):
layout.separator()
layout.operator("uv.pack_islands")
layout.operator("uv.pack_islands_to_area")
layout.operator("uv.average_islands_scale")
layout.separator()
@@ -933,6 +934,10 @@ class IMAGE_PT_snapping(Panel):
col.label(text="Target")
row = col.row(align=True)
row.prop(tool_settings, "snap_target", expand=True)
col.separator()
if 'INCREMENT' in tool_settings.snap_uv_element:
col.prop(tool_settings, "use_snap_uv_grid_absolute")
col.label(text="Affect")
row = col.row(align=True)
@@ -1467,6 +1472,35 @@ class IMAGE_PT_udim_grid(Panel):
col = layout.column()
col.prop(uvedit, "tile_grid_shape", text="Grid Shape")
class IMAGE_PT_dynamic_grid(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_category = "View"
bl_label = "Dynamic Grid"
@classmethod
def poll(cls, context):
sima = context.space_data
#Grid becomes irrelevant once an image is loaded in the UV Editor
return sima.show_uvedit and sima.image is None
#Not exposed in the Image editor and disabled by default
def draw_header(self, context):
sima = context.space_data
uvedit = sima.uv_editor
self.layout.prop(uvedit, "use_dynamic_grid", text="")
def draw(self, context):
layout = self.layout
sima = context.space_data
uvedit = sima.uv_editor
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column()
col.prop(uvedit, "dynamic_grid_size", text="Grid Size")
class IMAGE_PT_overlay(Panel):
bl_space_type = 'IMAGE_EDITOR'
@@ -1652,6 +1686,7 @@ classes = (
IMAGE_PT_uv_cursor,
IMAGE_PT_annotation,
IMAGE_PT_udim_grid,
IMAGE_PT_dynamic_grid,
IMAGE_PT_overlay,
IMAGE_PT_overlay_uv_edit,
IMAGE_PT_overlay_uv_edit_geometry,

View File

@@ -775,13 +775,15 @@ int BKE_image_find_nearest_tile(const Image *image, const float co[2])
LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) {
const int tile_index = tile->tile_number - 1001;
/* Coordinates of the current tile. */
const float tile_index_co[2] = {tile_index % 10, tile_index / 10};
float tile_index_co[2] = {tile_index % 10, tile_index / 10};
if (equals_v2v2(co_floor, tile_index_co)) {
return tile->tile_number;
}
/* Distance between co[2] and UDIM tile. */
/* Distance between co[2] and center of UDIM tile. */
tile_index_co[0] += 0.5f;
tile_index_co[1] += 0.5f;
const float dist_sq = len_squared_v2v2(tile_index_co, co);
if (dist_sq < dist_best_sq) {

View File

@@ -52,11 +52,23 @@ typedef struct FixedSizeBoxPack {
int w, h;
} FixedSizeBoxPack;
/* Similar to FixedSizeBoxPack. Uses float variables */
typedef struct RectSizeBoxPack {
struct RectSizeBoxPack *next, *prev;
float x, y;
float w, h;
} RectSizeBoxPack;
void BLI_box_pack_2d_fixedarea(struct ListBase *boxes,
int width,
int height,
struct ListBase *packed);
bool BLI_rect_pack_2d(BoxPack *boxarray,
const uint len,
const float rect_width,
const float rect_height);
#ifdef __cplusplus
}
#endif

View File

@@ -784,3 +784,100 @@ void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase
BLI_freelistN(&spaces);
}
/* Similar implementation of BLI_box_pack_2d_fixedarea() that works with BoxPack array and float
* variables */
bool BLI_rect_pack_2d(BoxPack *boxarray,
const uint len,
const float rect_width,
const float rect_height)
{
ListBase spaces = {NULL};
RectSizeBoxPack *full_rect = MEM_callocN(sizeof(RectSizeBoxPack), __func__);
full_rect->w = rect_width;
full_rect->h = rect_height;
bool is_box_packed;
BLI_addhead(&spaces, full_rect);
/* CHECK : Sorting is probably used incorrectly here */
qsort(boxarray, (size_t)len, sizeof(BoxPack), box_areasort);
/* Rotating islands in uvedits_islands.c doesn't work well with this algorithm
* TODO : Implement heuristic for rotating islands - Rotate islands if they don't fit in any
* empty space, but can fit if they are rotated. A boolean might be needed per island to check if
* islands need to be rotated when they are translated in uvedit_islands.c */
for (uint i = 0; i < len; i++) {
is_box_packed = false;
LISTBASE_FOREACH (RectSizeBoxPack *, space, &spaces) {
/* Skip this space if it's too small. */
if (boxarray[i].w > space->w || boxarray[i].h > space->h) {
continue;
}
/* Pack this box into this space. */
boxarray[i].x = space->x;
boxarray[i].y = space->y;
is_box_packed = true;
if (boxarray[i].w == space->w && boxarray[i].h == space->h) {
/* Box exactly fills space, so just remove the space. */
BLI_remlink(&spaces, space);
MEM_freeN(space);
}
else if (boxarray[i].w == space->w) {
/* Box fills the entire width, so we can just contract the box
* to the upper part that remains. */
space->y += boxarray[i].h;
space->h -= boxarray[i].h;
}
else if (boxarray[i].h == space->h) {
/* Box fills the entire height, so we can just contract the box
* to the right part that remains. */
space->x += boxarray[i].w;
space->w -= boxarray[i].w;
}
else {
/* Split the remaining L-shaped space into two spaces.
* There are two ways to do so, we pick the one that produces the biggest
* remaining space */
float area_hsplit_large = space->w * (space->h - boxarray[i].h);
float area_vsplit_large = (space->w - boxarray[i].w) * space->h;
/* Perform split. This space becomes the larger space,
* while the new smaller space is inserted _before_ it. */
RectSizeBoxPack *new_space = MEM_callocN(sizeof(RectSizeBoxPack), __func__);
if (area_hsplit_large > area_vsplit_large) {
new_space->x = space->x + boxarray[i].w;
new_space->y = space->y;
new_space->w = space->w - boxarray[i].w;
new_space->h = boxarray[i].h;
space->y += boxarray[i].h;
space->h -= boxarray[i].h;
}
else {
new_space->x = space->x;
new_space->y = space->y + boxarray[i].h;
new_space->w = boxarray[i].w;
new_space->h = space->h - boxarray[i].h;
space->x += boxarray[i].w;
space->w -= boxarray[i].w;
}
BLI_addhead(&spaces, new_space);
}
break;
}
/* Packing area not big enough to pack all boxes */
if (!is_box_packed) {
BLI_freelistN(&spaces);
return false;
}
}
/* All boxes packed successfully */
BLI_freelistN(&spaces);
return true;
}

View File

@@ -23,6 +23,7 @@
#include "DRW_render.h"
#include "DNA_camera_types.h"
#include "DNA_screen_types.h"
#include "DEG_depsgraph_query.h"
@@ -46,6 +47,7 @@ enum {
GRID_BACK = (1 << 9),
GRID_CAMERA = (1 << 10),
PLANE_IMAGE = (1 << 11),
DYNAMIC_GRID = (1 << 12),
};
void OVERLAY_grid_init(OVERLAY_Data *vedata)
@@ -61,6 +63,7 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
if (pd->space_type == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)draw_ctx->space_data;
View2D *v2d = &draw_ctx->region->v2d;
if (sima->mode == SI_MODE_UV || !ED_space_image_has_buffer(sima)) {
shd->grid_flag = GRID_BACK | PLANE_IMAGE | SHOW_GRID;
}
@@ -74,9 +77,32 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
shd->grid_size[0] = (float)sima->tile_grid_shape[0];
shd->grid_size[1] = (float)sima->tile_grid_shape[1];
}
for (int step = 0; step < 8; step++) {
shd->grid_steps[step] = powf(4, step) * (1.0f / 16.0f);
/**
* Previously the UV/Image Editor grid was static :
* - 0-1 UV space divided into 4x4 divisions marked by thick grid lines (1 grid unit = 0.25 UV
* units)
* - 0-1 UV space divided into 16x16 divisions marked by thin grid lines (1 grid unit = 0.0625
* UV units)
*
* The new UV/Image Editor grid now supports 2 grid types :
* - Subdividing grid : Similar to the 3D viewport grid (zooming in adds more divisions to the
* grid) [T89789]
* - Dynamic grid : Users create a desired NxN grid by using options exposed in UI [T78389]
*/
if (sima->flag & SI_DYNAMIC_GRID) {
shd->grid_flag |= DYNAMIC_GRID;
/* Temporary fix : dynamic_grid_size is not using the default value (=1) assignd in RNA */
sima->dynamic_grid_size = (sima->dynamic_grid_size == 0) ? 1 : sima->dynamic_grid_size;
}
/* N denotes the grid dimension when zoomed out (NxN grid).
* While zooming in, each grid division further subdivides into smaller NxN divisions
*
* If this value is changed, then also update the value in initSnapSpatial()
* TODO? : Probably best to move this value to SpaceImage/View2D struct */
int N = 8;
shd->zoom_factor = ED_space_image_zoom_level(v2d, N);
ED_space_image_grid_steps(sima, shd->grid_steps, N);
return;
}
@@ -248,6 +274,7 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)
grp = DRW_shgroup_create(sh, psl->grid_ps);
DRW_shgroup_uniform_int(grp, "gridFlag", &shd->grid_flag, 1);
DRW_shgroup_uniform_float_copy(grp, "zoomFactor", shd->zoom_factor);
DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->grid_axes, 1);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);

View File

@@ -142,6 +142,7 @@ typedef struct OVERLAY_ShadingData {
float grid_steps[8];
float inv_viewport_size[2];
float grid_line_size;
float zoom_factor; /* Only for UV/Image editor */
int grid_flag;
int zpos_flag;
int zneg_flag;

View File

@@ -15,6 +15,7 @@ uniform float lineKernel = 0.0;
uniform sampler2D depthBuffer;
uniform int gridFlag;
uniform float zoomFactor;
#define STEPS_LEN 8
uniform float gridSteps[STEPS_LEN] = float[](0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0, 10000.0);
@@ -28,6 +29,8 @@ uniform float gridSteps[STEPS_LEN] = float[](0.001, 0.01, 0.1, 1.0, 10.0, 100.0,
#define PLANE_YZ (1 << 6)
#define GRID_BACK (1 << 9) /* grid is behind objects */
#define GRID_CAMERA (1 << 10) /* In camera view */
#define PLANE_IMAGE (1 << 11) /* For UV/Image Image editor */
#define DYNAMIC_GRID (1 << 12) /* Dynamic grid is used in the UV/Image Editor */
#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */
@@ -122,9 +125,16 @@ void main()
* would be more accurate, but not really necessary. */
float grid_res = dot(dFdxPos, screenVecs[0].xyz);
/* The gride begins to appear when it comprises 4 pixels */
/* The grid begins to appear when it comprises 4 pixels */
grid_res *= 4;
/* For UV/Image editor use zoomFactor */
if((gridFlag & PLANE_IMAGE) != 0 && (gridFlag & DYNAMIC_GRID) == 0)
{/* Grid begins to appear when the length of one grid unit is at least 256/N pixels (for NxN grid)
* Value of N defined in overlay_grid.c */
grid_res = zoomFactor;
}
/* from biggest to smallest */
vec4 scale;
#if 0

View File

@@ -41,6 +41,16 @@ struct SpaceImage;
struct bContext;
struct wmOperator;
struct wmWindowManager;
struct View2D;
/* image_draw.c (Utility functions - should probably be moved to a BKE header) */
float ED_space_image_zoom_level(const struct View2D *v2d, const int grid_dimension);
void ED_space_image_grid_steps(struct SpaceImage *sima,
float grid_steps[8],
const int grid_dimension);
float ED_space_image_increment_snap_value(const int grid_dimesnions,
const float grid_steps[8],
const float zoom_factor);
/* image_edit.c, exported for transform */
struct Image *ED_space_image(struct SpaceImage *sima);

View File

@@ -247,10 +247,21 @@ struct UVPackIsland_Params {
uint correct_aspect : 1;
};
void ED_uvedit_pack_islands_multi(const struct Scene *scene,
const struct SpaceImage *sima,
Object **objects,
const uint objects_len,
const bool use_target_udim,
int target_udim,
const struct UVPackIsland_Params *params);
bool ED_uvedit_pack_islands_to_area_multi(const struct Scene *scene,
Object **objects,
const uint objects_len,
const float min_co[2],
const float max_co[2],
const bool scale_islands,
const struct UVPackIsland_Params *params);
#ifdef __cplusplus
}
#endif

View File

@@ -34,6 +34,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view2d_types.h"
#include "PIL_time.h"
@@ -576,3 +577,57 @@ void draw_image_cache(const bContext *C, ARegion *region)
ED_mask_draw_frames(mask, region, cfra, sfra, efra);
}
}
float ED_space_image_zoom_level(const View2D *v2d, const int grid_dimension)
{
/* UV-space length per pixel */
float xzoom = (v2d->cur.xmax - v2d->cur.xmin) / ((float)(v2d->mask.xmax - v2d->mask.xmin));
float yzoom = (v2d->cur.ymax - v2d->cur.ymin) / ((float)(v2d->mask.ymax - v2d->mask.ymin));
/* zoom_factor for UV/Image editor is calculated based on :
* - Default grid size on startup, which is 256x256 pixels
* - How blend factor for grid lines is set up in the fragment shader (grid_frag.glsl) */
float zoom_factor;
zoom_factor = (xzoom + yzoom) / 2.0f; /* Average for accuracy */
zoom_factor *= 256.0f / (powf(grid_dimension, 2));
return zoom_factor;
}
void ED_space_image_grid_steps(SpaceImage *sima, float grid_steps[8], const int grid_dimension)
{
if (sima->flag & SI_DYNAMIC_GRID) {
for (int step = 0; step < 8; step++) {
grid_steps[step] = powf(1, step) * (1.0f / ((float)sima->dynamic_grid_size));
}
}
else {
for (int step = 0; step < 8; step++) {
grid_steps[step] = powf(grid_dimension, step) * (1.0f / (powf(grid_dimension, 8)));
}
}
}
/* Calculate the increment snapping value for UV/image editor based on the zoom factor
* The code in here (except the offset part) is used in `grid_frag.glsl` (see `grid_res`) for
* drawing the grid overlay for the UV/Image editor */
float ED_space_image_increment_snap_value(const int grid_dimesnions,
const float grid_steps[8],
const float zoom_factor)
{
/* Small offset on each grid_steps[] so that snapping value doesn't change until grid lines are
* significantly visible.
* Offset = 3/4 * (grid_steps[i] - (grid_steps[i]/grid_dimesnsions))
*
* Refer grid_frag.glsl to find out when grid lines actually start appearing */
for (int step = 0; step < 8; step++) {
float offset = (3.0f / 4.0f) * (grid_steps[step] - (grid_steps[step] / grid_dimesnions));
if ((grid_steps[step] - offset) > zoom_factor) {
return grid_steps[step];
}
}
/* Fallback */
return grid_steps[0];
}

View File

@@ -28,6 +28,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
#include "DNA_screen_types.h"
#include "BLI_math.h"
#include "BLI_rect.h"
@@ -1609,8 +1610,21 @@ static void initSnapSpatial(TransInfo *t, float r_snap[2])
}
}
else if (t->spacetype == SPACE_IMAGE) {
r_snap[0] = 0.0625f;
r_snap[1] = 0.03125f;
SpaceImage *sima = t->area->spacedata.first;
View2D *v2d = &t->region->v2d;
/* N denotes the grid dimension when zoomed out (NxN grid).
* While zooming in, each grid division further subdivides into smaller NxN divisions
*
* If this value is changed, then also update the value in OVERLAY_grid_init()
* TODO? : Probably best to move this value to SpaceImage/View2D struct */
int N = 8;
float zoom_factor = ED_space_image_zoom_level(v2d, N);
float grid_steps[8];
ED_space_image_grid_steps(sima, grid_steps, N);
/* Snapping value based on what type of grid is used (subdividing or dynamic) */
r_snap[0] = ED_space_image_increment_snap_value(N, grid_steps, zoom_factor);
r_snap[1] = r_snap[0] / 2.0f;
}
else if (t->spacetype == SPACE_CLIP) {
r_snap[0] = 0.125f;

View File

@@ -590,6 +590,12 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.project = 0;
t->tsnap.mode = ts->snap_uv_mode;
/* NOTE : For now, absolute grid snap only works with translation */
if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_UV_GRID) &&
(t->mode == TFM_TRANSLATION)) {
t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT;
t->tsnap.mode |= SCE_SNAP_MODE_GRID;
}
}
else if (t->spacetype == SPACE_SEQ) {
t->tsnap.mode = SEQ_tool_settings_snap_mode_get(t->scene);
@@ -1502,7 +1508,8 @@ bool transform_snap_grid(TransInfo *t, float *val)
return false;
}
if (t->spacetype != SPACE_VIEW3D) {
/* Don't do grid snapping if not in 3D viewport or UV editor */
if (!((t->spacetype == SPACE_VIEW3D) || (t->spacetype == SPACE_IMAGE))) {
return false;
}

View File

@@ -137,6 +137,7 @@ void UV_OT_cylinder_project(struct wmOperatorType *ot);
void UV_OT_project_from_view(struct wmOperatorType *ot);
void UV_OT_minimize_stretch(struct wmOperatorType *ot);
void UV_OT_pack_islands(struct wmOperatorType *ot);
void UV_OT_pack_islands_to_area(struct wmOperatorType *ot);
void UV_OT_reset(struct wmOperatorType *ot);
void UV_OT_sphere_project(struct wmOperatorType *ot);
void UV_OT_unwrap(struct wmOperatorType *ot);

View File

@@ -29,6 +29,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "BLI_boxpack_2d.h"
#include "BLI_convexhull_2d.h"
@@ -38,6 +39,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_image.h"
#include "DEG_depsgraph.h"
@@ -357,8 +359,11 @@ static int bm_mesh_calc_uv_islands(const Scene *scene,
* \{ */
void ED_uvedit_pack_islands_multi(const Scene *scene,
const SpaceImage *sima,
Object **objects,
const uint objects_len,
const bool use_target_udim,
int target_udim,
const struct UVPackIsland_Params *params)
{
/* Align to the Y axis, could make this configurable. */
@@ -407,8 +412,25 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
BoxPack *boxarray = MEM_mallocN(sizeof(*boxarray) * island_list_len, __func__);
int index;
float selection_min_co[2], selection_max_co[2];
INIT_MINMAX2(selection_min_co, selection_max_co);
LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) {
/* Skip calculation if not using Specified UDIM option */
if (!use_target_udim) {
float bounds_min[2], bounds_max[2];
INIT_MINMAX2(bounds_min, bounds_max);
for (int i = 0; i < island->faces_len; i++) {
BMFace *f = island->faces[i];
BM_face_uv_minmax(f, bounds_min, bounds_max, island->cd_loop_uv_offset);
}
selection_min_co[0] = MIN2(bounds_min[0], selection_min_co[0]);
selection_min_co[1] = MIN2(bounds_min[1], selection_min_co[1]);
selection_max_co[0] = MAX2(bounds_max[0], selection_max_co[0]);
selection_max_co[1] = MAX2(bounds_max[1], selection_max_co[1]);
}
if (params->rotate) {
if (island->aspect_y != 1.0f) {
bm_face_array_uv_scale_y(
@@ -441,6 +463,265 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
}
}
/* Center of the selected UV bounding boxes */
float selection_center[2];
if (!use_target_udim) {
selection_center[0] = (selection_min_co[0] + selection_max_co[0]) / 2.0f;
selection_center[1] = (selection_min_co[1] + selection_max_co[1]) / 2.0f;
}
if (margin > 0.0f) {
/* Logic matches behavior from #param_pack,
* use area so multiply the margin by the area to give
* predictable results not dependent on UV scale. */
margin = (margin * (float)area) * 0.1f;
for (int i = 0; i < island_list_len; i++) {
struct FaceIsland *island = island_array[i];
BoxPack *box = &boxarray[i];
BLI_rctf_pad(&island->bounds_rect, margin, margin);
box->w = BLI_rctf_size_x(&island->bounds_rect);
box->h = BLI_rctf_size_y(&island->bounds_rect);
}
}
float boxarray_size[2];
BLI_box_pack_2d(boxarray, island_list_len, &boxarray_size[0], &boxarray_size[1]);
/* Don't change the aspect when scaling. */
boxarray_size[0] = boxarray_size[1] = max_ff(boxarray_size[0], boxarray_size[1]);
const float scale[2] = {1.0f / boxarray_size[0], 1.0f / boxarray_size[1]};
/* Tile offset */
float base_offset[2] = {0.0f, 0.0f};
/* CASE: Specified UDIM */
if (use_target_udim) {
const int specified_tile_index = target_udim - 1001;
/* Calculate offset based on specified_tile_index */
base_offset[0] = specified_tile_index % 10;
base_offset[1] = specified_tile_index / 10;
}
/* CASE: Closest UDIM */
else {
const Image *image;
bool is_tiled_image = false;
int udim_grid[2] = {1, 1};
/* To handle cases where sima=NULL - Smart UV project in 3D viewport */
if (sima != NULL) {
image = sima->image;
is_tiled_image = image && (image->source == IMA_SRC_TILED);
udim_grid[0] = sima->tile_grid_shape[0];
udim_grid[1] = sima->tile_grid_shape[1];
}
/* Check if selection lies on a valid UDIM grid tile */
bool is_valid_udim = false;
const float selection_co_floor[2] = {floorf(selection_center[0]), floorf(selection_center[1])};
if (selection_center[0] < udim_grid[0] && selection_center[0] > 0 &&
selection_center[1] < udim_grid[1] && selection_center[1] > 0) {
base_offset[0] = selection_co_floor[0];
base_offset[1] = selection_co_floor[1];
is_valid_udim = true;
}
/* Check if selection lies on a valid UDIM image tile */
else if (is_tiled_image) {
LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) {
const int tile_index = tile->tile_number - 1001;
const int target_x = (tile_index % 10);
const int target_y = (tile_index / 10);
if (selection_co_floor[0] == target_x && selection_co_floor[1] == target_y) {
base_offset[0] = selection_co_floor[0];
base_offset[1] = selection_co_floor[1];
is_valid_udim = true;
}
}
}
/* Probably not required since UDIM grid checks for 1001 */
else if (image && !is_tiled_image) {
if (is_zero_v2(selection_co_floor)) {
base_offset[0] = selection_co_floor[0];
base_offset[1] = selection_co_floor[1];
is_valid_udim = true;
}
}
/* If selection doesn't lie on any UDIM then compare both closest grid tile and image tile.
* Save the one that is closest */
if (!is_valid_udim) {
float nearest_image_tile_co[2] = {FLT_MAX, FLT_MAX};
if (image) {
int nearest_image_tile_index = BKE_image_find_nearest_tile(image, selection_center);
if (nearest_image_tile_index == -1) {
nearest_image_tile_index = 1001;
}
/* Calculate offset based on nearest_tile_index */
nearest_image_tile_co[0] = (nearest_image_tile_index - 1001) % 10;
nearest_image_tile_co[1] = (nearest_image_tile_index - 1001) / 10;
/* + 0.5f to get tile center coordinates */
nearest_image_tile_co[0] += 0.5f;
nearest_image_tile_co[1] += 0.5f;
}
float nearest_grid_tile_co[2] = {0.0f, 0.0f};
if (selection_center[0] > udim_grid[0]) {
nearest_grid_tile_co[0] = udim_grid[0] - 1;
}
else if (selection_center[0] < 0) {
nearest_grid_tile_co[0] = 0;
}
else {
nearest_grid_tile_co[0] = selection_co_floor[0];
}
if (selection_center[1] > udim_grid[1]) {
nearest_grid_tile_co[1] = udim_grid[1] - 1;
}
else if (selection_center[1] < 0) {
nearest_grid_tile_co[1] = 0;
}
else {
nearest_grid_tile_co[1] = selection_co_floor[1];
}
/* + 0.5f to get tile center coordinates */
nearest_grid_tile_co[0] += 0.5f;
nearest_grid_tile_co[1] += 0.5f;
float nearest_image_tile_dist = len_squared_v2v2(selection_center, nearest_image_tile_co);
float nearest_grid_tile_dist = len_squared_v2v2(selection_center, nearest_grid_tile_co);
base_offset[0] = (nearest_image_tile_dist < nearest_grid_tile_dist) ?
(nearest_image_tile_co[0] - 0.5f) :
(nearest_grid_tile_co[0] - 0.5f);
base_offset[1] = (nearest_image_tile_dist < nearest_grid_tile_dist) ?
(nearest_image_tile_co[1] - 0.5f) :
(nearest_grid_tile_co[1] - 0.5f);
}
}
for (int i = 0; i < island_list_len; i++) {
struct FaceIsland *island = island_array[boxarray[i].index];
const float pivot[2] = {
island->bounds_rect.xmin,
island->bounds_rect.ymin,
};
const float offset[2] = {
(boxarray[i].x * scale[0]) - island->bounds_rect.xmin + base_offset[0],
(boxarray[i].y * scale[1]) - island->bounds_rect.ymin + base_offset[1],
};
for (int j = 0; j < island->faces_len; j++) {
BMFace *efa = island->faces[j];
bm_face_uv_translate_and_scale_around_pivot(
efa, offset, scale, pivot, island->cd_loop_uv_offset);
}
}
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
}
for (int i = 0; i < island_list_len; i++) {
MEM_freeN(island_array[i]->faces);
MEM_freeN(island_array[i]);
}
MEM_freeN(island_array);
MEM_freeN(boxarray);
}
/** \} */
/* Almost similar to ED_uvedit_pack_islands_multi().
* TODO : Break some of the code into smaller functions since same operations are being done in
* both ED_uvedit_pack_islands_to_area_multi() and ED_uvedit_pack_islands_multi() */
bool ED_uvedit_pack_islands_to_area_multi(const Scene *scene,
Object **objects,
const uint objects_len,
const float min_co[2],
const float max_co[2],
const bool scale_islands,
const struct UVPackIsland_Params *params)
{
/* Align to the Y axis, could make this configurable. */
const int rotate_align_axis = 1;
ListBase island_list = {NULL};
int island_list_len = 0;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
if (cd_loop_uv_offset == -1) {
continue;
}
island_list_len += bm_mesh_calc_uv_islands(scene,
bm,
&island_list,
params->only_selected_faces,
params->only_selected_uvs,
params->use_seams,
1.0f,
cd_loop_uv_offset);
}
/* This check could probably be removed */
if (island_list_len == 0) {
return true;
}
float margin = scene->toolsettings->uvcalc_margin;
double area = 0.0f;
struct FaceIsland **island_array = MEM_mallocN(sizeof(*island_array) * island_list_len,
__func__);
BoxPack *boxarray = MEM_mallocN(sizeof(*boxarray) * island_list_len, __func__);
int index;
LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) {
/* For now using the same conditions for rotating islands when scaling is enabled and disabled.
* TODO : Use new heuristic for rotating islands when scaling is disabled (using the
* RectPack2D algorithm) */
if (params->rotate) {
if (island->aspect_y != 1.0f) {
bm_face_array_uv_scale_y(
island->faces, island->faces_len, 1.0f / island->aspect_y, island->cd_loop_uv_offset);
}
// AABB - Axis Aligned Bounding Box
bm_face_array_uv_rotate_fit_aabb(
island->faces, island->faces_len, rotate_align_axis, island->cd_loop_uv_offset);
if (island->aspect_y != 1.0f) {
bm_face_array_uv_scale_y(
island->faces, island->faces_len, island->aspect_y, island->cd_loop_uv_offset);
}
}
bm_face_array_calc_bounds(
island->faces, island->faces_len, island->cd_loop_uv_offset, &island->bounds_rect);
BoxPack *box = &boxarray[index];
box->index = index;
box->x = 0.0f;
box->y = 0.0f;
box->w = BLI_rctf_size_x(&island->bounds_rect);
box->h = BLI_rctf_size_y(&island->bounds_rect);
island_array[index] = island;
if (margin > 0.0f) {
area += (double)sqrtf(box->w * box->h);
}
}
if (margin > 0.0f) {
/* Logic matches behavior from #param_pack,
* use area so multiply the margin by the area to give
@@ -456,13 +737,41 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
}
}
float boxarray_size[2];
BLI_box_pack_2d(boxarray, island_list_len, &boxarray_size[0], &boxarray_size[1]);
if (scale_islands) {
/* The problem statement for pack islands to box area operator is : Pack a given set of
* rectangular boxes to a rectangular area. Scaling down the width by W (width of rectangualr
* area) and height by H (height of rectangualr area) for all the boxes and the packing area,
* the new problem statement becomes : packing a set of rectangular boxes to a square area ->
* Similar to the original pack islands operator */
for (int i = 0; i < island_list_len; i++) {
boxarray[i].w /= (max_co[0] - min_co[0]);
boxarray[i].h /= (max_co[1] - min_co[1]);
}
}
float boxarray_size[2] = {0.0f, 0.0f};
float scale[2] = {1.0f, 1.0f};
/* Don't change the aspect when scaling. */
boxarray_size[0] = boxarray_size[1] = max_ff(boxarray_size[0], boxarray_size[1]);
const float scale[2] = {1.0f / boxarray_size[0], 1.0f / boxarray_size[1]};
/* If scaling is enabled then use the original pack islands algorithm, otherwise use the
* RectPack2D algorithm for packing */
if (scale_islands) {
BLI_box_pack_2d(boxarray, island_list_len, &boxarray_size[0], &boxarray_size[1]);
boxarray_size[0] = boxarray_size[1] = max_ff(boxarray_size[0], boxarray_size[1]);
scale[0] = 1.0f / boxarray_size[0];
scale[1] = 1.0f / boxarray_size[1];
}
else {
if (!BLI_rect_pack_2d(
boxarray, island_list_len, (max_co[0] - min_co[0]), (max_co[1] - min_co[1]))) {
/* Cancel operator : Packing area not big enough for selected islands */
for (int i = 0; i < island_list_len; i++) {
MEM_freeN(island_array[i]->faces);
MEM_freeN(island_array[i]);
}
MEM_freeN(island_array);
MEM_freeN(boxarray);
return false;
}
}
for (int i = 0; i < island_list_len; i++) {
struct FaceIsland *island = island_array[boxarray[i].index];
@@ -470,10 +779,21 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
island->bounds_rect.xmin,
island->bounds_rect.ymin,
};
const float offset[2] = {
(boxarray[i].x * scale[0]) - island->bounds_rect.xmin,
(boxarray[i].y * scale[1]) - island->bounds_rect.ymin,
};
float offset[2];
if (scale_islands) {
/* Scale boxes back to original dimensions and offset them to the position of the packing
* area */
offset[0] = (boxarray[i].x * scale[0] * (max_co[0] - min_co[0])) - island->bounds_rect.xmin +
min_co[0];
offset[1] = (boxarray[i].y * scale[1] * (max_co[1] - min_co[1])) - island->bounds_rect.ymin +
min_co[1];
}
else {
offset[0] = (boxarray[i].x) - island->bounds_rect.xmin + min_co[0];
offset[1] = (boxarray[i].y) - island->bounds_rect.ymin + min_co[1];
}
for (int j = 0; j < island->faces_len; j++) {
BMFace *efa = island->faces[j];
bm_face_uv_translate_and_scale_around_pivot(
@@ -494,6 +814,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
MEM_freeN(island_array);
MEM_freeN(boxarray);
}
/** \} */
/* All islands packed successfully */
return true;
}

View File

@@ -1338,6 +1338,172 @@ static void UV_OT_snap_selected(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name UV offset Operator
* \{ */
/* Since pixel resolution is not implemented yet (refer T78405), pixel offset is not implemented in
* this operator */
enum {
UDIM_OFFSET_UP = 0,
UDIM_OFFSET_DOWN,
UDIM_OFFSET_LEFT,
UDIM_OFFSET_RIGHT,
DYNAMIC_GRID_OFFSET_UP,
DYNAMIC_GRID_OFFSET_DOWN,
DYNAMIC_GRID_OFFSET_LEFT,
DYNAMIC_GRID_OFFSET_RIGHT,
};
static void uv_calc_offset(const SpaceImage *sima, const int offset_direction, float uv_offset[2])
{
const bool is_dynamic_grid = sima->flag & SI_DYNAMIC_GRID;
zero_v2(uv_offset);
/* Assign offset based on the keymap input */
switch (offset_direction) {
case UDIM_OFFSET_UP: {
uv_offset[1] = 1.0f;
break;
}
case UDIM_OFFSET_DOWN: {
uv_offset[1] = -1.0f;
break;
}
case UDIM_OFFSET_LEFT: {
uv_offset[0] = -1.0f;
break;
}
case UDIM_OFFSET_RIGHT: {
uv_offset[0] = 1.0f;
break;
}
case DYNAMIC_GRID_OFFSET_UP: {
if (is_dynamic_grid) {
uv_offset[1] = 1.0f / ((float)sima->dynamic_grid_size);
}
break;
}
case DYNAMIC_GRID_OFFSET_DOWN: {
if (is_dynamic_grid) {
uv_offset[1] = (-1.0f) / ((float)sima->dynamic_grid_size);
}
break;
}
case DYNAMIC_GRID_OFFSET_RIGHT: {
if (is_dynamic_grid) {
uv_offset[0] = 1.0f / ((float)sima->dynamic_grid_size);
}
break;
}
case DYNAMIC_GRID_OFFSET_LEFT: {
if (is_dynamic_grid) {
uv_offset[0] = (-1.0f) / ((float)sima->dynamic_grid_size);
}
break;
}
default: {
/* Pass */
}
}
}
static int uv_offset_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
const SpaceImage *sima = CTX_wm_space_image(C);
const ToolSettings *ts = scene->toolsettings;
const int offset_direction = RNA_enum_get(op->ptr, "offset_direction");
float uv_offset[2] = {0.0f, 0.0f};
uv_calc_offset(sima, offset_direction, uv_offset);
if (is_zero_v2(uv_offset)) {
return OPERATOR_CANCELLED;
}
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
bool changed = false;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if ((ts->uv_flag & UV_SYNC_SELECTION) && (em->bm->totvertsel == 0)) {
continue;
}
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
add_v2_v2(luv->uv, uv_offset);
changed = true;
}
}
}
if (changed) {
DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
}
}
MEM_freeN(objects);
return OPERATOR_FINISHED;
}
/* Refer Task T78405 */
static void UV_OT_offset(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Offset UVs";
ot->idname = "UV_OT_offset";
ot->description = "Offset selected UVs by a fixed distance in a specified direction";
/* api callbacks */
ot->exec = uv_offset_exec;
ot->poll = ED_operator_uvedit_space_image;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* RNA properties */
static const EnumPropertyItem offset_direction[] = {
{UDIM_OFFSET_UP, "UDIM_UP", 0, "Udim Up", ""},
{UDIM_OFFSET_DOWN, "UDIM_DOWN", 0, "Udim Down", ""},
{UDIM_OFFSET_LEFT, "UDIM_LEFT", 0, "Udim Left", ""},
{UDIM_OFFSET_RIGHT, "UDIM_RIGHT", 0, "Udim Right", ""},
{DYNAMIC_GRID_OFFSET_UP, "DYNAMIC_GRID_UP", 0, "Dynamic grid Up", ""},
{DYNAMIC_GRID_OFFSET_DOWN, "DYNAMIC_GRID_DOWN", 0, "Dynamic grid Down", ""},
{DYNAMIC_GRID_OFFSET_LEFT, "DYNAMIC_GRID_LEFT", 0, "Dynamic grid Left", ""},
{DYNAMIC_GRID_OFFSET_RIGHT, "DYNAMIC_GRID_RIGHT", 0, "Dynamic grid Right", ""},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop;
prop = RNA_def_enum(ot->srna,
"offset_direction",
offset_direction,
0,
"UV Offset Direction",
"Offset and direction for moving selected UVs");
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Pin UV's Operator
* \{ */
@@ -2056,6 +2222,7 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_weld);
WM_operatortype_append(UV_OT_remove_doubles);
WM_operatortype_append(UV_OT_pin);
WM_operatortype_append(UV_OT_offset);
WM_operatortype_append(UV_OT_average_islands_scale);
WM_operatortype_append(UV_OT_cube_project);
@@ -2063,6 +2230,7 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_project_from_view);
WM_operatortype_append(UV_OT_minimize_stretch);
WM_operatortype_append(UV_OT_pack_islands);
WM_operatortype_append(UV_OT_pack_islands_to_area);
WM_operatortype_append(UV_OT_reset);
WM_operatortype_append(UV_OT_sphere_project);
WM_operatortype_append(UV_OT_unwrap);

View File

@@ -37,6 +37,7 @@
#include "BLI_alloca.h"
#include "BLI_array.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_string.h"
@@ -64,6 +65,7 @@
#include "PIL_time.h"
#include "UI_interface.h"
#include "UI_view2d.h"
#include "ED_image.h"
#include "ED_mesh.h"
@@ -1005,10 +1007,20 @@ static void uvedit_pack_islands_multi(const Scene *scene,
}
}
/* Packing targets */
enum {
CLOSEST_UDIM = 0,
SPECIFIED_UDIM = 1,
};
static int pack_islands_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
const Scene *scene = CTX_data_scene(C);
const SpaceImage *sima = CTX_wm_space_image(C);
const Image *image = sima->image;
const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
const UnwrapOptions options = {
.topology_from_uvs = true,
@@ -1018,17 +1030,19 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
.correct_aspect = true,
};
bool rotate = RNA_boolean_get(op->ptr, "rotate");
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, CTX_wm_view3d(C), &objects_len);
/* Early exit in case no UVs are selected */
if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
/* Set RNA props */
bool rotate = RNA_boolean_get(op->ptr, "rotate");
const bool use_target_udim = (RNA_enum_get(op->ptr, "packTo") == SPECIFIED_UDIM);
if (RNA_struct_property_is_set(op->ptr, "margin")) {
scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
}
@@ -1036,9 +1050,64 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
}
int target_udim = 1001;
if (use_target_udim) {
target_udim = RNA_int_get(op->ptr, "target_udim");
if (target_udim > 2000 || target_udim < 1001) {
/* Early exit since invalid UDIM was specified.
* Before exit, set RNA prop to the value specified when the operator was last used */
RNA_int_set(op->ptr, "target_udim", scene->toolsettings->target_udim);
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
/* Check if specifed UDIM index is valid */
bool is_udim_valid = false;
const int target_x = ((target_udim - 1001) % 10) + 1;
const int target_y = ((target_udim - 1001) / 10) + 1;
if (target_x <= sima->tile_grid_shape[0] && target_y <= sima->tile_grid_shape[1]) {
scene->toolsettings->target_udim = target_udim;
is_udim_valid = true;
}
else if (is_tiled_image) {
LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) {
if (target_udim == tile->tile_number) {
scene->toolsettings->target_udim = target_udim;
is_udim_valid = true;
break;
}
}
}
else if (image && !is_tiled_image) {
/* Non-tiled image. Always 0-1 UV space */
if (target_udim == 1001) {
scene->toolsettings->target_udim = target_udim;
is_udim_valid = true;
}
}
if (!is_udim_valid) {
if (RNA_struct_property_is_set(op->ptr, "target_udim")) {
/* Early exit since invalid UDIM was specified */
RNA_int_set(op->ptr, "target_udim", scene->toolsettings->target_udim);
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
else {
/* Fallback */
target_udim = 1001;
scene->toolsettings->target_udim = target_udim;
RNA_int_set(op->ptr, "target_udim", scene->toolsettings->target_udim);
}
}
}
ED_uvedit_pack_islands_multi(scene,
sima,
objects,
objects_len,
use_target_udim,
target_udim,
&(struct UVPackIsland_Params){
.rotate = rotate,
.rotate_align_axis = -1,
@@ -1048,31 +1117,280 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
});
MEM_freeN(objects);
return OPERATOR_FINISHED;
}
static void pack_islands_ui_draw(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
uiLayout *col;
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
col = uiLayoutColumn(layout, false);
/* Expose target UDIM property only if packing target is set to Specified UDIM */
uiItemR(col, op->ptr, "packTo", 0, NULL, 0);
if (RNA_enum_get(op->ptr, "packTo") == SPECIFIED_UDIM) {
uiItemR(col, op->ptr, "target_udim", 0, NULL, 0);
}
uiItemR(col, op->ptr, "rotate", 0, NULL, 0);
uiItemR(col, op->ptr, "margin", 0, NULL, 0);
}
void UV_OT_pack_islands(wmOperatorType *ot)
{
static const EnumPropertyItem pack_target[] = {
{CLOSEST_UDIM, "CLOSEST_UDIM", 0, "Closest UDIM", "Pack islands to closest UDIM"},
{SPECIFIED_UDIM, "SPECIFIED_UDIM", 0, "Specified UDIM", "Pack islands to specified UDIM"},
{0, NULL, 0, NULL, NULL},
};
/* identifiers */
ot->name = "Pack Islands";
ot->idname = "UV_OT_pack_islands";
ot->description = "Transform all islands so that they fill up the UV space as much as possible";
ot->description =
"Transform all islands so that they fill up the UV/UDIM space as much as possible";
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* api callbacks */
ot->exec = pack_islands_exec;
ot->poll = ED_operator_uvedit;
ot->ui = pack_islands_ui_draw;
/* properties */
RNA_def_enum(ot->srna, "packTo", pack_target, CLOSEST_UDIM, "Pack to", "");
RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit");
RNA_def_int(ot->srna,
"target_udim",
1001,
1001,
2000,
"Target UDIM",
"Pack islands to target UDIM",
1001,
1100);
RNA_def_float_factor(
ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Pack islands to area Operator
* \{ */
static int pack_islands_to_area_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
const Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, CTX_wm_view3d(C), &objects_len);
/* Packing area coordinates */
float box_min_co[2] = {0.0f, 0.0f};
float box_max_co[2] = {1.0f, 1.0f};
/* Store coordinates for operator rerun */
float pack_area[4] = {0.0f, 0.0f, 1.0f, 1.0f};
rctf bounds;
WM_operator_properties_border_to_rctf(op, &bounds);
UI_view2d_region_to_view_rctf(&region->v2d, &bounds, &bounds);
/* Bounding coordinates for the user-defined area */
box_min_co[0] = bounds.xmin;
box_min_co[1] = bounds.ymin;
box_max_co[0] = bounds.xmax;
box_max_co[1] = bounds.ymax;
RNA_float_get_array(op->ptr, "pack_area", pack_area);
/* Running operator through modal callback */
if (!RNA_struct_property_is_set(op->ptr, "pack_area")) {
RNA_float_set_array(op->ptr, "box_min_co", box_min_co);
RNA_float_set_array(op->ptr, "box_max_co", box_max_co);
pack_area[0] = box_min_co[0];
pack_area[1] = box_min_co[1];
pack_area[2] = box_max_co[0];
pack_area[3] = box_max_co[1];
RNA_float_set_array(op->ptr, "pack_area", pack_area);
/* Scale always true when box select used to define area */
RNA_boolean_set(op->ptr, "scale", true);
}
/* Re-running operator theough properties panel */
else {
RNA_float_get_array(op->ptr, "box_min_co", box_min_co);
RNA_float_get_array(op->ptr, "box_max_co", box_max_co);
if ((box_max_co[0] - box_min_co[0]) <= 0.001f || (box_max_co[1] - box_min_co[1]) <= 0.001f) {
box_min_co[0] = pack_area[0];
box_min_co[1] = pack_area[1];
box_max_co[0] = pack_area[2];
box_max_co[1] = pack_area[3];
RNA_float_set_array(op->ptr, "box_min_co", box_min_co);
RNA_float_set_array(op->ptr, "box_max_co", box_max_co);
RNA_float_set_array(op->ptr, "pack_area", pack_area);
/* CANCEL OPERATOR SINCE INVALID COORDINATES WERE ENTERED */
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
else {
pack_area[0] = box_min_co[0];
pack_area[1] = box_min_co[1];
pack_area[2] = box_max_co[0];
pack_area[3] = box_max_co[1];
RNA_float_set_array(op->ptr, "pack_area", pack_area);
}
}
/* Keeping a lower bound of 0.001 for user-defined space, smaller than that and the UVs won't be
* visible in the UV editor
* NOTE : Could be removed/changed */
if ((box_max_co[0] - box_min_co[0]) <= 0.001f || (box_max_co[1] - box_min_co[1]) <= 0.001f) {
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
/* RNA props */
bool rotate_islands = RNA_boolean_get(op->ptr, "rotate");
bool scale_islands = RNA_boolean_get(op->ptr, "scale");
if (RNA_struct_property_is_set(op->ptr, "margin")) {
scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
}
else {
RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
}
/* Cancel operator in case packing area is not big enough to pack all selected islands */
if (!ED_uvedit_pack_islands_to_area_multi(scene,
objects,
objects_len,
box_min_co,
box_max_co,
scale_islands,
&(struct UVPackIsland_Params){
.rotate = rotate_islands,
.rotate_align_axis = -1,
.only_selected_uvs = true,
.only_selected_faces = true,
.correct_aspect = true,
})) {
/* Warning might be better than using error. Something similar to
* dyntopo_warning_popup() might be ideal in this case */
BKE_report(op->reports,
RPT_ERROR,
"Operator Cancelled. Packing area not big enough for selected islands");
RNA_boolean_set(op->ptr, "scale", true);
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
MEM_freeN(objects);
return OPERATOR_FINISHED;
}
static int pack_islands_to_area_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* Check if any UVs are selected in the UV editor before calling WM_gesture_box_invoke() */
ViewLayer *view_layer = CTX_data_view_layer(C);
const Scene *scene = CTX_data_scene(C);
uint objects_len = 0;
/* Get reference to objects currently in edit mode */
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, CTX_wm_view3d(C), &objects_len);
const UnwrapOptions options = {
.topology_from_uvs = true,
.only_selected_faces = true,
.only_selected_uvs = true,
.fill_holes = false,
.correct_aspect = false,
};
/* If no islands selected then cancel operator */
if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
/* Free memory before running invoke */
MEM_freeN(objects);
return WM_gesture_box_invoke(C, op, event);
}
void UV_OT_pack_islands_to_area(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Pack Islands to area";
ot->idname = "UV_OT_pack_islands_to_area";
ot->description = "Transform selected islands so that they fill up specified area in UV space";
/* api callbacks */
ot->invoke = pack_islands_to_area_invoke;
ot->exec = pack_islands_to_area_exec;
ot->modal = WM_gesture_box_modal;
ot->cancel = WM_gesture_box_cancel;
ot->poll = ED_operator_uvedit;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* RNA properties */
/* Max coordinates of the packing area */
static float default_max[2] = {1.0f, 1.0f};
RNA_def_float_vector(ot->srna,
"box_max_co",
2,
default_max,
-100.0f,
100.0f,
"Maximum",
"Maximum coordinates for the packing area",
-100.0f,
100.0f);
/* Min coordinates of packing area */
static float default_min[2] = {0.0f, 0.0f};
RNA_def_float_vector(ot->srna,
"box_min_co",
2,
default_min,
-100.0f,
100.0f,
"Minimum",
"Minimum coordinates for the packing area",
-100.0f,
100.0f);
RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit");
RNA_def_boolean(ot->srna, "scale", true, "Scale", "Preserve island scale when packing");
RNA_def_float_factor(
ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
/* Store pack area coordinates for rerun from properties panel */
PropertyRNA *prop;
static float default_val[4] = {0.0f, 0.0f, 1.0f, 1.0f};
prop = RNA_def_float_array(ot->srna,
"pack_area",
4,
default_val,
INT_MIN,
INT_MAX,
"Packing area coordinates",
"",
INT_MIN,
INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
WM_operator_properties_border(ot);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Average UV Islands Scale Operator
* \{ */
@@ -2055,6 +2373,8 @@ static int smart_project_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
/* sima=NULL cases are handled in ED_uvedit_pack_islands_multi() */
const SpaceImage *sima = CTX_wm_space_image(C);
/* May be NULL. */
View3D *v3d = CTX_wm_view3d(C);
@@ -2065,6 +2385,7 @@ static int smart_project_exec(bContext *C, wmOperator *op)
const float project_angle_limit_cos = cosf(project_angle_limit);
const float project_angle_limit_half_cos = cosf(project_angle_limit / 2);
const int target_udim = 1001; /* 0-1 UV space */
/* Memory arena for list links (cleared for each object). */
MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@@ -2204,8 +2525,11 @@ static int smart_project_exec(bContext *C, wmOperator *op)
/* Depsgraph refresh functions are called here. */
const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
ED_uvedit_pack_islands_multi(scene,
sima,
objects_changed,
object_changed_len,
true,
target_udim,
&(struct UVPackIsland_Params){
.rotate = true,
/* We could make this optional. */

View File

@@ -337,6 +337,7 @@
.doublimit = 0.001, \
.vgroup_weight = 1.0f, \
.uvcalc_margin = 0.001f, \
.target_udim = 1001, \
.uvcalc_flag = UVCALC_TRANSFORM_CORRECT_SLIDE, \
.unwrapper = 1, \
.select_thresh = 0.01f, \

View File

@@ -1404,6 +1404,8 @@ typedef struct ToolSettings {
char uv_selectmode;
float uvcalc_margin;
int target_udim; /* Can be extended for unwrap operator as well */
int _pad3[1];
/* Auto-IK */
/** Runtime only. */
@@ -1463,14 +1465,12 @@ typedef struct ToolSettings {
char edge_mode_live_unwrap;
char _pad1[1];
/* Transform */
char transform_pivot_point;
char transform_flag;
char snap_mode, snap_node_mode;
char snap_uv_mode;
char snap_flag;
short snap_flag;
char snap_target;
char snap_transform_mode_flag;
@@ -2051,6 +2051,7 @@ enum {
#define SCE_SNAP_ABS_GRID (1 << 5)
#define SCE_SNAP_BACKFACE_CULLING (1 << 6)
#define SCE_SNAP_SEQ (1 << 7)
#define SCE_SNAP_ABS_UV_GRID (1 << 8)
/** #ToolSettings.snap_target */
#define SCE_SNAP_TARGET_CLOSEST 0

View File

@@ -1197,6 +1197,9 @@ typedef struct SpaceImage {
float uv_opacity;
int tile_grid_shape[2];
/** UV editor Dynamic Grid. Value of N will produce NxN grid. */
int dynamic_grid_size;
char _pad3[4];
MaskSpaceInfo mask_info;
SpaceImageOverlay overlay;
@@ -1252,7 +1255,9 @@ typedef enum eSpaceImage_Flag {
SI_FLAG_UNUSED_7 = (1 << 7), /* cleared */
SI_FLAG_UNUSED_8 = (1 << 8), /* cleared */
SI_COORDFLOATS = (1 << 9),
SI_FLAG_UNUSED_10 = (1 << 10),
/* Use dynamic grid in UV editor */
SI_DYNAMIC_GRID = (1 << 10),
SI_LIVE_UNWRAP = (1 << 11),
SI_USE_ALPHA = (1 << 12),
SI_SHOW_ALPHA = (1 << 13),

View File

@@ -3156,6 +3156,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Snap UV Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_uv_grid_absolute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_ABS_UV_GRID);
RNA_def_property_ui_text(
prop,
"Absolute Grid Snap",
"Absolute grid alignment while translating (based on the pivot center)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "snap_target", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "snap_target");
RNA_def_property_enum_items(prop, rna_enum_snap_target_items);

View File

@@ -1775,9 +1775,17 @@ static const EnumPropertyItem *rna_SpaceImageEditor_pivot_itemf(bContext *UNUSED
bool *UNUSED(r_free))
{
static const EnumPropertyItem pivot_items[] = {
{V3D_AROUND_CENTER_BOUNDS, "CENTER", ICON_PIVOT_BOUNDBOX, "Bounding Box Center", ""},
{V3D_AROUND_CENTER_MEDIAN, "MEDIAN", ICON_PIVOT_MEDIAN, "Median Point", ""},
{V3D_AROUND_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "2D Cursor", ""},
{V3D_AROUND_CENTER_BOUNDS,
"CENTER",
ICON_PIVOT_BOUNDBOX,
"Bounding Box Center",
"Pivot around bounding box center of selected UVs"},
{V3D_AROUND_CENTER_MEDIAN,
"MEDIAN",
ICON_PIVOT_MEDIAN,
"Median Point",
"Pivot around the median point of selected UVs"},
{V3D_AROUND_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "2D Cursor", "Pivot around the 2D Cursor"},
{V3D_AROUND_LOCAL_ORIGINS,
"INDIVIDUAL_ORIGINS",
ICON_PIVOT_INDIVIDUAL,
@@ -3443,6 +3451,19 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
prop, "Tile Grid Shape", "How many tiles will be shown in the background");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "use_dynamic_grid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DYNAMIC_GRID);
RNA_def_property_ui_text(prop, "Dynamic Grid", "Replace the default grid with a Dynamic grid");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "dynamic_grid_size", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "dynamic_grid_size");
RNA_def_property_int_default(prop, 1);
RNA_def_property_range(prop, 1, 5000);
RNA_def_property_ui_text(
prop, "Dynamic Grid Size", "How many grid units in UV space make one UV Unit");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "uv_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "uv_opacity");
RNA_def_property_range(prop, 0.0f, 1.0f);

View File

@@ -75,7 +75,6 @@ void RNA_api_texture(StructRNA *srna)
-1e4,
1e4);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* return location and normal */
parm = RNA_def_float_vector(
func,

View File

@@ -4019,6 +4019,7 @@ static void gesture_box_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border");
WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border");
WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
WM_modalkeymap_assign(keymap, "UV_OT_pack_islands_to_area");
WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_box");
}