Merge remote-tracking branch 'origin/master' into sculpt-dev

Also fixed a bug with eevee and color attributes.
This commit is contained in:
Joseph Eagar 2022-05-12 01:10:47 -07:00
commit cd316eb6c6
27 changed files with 324 additions and 133 deletions

View File

@ -13,9 +13,11 @@ CCL_NAMESPACE_BEGIN
BlenderImageLoader::BlenderImageLoader(BL::Image b_image,
const int frame,
const int tile_number,
const bool is_preview_render)
: b_image(b_image),
frame(frame),
tile_number(tile_number),
/* Don't free cache for preview render to avoid race condition from T93560, to be fixed
properly later as we are close to release. */
free_cache(!is_preview_render && !b_image.has_data())
@ -66,12 +68,11 @@ bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata,
{
const size_t num_pixels = ((size_t)metadata.width) * metadata.height;
const int channels = metadata.channels;
const int tile = 0; /* TODO(lukas): Support tiles here? */
if (b_image.is_float()) {
/* image data */
float *image_pixels;
image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile);
image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile_number);
if (image_pixels && num_pixels * channels == pixels_size) {
memcpy(pixels, image_pixels, pixels_size * sizeof(float));
@ -99,7 +100,7 @@ bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata,
}
}
else {
unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile);
unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
if (image_pixels && num_pixels * channels == pixels_size) {
memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
@ -153,7 +154,13 @@ string BlenderImageLoader::name() const
bool BlenderImageLoader::equals(const ImageLoader &other) const
{
const BlenderImageLoader &other_loader = (const BlenderImageLoader &)other;
return b_image == other_loader.b_image && frame == other_loader.frame;
return b_image == other_loader.b_image && frame == other_loader.frame &&
tile_number == other_loader.tile_number;
}
int BlenderImageLoader::get_tile_number() const
{
return tile_number;
}
/* Point Density */

View File

@ -12,7 +12,10 @@ CCL_NAMESPACE_BEGIN
class BlenderImageLoader : public ImageLoader {
public:
BlenderImageLoader(BL::Image b_image, const int frame, const bool is_preview_render);
BlenderImageLoader(BL::Image b_image,
const int frame,
const int tile_number,
const bool is_preview_render);
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
@ -22,8 +25,11 @@ class BlenderImageLoader : public ImageLoader {
string name() const override;
bool equals(const ImageLoader &other) const override;
int get_tile_number() const override;
BL::Image b_image;
int frame;
int tile_number;
bool free_cache;
};

View File

@ -776,9 +776,21 @@ static ShaderNode *add_node(Scene *scene,
*/
int scene_frame = b_scene.frame_current();
int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
image->handle = scene->image_manager->add_image(
new BlenderImageLoader(b_image, image_frame, b_engine.is_preview()),
image->image_params());
if (b_image.source() != BL::Image::source_TILED) {
image->handle = scene->image_manager->add_image(
new BlenderImageLoader(b_image, image_frame, 0, b_engine.is_preview()),
image->image_params());
}
else {
vector<ImageLoader *> loaders;
loaders.reserve(image->get_tiles().size());
for (int tile_number : image->get_tiles()) {
loaders.push_back(
new BlenderImageLoader(b_image, image_frame, tile_number, b_engine.is_preview()));
}
image->handle = scene->image_manager->add_image(loaders, image->image_params());
}
}
else {
ustring filename = ustring(
@ -814,7 +826,7 @@ static ShaderNode *add_node(Scene *scene,
int scene_frame = b_scene.frame_current();
int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
env->handle = scene->image_manager->add_image(
new BlenderImageLoader(b_image, image_frame, b_engine.is_preview()),
new BlenderImageLoader(b_image, image_frame, 0, b_engine.is_preview()),
env->image_params());
}
else {

View File

@ -1304,8 +1304,38 @@ bool OSLRenderServices::texture(ustring filename,
break;
}
case OSLTextureHandle::SVM: {
/* Packed texture. */
float4 rgba = kernel_tex_image_interp(kernel_globals, handle->svm_slot, s, 1.0f - t);
int id = -1;
if (handle->svm_slots[0].w == -1) {
/* Packed single texture. */
id = handle->svm_slots[0].y;
}
else {
/* Packed tiled texture. */
int tx = (int)s;
int ty = (int)t;
int tile = 1001 + 10 * ty + tx;
for (int4 tile_node : handle->svm_slots) {
if (tile_node.x == tile) {
id = tile_node.y;
break;
}
if (tile_node.z == tile) {
id = tile_node.w;
break;
}
}
s -= tx;
t -= ty;
}
float4 rgba;
if (id == -1) {
rgba = make_float4(
TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
}
else {
rgba = kernel_tex_image_interp(kernel_globals, id, s, 1.0f - t);
}
result[0] = rgba[0];
if (nchannels > 1)
@ -1319,7 +1349,7 @@ bool OSLRenderServices::texture(ustring filename,
}
case OSLTextureHandle::IES: {
/* IES light. */
result[0] = kernel_ies_interp(kernel_globals, handle->svm_slot, s, t);
result[0] = kernel_ies_interp(kernel_globals, handle->svm_slots[0].y, s, t);
status = true;
break;
}
@ -1413,7 +1443,7 @@ bool OSLRenderServices::texture3d(ustring filename,
/* Packed texture. */
ShaderData *sd = (ShaderData *)(sg->renderstate);
KernelGlobals kernel_globals = sd->osl_globals;
int slot = handle->svm_slot;
int slot = handle->svm_slots[0].y;
float3 P_float3 = make_float3(P.x, P.y, P.z);
float4 rgba = kernel_tex_image_interp_3d(kernel_globals, slot, P_float3, INTERPOLATION_NONE);

View File

@ -39,18 +39,26 @@ struct KernelGlobalsCPU;
* with additional data.
*
* These are stored in a concurrent hash map, because OSL can compile multiple
* shaders in parallel. */
* shaders in parallel.
*
* Note: The svm_slots array contains a compressed mapping of tile to svm_slot pairs
* stored as follows: x:tile_a, y:svm_slot_a, z:tile_b, w:svm_slot_b etc. */
struct OSLTextureHandle : public OIIO::RefCnt {
enum Type { OIIO, SVM, IES, BEVEL, AO };
OSLTextureHandle(Type type, const vector<int4> &svm_slots)
: type(type), svm_slots(svm_slots), oiio_handle(NULL), processor(NULL)
{
}
OSLTextureHandle(Type type = OIIO, int svm_slot = -1)
: type(type), svm_slot(svm_slot), oiio_handle(NULL), processor(NULL)
: OSLTextureHandle(type, {make_int4(0, svm_slot, -1, -1)})
{
}
Type type;
int svm_slot;
vector<int4> svm_slots;
OSL::TextureSystem::TextureHandle *oiio_handle;
ColorSpaceProcessor *processor;
};

View File

@ -117,12 +117,12 @@ void ImageHandle::clear()
manager = NULL;
}
bool ImageHandle::empty()
bool ImageHandle::empty() const
{
return tile_slots.empty();
}
int ImageHandle::num_tiles()
int ImageHandle::num_tiles() const
{
return tile_slots.size();
}
@ -154,6 +154,35 @@ int ImageHandle::svm_slot(const int tile_index) const
return tile_slots[tile_index];
}
vector<int4> ImageHandle::get_svm_slots() const
{
const size_t num_nodes = divide_up(tile_slots.size(), 2);
vector<int4> svm_slots;
svm_slots.reserve(num_nodes);
for (size_t i = 0; i < num_nodes; i++) {
int4 node;
int slot = tile_slots[2 * i];
node.x = manager->images[slot]->loader->get_tile_number();
node.y = slot;
if ((2 * i + 1) < tile_slots.size()) {
slot = tile_slots[2 * i + 1];
node.z = manager->images[slot]->loader->get_tile_number();
node.w = slot;
}
else {
node.z = -1;
node.w = -1;
}
svm_slots.push_back(node);
}
return svm_slots;
}
device_texture *ImageHandle::image_memory(const int tile_index) const
{
if (tile_index >= tile_slots.size()) {
@ -266,6 +295,11 @@ ustring ImageLoader::osl_filepath() const
return ustring();
}
int ImageLoader::get_tile_number() const
{
return 0;
}
bool ImageLoader::equals(const ImageLoader *a, const ImageLoader *b)
{
if (a == NULL && b == NULL) {
@ -397,6 +431,19 @@ ImageHandle ImageManager::add_image(ImageLoader *loader,
return handle;
}
ImageHandle ImageManager::add_image(const vector<ImageLoader *> &loaders,
const ImageParams &params)
{
ImageHandle handle;
for (ImageLoader *loader : loaders) {
const int slot = add_image_slot(loader, params, true);
handle.tile_slots.push_back(slot);
}
handle.manager = this;
return handle;
}
int ImageManager::add_image_slot(ImageLoader *loader,
const ImageParams &params,
const bool builtin)

View File

@ -112,6 +112,9 @@ class ImageLoader {
/* Optional for OSL texture cache. */
virtual ustring osl_filepath() const;
/* Optional for tiled textures loaded externally. */
virtual int get_tile_number() const;
/* Free any memory used for loading metadata and pixels. */
virtual void cleanup(){};
@ -139,11 +142,12 @@ class ImageHandle {
void clear();
bool empty();
int num_tiles();
bool empty() const;
int num_tiles() const;
ImageMetaData metadata();
int svm_slot(const int tile_index = 0) const;
vector<int4> get_svm_slots() const;
device_texture *image_memory(const int tile_index = 0) const;
VDBImageLoader *vdb_loader(const int tile_index = 0) const;
@ -169,6 +173,7 @@ class ImageManager {
const ImageParams &params,
const array<int> &tiles);
ImageHandle add_image(ImageLoader *loader, const ImageParams &params, const bool builtin = true);
ImageHandle add_image(const vector<ImageLoader *> &loaders, const ImageParams &params);
void device_update(Device *device, Scene *scene, Progress &progress);
void device_update_slot(Device *device, Scene *scene, int slot, Progress *progress);

View File

@ -1211,14 +1211,15 @@ void OSLCompiler::parameter_texture(const char *name, ustring filename, ustring
parameter(name, filename);
}
void OSLCompiler::parameter_texture(const char *name, int svm_slot)
void OSLCompiler::parameter_texture(const char *name, const ImageHandle &handle)
{
/* Texture loaded through SVM image texture system. We generate a unique
* name, which ends up being used in OSLRenderServices::get_texture_handle
* to get handle again. Note that this name must be unique between multiple
* render sessions as the render services are shared. */
ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
services->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::SVM, svm_slot));
services->textures.insert(filename,
new OSLTextureHandle(OSLTextureHandle::SVM, handle.get_svm_slots()));
parameter(name, filename);
}
@ -1290,7 +1291,7 @@ void OSLCompiler::parameter_texture(const char * /* name */,
{
}
void OSLCompiler::parameter_texture(const char * /* name */, int /* svm_slot */)
void OSLCompiler::parameter_texture(const char * /* name */, const ImageHandle & /*handle*/)
{
}

View File

@ -147,7 +147,7 @@ class OSLCompiler {
void parameter_attribute(const char *name, ustring s);
void parameter_texture(const char *name, ustring filename, ustring colorspace);
void parameter_texture(const char *name, int svm_slot);
void parameter_texture(const char *name, const ImageHandle &handle);
void parameter_texture_ies(const char *name, int svm_slot);
ShaderType output_type()

View File

@ -453,14 +453,15 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
}
else {
compiler.parameter_texture("filename", handle.svm_slot());
compiler.parameter_texture("filename", handle);
}
const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
alpha_type == IMAGE_ALPHA_IGNORE);
const bool is_tiled = (filename.find("<UDIM>") != string::npos ||
filename.find("<UVTILE>") != string::npos);
filename.find("<UVTILE>") != string::npos) ||
handle.num_tiles() > 1;
compiler.parameter(this, "projection");
compiler.parameter(this, "projection_blend");
@ -605,7 +606,7 @@ void EnvironmentTextureNode::compile(OSLCompiler &compiler)
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
}
else {
compiler.parameter_texture("filename", handle.svm_slot());
compiler.parameter_texture("filename", handle);
}
compiler.parameter(this, "projection");
@ -960,7 +961,7 @@ void SkyTextureNode::compile(OSLCompiler &compiler)
compiler.parameter_array("nishita_data", sunsky.nishita_data, 10);
/* nishita texture */
if (sky_type == NODE_SKY_NISHITA) {
compiler.parameter_texture("filename", handle.svm_slot());
compiler.parameter_texture("filename", handle);
}
compiler.add(this, "node_sky_texture");
}
@ -1855,7 +1856,7 @@ void PointDensityTextureNode::compile(OSLCompiler &compiler)
handle = image_manager->add_image(filename.string(), image_params());
}
compiler.parameter_texture("filename", handle.svm_slot());
compiler.parameter_texture("filename", handle);
if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", tfm);
compiler.parameter("use_mapping", 1);

View File

@ -203,7 +203,7 @@ class DATA_PT_geometry_curve_start_end(CurveButtonsPanelCurve, Panel):
@classmethod
def poll(cls, context):
# Text objects don't support these properties
return (type(context.curve) in {Curve})
return (type(context.curve) == Curve)
def draw(self, context):
layout = self.layout

View File

@ -389,7 +389,8 @@ class _draw_tool_settings_context_mode:
"strength",
pressure_name="use_pressure_strength",
unified_name="use_unified_strength",
header=True)
header=True
)
return True
@ -537,16 +538,16 @@ class _draw_tool_settings_context_mode:
return False
UnifiedPaintPanel.prop_unified(
layout,
context,
brush,
"size",
unified_name="use_unified_size",
pressure_name="use_pressure_size",
text="Radius",
slider=True,
header=True
)
layout,
context,
brush,
"size",
unified_name="use_unified_size",
pressure_name="use_pressure_size",
text="Radius",
slider=True,
header=True,
)
if brush.curves_sculpt_tool not in {'ADD', 'DELETE'}:
UnifiedPaintPanel.prop_unified(
@ -556,7 +557,7 @@ class _draw_tool_settings_context_mode:
"strength",
unified_name="use_unified_strength",
pressure_name="use_pressure_strength",
header=True
header=True,
)
if brush.curves_sculpt_tool == 'COMB':
@ -569,7 +570,6 @@ class _draw_tool_settings_context_mode:
layout.popover("VIEW3D_PT_curves_sculpt_add_shape", text="Curve Shape")
layout.prop(brush, "use_frontface", text="Front Faces Only")
if brush.curves_sculpt_tool == 'GROW_SHRINK':
layout.prop(brush, "direction", expand=True, text="")
layout.prop(brush, "falloff_shape", expand=True)

View File

@ -454,7 +454,7 @@ bool BKE_image_is_dirty_writable(struct Image *image, bool *r_is_writable);
int BKE_image_sequence_guess_offset(struct Image *image);
bool BKE_image_has_anim(struct Image *image);
bool BKE_image_has_packedfile(const struct Image *image);
bool BKE_image_has_filepath(struct Image *ima);
bool BKE_image_has_filepath(const struct Image *ima);
/**
* Checks the image buffer changes with time (not keyframed values).
*/

View File

@ -721,6 +721,9 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src)
imapf_src = imapf_src->next) {
ImagePackedFile *imapf_dst = static_cast<ImagePackedFile *>(
MEM_mallocN(sizeof(ImagePackedFile), "Image Packed Files (copy)"));
imapf_dst->view = imapf_src->view;
imapf_dst->tile_number = imapf_src->tile_number;
STRNCPY(imapf_dst->filepath, imapf_src->filepath);
if (imapf_src->packedfile) {
@ -1197,7 +1200,8 @@ Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
}
/** Pack image buffer to memory as PNG or EXR. */
static bool image_memorypack_imbuf(Image *ima, ImBuf *ibuf, const char *filepath)
static bool image_memorypack_imbuf(
Image *ima, ImBuf *ibuf, int view, int tile_number, const char *filepath)
{
ibuf->ftype = (ibuf->rect_float) ? IMB_FTYPE_OPENEXR : IMB_FTYPE_PNG;
@ -1219,6 +1223,8 @@ static bool image_memorypack_imbuf(Image *ima, ImBuf *ibuf, const char *filepath
imapf = static_cast<ImagePackedFile *>(MEM_mallocN(sizeof(ImagePackedFile), "Image PackedFile"));
STRNCPY(imapf->filepath, filepath);
imapf->packedfile = pf;
imapf->view = view;
imapf->tile_number = tile_number;
BLI_addtail(&ima->packedfiles, imapf);
ibuf->encodedbuffer = nullptr;
@ -1234,42 +1240,47 @@ bool BKE_image_memorypack(Image *ima)
image_free_packedfiles(ima);
if (BKE_image_is_multiview(ima)) {
/* Store each view as a separate packed files with R_IMF_VIEWS_INDIVIDUAL. */
ImageView *iv;
int i;
const int tot_viewfiles = image_num_viewfiles(ima);
const bool is_tiled = (ima->source == IMA_SRC_TILED);
const bool is_multiview = BKE_image_is_multiview(ima);
for (i = 0, iv = static_cast<ImageView *>(ima->views.first); iv;
iv = static_cast<ImageView *>(iv->next), i++) {
ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, i, 0, nullptr);
ImageUser iuser{};
BKE_imageuser_default(&iuser);
char tiled_filepath[FILE_MAX];
for (int view = 0; view < tot_viewfiles; view++) {
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
int index = (is_multiview || is_tiled) ? view : IMA_NO_INDEX;
int entry = is_tiled ? tile->tile_number : 0;
ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, index, entry, nullptr);
if (!ibuf) {
ok = false;
break;
}
/* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */
if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX};
BLI_path_suffix(iv->filepath, FILE_MAX, suffix[i], "");
const char *filepath = ibuf->name;
if (is_tiled) {
iuser.tile = tile->tile_number;
BKE_image_user_file_path(&iuser, ima, tiled_filepath);
filepath = tiled_filepath;
}
else if (is_multiview) {
ImageView *iv = static_cast<ImageView *>(BLI_findlink(&ima->views, view));
/* if the image was a R_IMF_VIEWS_STEREO_3D we force _L, _R suffices */
if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
const char *suffix[2] = {STEREO_LEFT_SUFFIX, STEREO_RIGHT_SUFFIX};
BLI_path_suffix(iv->filepath, FILE_MAX, suffix[view], "");
}
filepath = iv->filepath;
}
ok = ok && image_memorypack_imbuf(ima, ibuf, iv->filepath);
ok = ok && image_memorypack_imbuf(ima, ibuf, view, tile->tile_number, filepath);
IMB_freeImBuf(ibuf);
}
ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
}
else {
ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0, nullptr);
if (ibuf) {
ok = ok && image_memorypack_imbuf(ima, ibuf, ibuf->name);
IMB_freeImBuf(ibuf);
}
else {
ok = false;
}
if (is_multiview) {
ima->views_format = R_IMF_VIEWS_INDIVIDUAL;
}
if (ok && ima->source == IMA_SRC_GENERATED) {
@ -1284,27 +1295,24 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
{
const int tot_viewfiles = image_num_viewfiles(ima);
if (tot_viewfiles == 1) {
ImagePackedFile *imapf = static_cast<ImagePackedFile *>(
MEM_mallocN(sizeof(ImagePackedFile), "Image packed file"));
BLI_addtail(&ima->packedfiles, imapf);
imapf->packedfile = BKE_packedfile_new(reports, ima->filepath, basepath);
if (imapf->packedfile) {
STRNCPY(imapf->filepath, ima->filepath);
}
else {
BLI_freelinkN(&ima->packedfiles, imapf);
}
}
else {
for (ImageView *iv = static_cast<ImageView *>(ima->views.first); iv; iv = iv->next) {
ImageUser iuser{};
BKE_imageuser_default(&iuser);
for (int view = 0; view < tot_viewfiles; view++) {
iuser.view = view;
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
iuser.tile = tile->tile_number;
char filepath[FILE_MAX];
BKE_image_user_file_path(&iuser, ima, filepath);
ImagePackedFile *imapf = static_cast<ImagePackedFile *>(
MEM_mallocN(sizeof(ImagePackedFile), "Image packed file"));
BLI_addtail(&ima->packedfiles, imapf);
imapf->packedfile = BKE_packedfile_new(reports, iv->filepath, basepath);
imapf->packedfile = BKE_packedfile_new(reports, filepath, basepath);
imapf->view = view;
imapf->tile_number = tile->tile_number;
if (imapf->packedfile) {
STRNCPY(imapf->filepath, iv->filepath);
STRNCPY(imapf->filepath, filepath);
}
else {
BLI_freelinkN(&ima->packedfiles, imapf);
@ -1323,11 +1331,16 @@ void BKE_image_packfiles_from_mem(ReportList *reports,
if (tot_viewfiles != 1) {
BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently...");
}
else if (ima->source == IMA_SRC_TILED) {
BKE_report(reports, RPT_ERROR, "Cannot pack tiled images from raw data currently...");
}
else {
ImagePackedFile *imapf = static_cast<ImagePackedFile *>(
MEM_mallocN(sizeof(ImagePackedFile), __func__));
BLI_addtail(&ima->packedfiles, imapf);
imapf->packedfile = BKE_packedfile_new_from_memory(data, data_len);
imapf->view = 0;
imapf->tile_number = 1001;
STRNCPY(imapf->filepath, ima->filepath);
}
}
@ -2950,8 +2963,9 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
/* try to repack file */
if (BKE_image_has_packedfile(ima)) {
const int tot_viewfiles = image_num_viewfiles(ima);
const int tot_files = tot_viewfiles * BLI_listbase_count(&ima->tiles);
if (tot_viewfiles != BLI_listbase_count_at_most(&ima->packedfiles, tot_viewfiles + 1)) {
if (tot_files != BLI_listbase_count_at_most(&ima->packedfiles, tot_files + 1)) {
/* in case there are new available files to be loaded */
image_free_packedfiles(ima);
BKE_image_packfiles(nullptr, ima, ID_BLEND_PATH(bmain, &ima->id));
@ -3926,18 +3940,23 @@ static ImBuf *load_image_single(Image *ima,
int flag = IB_rect | IB_multilayer;
*r_cache_ibuf = true;
const int tile_number = image_get_tile_number_from_iuser(ima, iuser);
/* is there a PackedFile with this image ? */
if (has_packed && !is_sequence) {
ImagePackedFile *imapf = static_cast<ImagePackedFile *>(
BLI_findlink(&ima->packedfiles, view_id));
if (imapf->packedfile) {
flag |= imbuf_alpha_flags_for_image(ima);
ibuf = IMB_ibImageFromMemory((unsigned char *)imapf->packedfile->data,
imapf->packedfile->size,
flag,
ima->colorspace_settings.name,
"<packed data>");
flag |= imbuf_alpha_flags_for_image(ima);
LISTBASE_FOREACH (ImagePackedFile *, imapf, &ima->packedfiles) {
if (imapf->view == view_id && imapf->tile_number == tile_number) {
if (imapf->packedfile) {
ibuf = IMB_ibImageFromMemory((unsigned char *)imapf->packedfile->data,
imapf->packedfile->size,
flag,
ima->colorspace_settings.name,
"<packed data>");
}
break;
}
}
}
else {
@ -3996,6 +4015,8 @@ static ImBuf *load_image_single(Image *ima,
BLI_addtail(&ima->packedfiles, imapf);
STRNCPY(imapf->filepath, filepath);
imapf->view = view_id;
imapf->tile_number = tile_number;
imapf->packedfile = BKE_packedfile_new(
nullptr, filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
}
@ -5103,7 +5124,7 @@ bool BKE_image_has_packedfile(const Image *ima)
return (BLI_listbase_is_empty(&ima->packedfiles) == false);
}
bool BKE_image_has_filepath(Image *ima)
bool BKE_image_has_filepath(const Image *ima)
{
/* This could be improved to detect cases like //../../, currently path
* remapping empty file paths empty. */

View File

@ -237,14 +237,14 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
for (ima = bmain->images.first; ima; ima = ima->id.next) {
if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED(ima)) {
if (ima->source == IMA_SRC_FILE) {
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_TILED)) {
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot++;
}
else if (BKE_image_has_multiple_ibufs(ima) && verbose) {
else if (ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE) && verbose) {
BKE_reportf(reports,
RPT_WARNING,
"Image '%s' skipped, movies, image sequences and packed files not supported",
"Image '%s' skipped, packing movies or image sequences not supported",
ima->id.name + 2);
}
}
@ -494,15 +494,22 @@ static void unpack_generate_paths(const char *name,
if (tempname[0] == '\0') {
/* NOTE: we generally do not have any real way to re-create extension out of data. */
BLI_strncpy(tempname, id->name + 2, sizeof(tempname));
const size_t len = BLI_strncpy_rlen(tempname, id->name + 2, sizeof(tempname));
printf("%s\n", tempname);
/* For images we can add the file extension based on the file magic. */
/* For images ensure that the temporary filename contains tile number information as well as
* a file extension based on the file magic. */
if (id_type == ID_IM) {
ImagePackedFile *imapf = ((Image *)id)->packedfiles.last;
Image *ima = (Image *)id;
ImagePackedFile *imapf = ima->packedfiles.last;
if (imapf != NULL && imapf->packedfile != NULL) {
const PackedFile *pf = imapf->packedfile;
enum eImbFileType ftype = IMB_ispic_type_from_memory((const uchar *)pf->data, pf->size);
if (ima->source == IMA_SRC_TILED) {
char tile_number[6];
BLI_snprintf(tile_number, sizeof(tile_number), ".%d", imapf->tile_number);
BLI_strncpy(tempname + len, tile_number, sizeof(tempname) - len);
}
if (ftype != IMB_FTYPE_NONE) {
const int imtype = BKE_ftype_to_imtype(ftype, NULL);
BKE_image_path_ensure_ext_from_imtype(tempname, imtype);
@ -639,6 +646,11 @@ int BKE_packedfile_unpack_image(Main *bmain,
/* keep the new name in the image for non-pack specific reasons */
if (how != PF_REMOVE) {
BLI_strncpy(ima->filepath, new_file_path, sizeof(imapf->filepath));
if (ima->source == IMA_SRC_TILED) {
/* Ensure that the Image filepath is kept in a tokenized format. */
char *filename = (char *)BLI_path_basename(ima->filepath);
BKE_image_ensure_tile_token(filename);
}
}
MEM_freeN(new_file_path);
}

View File

@ -3550,5 +3550,16 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
brush->curves_sculpt_settings->points_per_curve = 8;
}
}
/* UDIM Packing. */
if (!DNA_struct_elem_find(fd->filesdna, "ImagePackedFile", "int", "tile_number")) {
for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
int view;
LISTBASE_FOREACH_INDEX (ImagePackedFile *, imapf, &ima->packedfiles, view) {
imapf->view = view;
imapf->tile_number = 1001;
}
}
}
}
}

View File

@ -505,10 +505,10 @@ static bool custom_data_match_attribute(const CustomData *custom_data,
return false;
}
ATTR_NO_OPT static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
const CustomData *cd_vdata,
const CustomData *cd_ldata,
const char name[])
static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
const CustomData *cd_vdata,
const CustomData *cd_ldata,
const char name[])
{
CustomDataLayer *layer = NULL;
AttributeDomain domain;
@ -552,11 +552,11 @@ ATTR_NO_OPT static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
return vcol_i;
}
ATTR_NO_OPT static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
const Mesh *me,
struct GPUMaterial **gpumat_array,
int gpumat_array_len,
DRW_MeshAttributes *attributes)
static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
const Mesh *me,
struct GPUMaterial **gpumat_array,
int gpumat_array_len,
DRW_MeshAttributes *attributes)
{
const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);

View File

@ -25,7 +25,7 @@ struct VColRef {
* corresponds to the integer position of the attribute
* within the global color attribute list.
*/
ATTR_NO_OPT static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
const CustomData *cd_ldata,
const uint vcol_layers)
{
@ -71,7 +71,7 @@ namespace blender::draw {
* \{ */
/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */
ATTR_NO_OPT static void init_vcol_format(GPUVertFormat *format,
static void init_vcol_format(GPUVertFormat *format,
const MeshBatchCache *cache,
CustomData *cd_vdata,
CustomData *cd_ldata,
@ -122,7 +122,7 @@ using gpuMeshVcol = struct gpuMeshVcol {
ushort r, g, b, a;
};
ATTR_NO_OPT static void extract_vcol_init(const MeshRenderData *mr,
static void extract_vcol_init(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))

View File

@ -494,7 +494,7 @@ static bool add_collection_search_item(CollItemSearch *cis,
cis->name,
cis->data,
cis->iconid,
cis->has_sep_char ? UI_BUT_HAS_SEP_CHAR : 0,
cis->has_sep_char ? (uint64_t)UI_BUT_HAS_SEP_CHAR : 0,
name_prefix_offset);
}

View File

@ -2316,6 +2316,14 @@ static bool image_has_valid_path(Image *ima)
return strchr(ima->filepath, '\\') || strchr(ima->filepath, '/');
}
static bool image_should_pack_during_save_all(const Image *ima)
{
/* Images without a filepath (implied with IMA_SRC_GENERATED) should
* be packed during a save_all operation. */
return (ima->source == IMA_SRC_GENERATED) ||
(ima->source == IMA_SRC_TILED && !BKE_image_has_filepath(ima));
}
bool ED_image_should_save_modified(const Main *bmain)
{
ReportList reports;
@ -2339,7 +2347,7 @@ int ED_image_save_all_modified_info(const Main *bmain, ReportList *reports)
bool is_format_writable;
if (image_should_be_saved(ima, &is_format_writable)) {
if (BKE_image_has_packedfile(ima) || (ima->source == IMA_SRC_GENERATED)) {
if (BKE_image_has_packedfile(ima) || image_should_pack_during_save_all(ima)) {
if (!ID_IS_LINKED(ima)) {
num_saveable_images++;
}
@ -2396,7 +2404,7 @@ bool ED_image_save_all_modified(const bContext *C, ReportList *reports)
bool is_format_writable;
if (image_should_be_saved(ima, &is_format_writable)) {
if (BKE_image_has_packedfile(ima) || (ima->source == IMA_SRC_GENERATED)) {
if (BKE_image_has_packedfile(ima) || image_should_pack_during_save_all(ima)) {
BKE_image_memorypack(ima);
}
else if (is_format_writable) {
@ -3040,9 +3048,8 @@ static bool image_pack_test(bContext *C, wmOperator *op)
return false;
}
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
BKE_report(
op->reports, RPT_ERROR, "Packing movies, image sequences or tiled images not supported");
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
return false;
}
@ -3110,9 +3117,8 @@ static int image_unpack_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
BKE_report(
op->reports, RPT_ERROR, "Unpacking movies, image sequences or tiled images not supported");
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
return OPERATOR_CANCELLED;
}
@ -3144,9 +3150,8 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
return OPERATOR_CANCELLED;
}
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
BKE_report(
op->reports, RPT_ERROR, "Unpacking movies, image sequences or tiled images not supported");
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
return OPERATOR_CANCELLED;
}

View File

@ -172,7 +172,6 @@ int GPU_max_compute_shader_storage_blocks()
return GCaps.max_compute_shader_storage_blocks;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -333,6 +333,8 @@ static char attr_prefix_get(CustomDataType type)
switch (type) {
case CD_TANGENT:
return 't';
case CD_MCOL:
return 'c';
case CD_AUTO_FROM_NAME:
return 'a';
case CD_HAIRLENGTH:

View File

@ -64,6 +64,11 @@ typedef struct ImageView {
typedef struct ImagePackedFile {
struct ImagePackedFile *next, *prev;
struct PackedFile *packedfile;
/* Which view and tile this ImagePackedFile represents. Normal images will use 0 and 1001
* respectively when creating their ImagePackedFile. Must be provided for each packed image. */
int view;
int tile_number;
/** 1024 = FILE_MAX. */
char filepath[1024];
} ImagePackedFile;

View File

@ -454,7 +454,7 @@ int rna_AttributeGroup_color_length(PointerRNA *ptr)
return BKE_id_attributes_length(ptr->owner_id, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL, true);
}
ATTR_NO_OPT int rna_AttributeGroup_length(PointerRNA *ptr)
int rna_AttributeGroup_length(PointerRNA *ptr)
{
return BKE_id_attributes_length(ptr->owner_id, ATTR_DOMAIN_MASK_ALL, CD_MASK_PROP_ALL, false);
}

View File

@ -737,6 +737,16 @@ static void rna_def_image_packed_files(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "filepath");
RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "view", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "view");
RNA_def_property_ui_text(prop, "View Index", "");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "tile_number", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "tile_number");
RNA_def_property_ui_text(prop, "Tile Number", "");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_api_image_packed_file(srna);
}

View File

@ -161,9 +161,8 @@ static void rna_Image_unpack(Image *image, Main *bmain, ReportList *reports, int
if (!BKE_image_has_packedfile(image)) {
BKE_report(reports, RPT_ERROR, "Image not packed");
}
else if (BKE_image_has_multiple_ibufs(image)) {
BKE_report(
reports, RPT_ERROR, "Unpacking movies, image sequences or tiled images not supported");
else if (ELEM(image->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
BKE_report(reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
return;
}
else {

View File

@ -42,10 +42,20 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
GPUNodeStack *out)
{
NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
/* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR as geometry nodes may
* overwrite data which will also change the CustomDataType. This will also make EEVEE and Cycles
/* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR for named attributes
* as geometry nodes may overwrite data which will also change the CustomDataType.
* This will also make EEVEE and Cycles
* consistent. See T93179. */
GPUNodeLink *vertexColorLink = GPU_attribute(mat, CD_AUTO_FROM_NAME, vertexColor->layer_name);
GPUNodeLink *vertexColorLink;
if (vertexColor->layer_name[0]) {
vertexColorLink = GPU_attribute(mat, CD_AUTO_FROM_NAME, vertexColor->layer_name);
}
else { /* Fall back on active render color attribute. */
vertexColorLink = GPU_attribute(mat, CD_MCOL, vertexColor->layer_name);
}
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
}