Compare commits

...

75 Commits

Author SHA1 Message Date
e704c78d87 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-07-27 21:42:50 +02:00
3c643440a3 Always show active tile if the current image is tiled 2018-07-27 21:42:44 +02:00
ccbfdd05d7 Improve creating and saving tiled images 2018-07-27 21:42:43 +02:00
579bf61a97 Revert last commit, was temporary
This reverts commit 8eee1a312b.
2018-07-27 21:42:09 +02:00
8eee1a312b a 2018-07-26 18:22:19 +02:00
82e2c9ff31 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-07-23 02:50:33 +02:00
215f1c928e Support UDIM textures in workbench engine and texture painting 2018-07-23 02:50:10 +02:00
80afab3d82 Allocate correct length for drawing UDIM grids 2018-07-23 02:50:10 +02:00
6cab58dfc2 Fix GLSL UDIM functions after the merge 2018-07-23 02:49:41 +02:00
2b74af08eb Merge remote-tracking branch 'origin/blender2.8' into udim 2018-07-22 21:19:48 +02:00
395f6bcc60 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-07-15 22:57:56 +02:00
d87a227ce1 Change UDIM operator poll functions to return bool 2018-07-04 15:17:35 +02:00
54f50bd3cc Merge remote-tracking branch 'origin/blender2.8' into udim 2018-07-04 15:17:27 +02:00
962311358b Don't handle first tile twice in image drawing and saving 2018-06-28 02:21:12 +02:00
5b6df588f2 Cleanup whitespace 2018-06-28 02:19:32 +02:00
cd20a1399e Support active tile selection without an active image 2018-06-28 01:22:30 +02:00
19db478bc5 Add tiled grid drawing option when no image is loaded 2018-06-28 01:22:24 +02:00
b33d272e91 Merge remote-tracking branch 'origin/blender2.8' into temp-udim-images 2018-06-28 00:49:33 +02:00
f24647bd4d Only allow switching an image to Tiled if its filename contains 1001 2018-06-20 02:26:59 +02:00
f354744713 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-06-20 02:25:48 +02:00
fbb0815fd7 Remove unused code from rna_image.c 2018-06-16 13:53:01 +02:00
b0c7dda4a7 Try to detect unused tiles when rendering with Cycles and skip loading them 2018-06-16 13:39:56 +02:00
d5e849339b Merge remote-tracking branch 'origin/blender2.8' into udim 2018-06-15 23:30:41 +02:00
7d05a1035a Support 3D texture painting across tiles 2018-06-15 23:30:11 +02:00
7c34a379fa Remove leftover debug printf 2018-06-15 21:28:14 +02:00
ea9d1a06aa Don't add image tiles for which no file was found 2018-06-15 21:23:07 +02:00
acfbd76f85 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-06-15 20:45:36 +02:00
c6e8dd331b Rename Generate Tile operator to Fill Tile 2018-06-15 20:45:21 +02:00
b3da4f8fd5 Added highlighted border around currently selected tile 2018-06-15 20:45:21 +02:00
82e2ea8fce Added Alt+LMouse key binding to select current tile 2018-06-15 20:45:21 +02:00
b6a3231ba5 Fix filling in secondary tiles in 2D paint mode 2018-06-15 20:01:11 +02:00
9b745515e4 Fix minimum for tile number argument of ImageTiles.get 2018-06-15 19:32:13 +02:00
a725059074 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-06-15 18:43:37 +02:00
59428ec169 Fix memory leaks in 2D painter 2018-06-15 18:23:24 +02:00
28504a99c2 Fix anisotropic brush scaling for tiled images 2018-06-15 18:23:05 +02:00
120300708f Only draw tiles that exist in the image 2018-06-15 18:11:26 +02:00
ab629a95f0 Limit active tile to positive numbers 2018-06-15 17:55:49 +02:00
c383935a72 UDIM Refactor: Store tiles in a linked list, access by position instead of index 2018-06-15 17:55:49 +02:00
852969826f Merge branch 'blender2.8' into udim 2018-06-15 14:09:03 +02:00
67097adad6 Use proper BKE function for mapping tile positions in the image editor operators 2018-06-15 13:41:45 +02:00
4b69034172 Allow to override the size of newly generated tiles 2018-06-15 13:41:45 +02:00
8b75f609e4 Support 2D painting across tiles in 2018-06-15 13:41:45 +02:00
d8ed157bd2 Merge branch 'blender2.8' into temp-udim-images 2018-06-14 18:51:02 +02:00
27cd60017f Cleanup: minor style and naming changes. 2018-06-14 15:45:45 +02:00
e93ce4f5e0 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-06-13 18:46:05 +02:00
4e27014103 Support anisotropic brush scaling to compensate for different tile aspect ratios 2018-06-13 18:43:21 +02:00
8325f7f0b4 Scale the brush radius to compensate for resolution difference in tiles 2018-06-13 17:07:53 +02:00
37c89eb3da Support live redrawing for secondary tiles during texture painting 2018-06-13 16:38:18 +02:00
336fbdf5fc Add support for different tile sizes to inage editor drawing 2018-06-13 16:28:52 +02:00
d9cd8df242 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-06-13 16:05:32 +02:00
bc05599bd0 Start supporting tiled images in 3D texture painting 2018-06-13 16:04:56 +02:00
79c58d27e9 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-06-12 21:46:32 +02:00
b91706368f Add operator for generating images in specific tiles 2018-06-12 21:44:28 +02:00
f388b31ad1 Add UI option for specifying the tile name
This UI is just for development purposes, it's not exactly great.
2018-06-12 21:43:23 +02:00
4875f41ea6 Implement custom UDIM tile labeling
Not exposed in UI/RNA yet.
2018-06-12 19:46:39 +02:00
d3d0c8febc Add operators for adding and removing tiles 2018-06-12 18:56:04 +02:00
7118317e9f Remove cache entries and free GPUTextures when changing tiled image to non-tiled 2018-06-12 18:56:04 +02:00
b7cc2dbdce Fix incorrect amount of vertices in UDIM grid drawing 2018-06-12 18:56:04 +02:00
e1e975aeb8 Fix UDIM grid being drawn too wide 2018-06-12 18:56:04 +02:00
3451769219 Move GPUTexture to per-tile struct 2018-06-12 18:56:04 +02:00
24318440eb Add per-tile struct to Image to track the status of every tile 2018-06-12 18:56:04 +02:00
799303dd87 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-06-12 15:13:24 +02:00
005d1d0933 Support saving tiled images 2018-06-12 00:07:09 +02:00
9fc9376004 Cleanup 2D tiled painting code by adding a temporary ImageUser 2018-06-12 00:06:35 +02:00
cc4defac04 Support 2D painting onto tiled images
Currently, a limitation is that strokes can not cross between tiles, only the tile in which the stroke started will be affected.
2018-06-11 23:07:34 +02:00
1d40503210 Change out-of-bounds color for tiled images in GLSL to match missing images 2018-06-11 22:21:14 +02:00
d6f9e6bf0c Merge remote-tracking branch 'origin/blender2.8' into udim 2018-06-11 22:10:47 +02:00
94d0cbf127 Support tiled textures in the viewport and in Eevee 2018-06-11 22:07:52 +02:00
e2e80ec649 Merge remote-tracking branch 'origin/blender2.8' into udim 2018-06-11 14:40:39 +02:00
62550b490a Add UDIM support to the Cycles Image node
SVM only for now, OSL will come later.
2018-06-11 14:39:33 +02:00
25a4363ed4 Rename IMA_SRC_UDIM to IMA_SRC_TILED 2018-06-11 11:16:51 +02:00
5c62468e4b Support UDIMs in Image Space operators 2018-06-11 09:40:50 +02:00
89c0dc4ebd Implement basic UDIM grid drawing 2018-06-10 23:14:07 +02:00
a5732a1de4 Automatically find and load all UDIM tiles even if only the 1001 tile is selected 2018-06-10 22:43:30 +02:00
9220f3b64f Add first parts of UDIM support in the core image code
Internally, UDIMs are handled very similar to sequences - they consist of a list
of files (containing a sequential number in their name) that all belong to one
Image datablock. This means that existing code like the IBuf cache can be reused.

The current drawing and opening code are just a minimal implementation to test
the core code, they'll be improved of course.
2018-06-10 21:17:04 +02:00
76 changed files with 2697 additions and 945 deletions

View File

@@ -348,6 +348,7 @@ static void create_mesh_volume_attribute(BL::Object& b_ob,
Attribute::standard_name(std),
b_ob.ptr.data,
animated,
0,
frame,
INTERPOLATION_LINEAR,
EXTENSION_CLIP,

View File

@@ -142,8 +142,8 @@ void BlenderSession::create_session()
/* setup callbacks for builtin image support */
scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3);
scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4, _5);
scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4, _5);
scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4, _5, _6);
scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4, _5, _6);
session->scene = scene;
@@ -1119,6 +1119,7 @@ void BlenderSession::builtin_image_info(const string &builtin_name,
bool BlenderSession::builtin_image_pixels(const string &builtin_name,
void *builtin_data,
int tile,
unsigned char *pixels,
const size_t pixels_size,
const bool free_cache)
@@ -1137,7 +1138,7 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name,
const int height = b_image.size()[1];
const int channels = b_image.channels();
unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame);
unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile);
const size_t num_pixels = ((size_t)width) * height;
if(image_pixels && num_pixels * channels == pixels_size) {
@@ -1182,6 +1183,7 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name,
bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
void *builtin_data,
int tile,
float *pixels,
const size_t pixels_size,
const bool free_cache)
@@ -1204,7 +1206,7 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
const int channels = b_image.channels();
float *image_pixels;
image_pixels = image_get_float_pixels_for_frame(b_image, frame);
image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile);
const size_t num_pixels = ((size_t)width) * height;
if(image_pixels && num_pixels * channels == pixels_size) {

View File

@@ -160,11 +160,13 @@ protected:
ImageMetaData& metadata);
bool builtin_image_pixels(const string &builtin_name,
void *builtin_data,
int tile,
unsigned char *pixels,
const size_t pixels_size,
const bool free_cache);
bool builtin_image_float_pixels(const string &builtin_name,
void *builtin_data,
int tile,
float *pixels,
const size_t pixels_size,
const bool free_cache);

View File

@@ -670,6 +670,12 @@ static ShaderNode *add_node(Scene *scene,
image->animated = b_image_node.image_user().use_auto_refresh();
image->use_alpha = b_image.use_alpha();
image->tiles.clear();
BL::Image::tiles_iterator b_iter;
for(b_image.tiles.begin(b_iter); b_iter != b_image.tiles.end(); ++b_iter) {
image->tiles.push_back(b_iter->tile_number());
}
/* TODO: restore */
/* TODO(sergey): Does not work properly when we change builtin type. */
#if 0
@@ -884,6 +890,7 @@ static ShaderNode *add_node(Scene *scene,
scene->image_manager->tag_reload_image(
point_density->filename.string(),
point_density->builtin_data,
0,
point_density->interpolation,
EXTENSION_CLIP,
true);
@@ -1245,7 +1252,7 @@ void BlenderSync::sync_materials(BL::Depsgraph& b_depsgraph, bool update_all)
/* test if we need to sync */
if(shader_map.sync(&shader, b_mat) || shader->need_sync_object || update_all) {
ShaderGraph *graph = new ShaderGraph();
ShaderGraph *graph = new ShaderGraph(shader);
shader->name = b_mat.name().c_str();
shader->pass_id = b_mat.pass_index();
@@ -1320,7 +1327,7 @@ void BlenderSync::sync_world(BL::Depsgraph& b_depsgraph, bool update_all)
if(world_recalc || update_all || b_world.ptr.data != world_map) {
Shader *shader = scene->default_background;
ShaderGraph *graph = new ShaderGraph();
ShaderGraph *graph = new ShaderGraph(shader);
/* create nodes */
if(b_world && b_world.use_nodes() && b_world.node_tree()) {
@@ -1418,7 +1425,7 @@ void BlenderSync::sync_lights(BL::Depsgraph& b_depsgraph, bool update_all)
/* test if we need to sync */
if(shader_map.sync(&shader, b_light) || update_all) {
ShaderGraph *graph = new ShaderGraph();
ShaderGraph *graph = new ShaderGraph(shader);
/* create nodes */
if(b_light.use_nodes() && b_light.node_tree()) {

View File

@@ -620,6 +620,8 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene,
params.bvh_layout = DebugFlags().cpu.bvh_layout;
params.background = background;
return params;
}

View File

@@ -34,8 +34,8 @@ extern "C" {
size_t BLI_timecode_string_from_time_simple(char *str, size_t maxlen, double time_seconds);
void BKE_image_user_frame_calc(void *iuser, int cfra, int fieldnr);
void BKE_image_user_file_path(void *iuser, void *ima, char *path);
unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame);
float *BKE_image_get_float_pixels_for_frame(void *image, int frame);
unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame, int tile);
float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
}
CCL_NAMESPACE_BEGIN
@@ -220,8 +220,15 @@ static inline string image_user_file_path(BL::ImageUser& iuser,
int cfra)
{
char filepath[1024];
iuser.tile(0);
BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath);
if(ima.source() == BL::Image::source_TILED) {
char *udim_id = strstr(filepath, "1001");
if(udim_id) {
memcpy(udim_id, "%04d", 4);
}
}
return string(filepath);
}
@@ -232,15 +239,15 @@ static inline int image_user_frame_number(BL::ImageUser& iuser, int cfra)
}
static inline unsigned char *image_get_pixels_for_frame(BL::Image& image,
int frame)
int frame, int tile)
{
return BKE_image_get_pixels_for_frame(image.ptr.data, frame);
return BKE_image_get_pixels_for_frame(image.ptr.data, frame, tile);
}
static inline float *image_get_float_pixels_for_frame(BL::Image& image,
int frame)
int frame, int tile)
{
return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame);
return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame, tile);
}
/* Utilities */

View File

@@ -277,7 +277,7 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a
# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */
# ifdef __TEXTURES__
case NODE_TEX_IMAGE:
svm_node_tex_image(kg, sd, stack, node);
svm_node_tex_image(kg, sd, stack, node, &offset);
break;
case NODE_TEX_IMAGE_BOX:
svm_node_tex_image_box(kg, sd, stack, node);

View File

@@ -18,6 +18,9 @@ CCL_NAMESPACE_BEGIN
ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint use_alpha)
{
if(id == -1) {
return make_float4(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
}
float4 r = kernel_tex_image_interp(kg, id, x, y);
const float alpha = r.w;
@@ -46,9 +49,8 @@ ccl_device_inline float3 texco_remap_square(float3 co)
return (co - make_float3(0.5f, 0.5f, 0.5f)) * 2.0f;
}
ccl_device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
ccl_device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
{
uint id = node.y;
uint co_offset, out_offset, alpha_offset, srgb;
decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb);
@@ -67,6 +69,38 @@ ccl_device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *sta
else {
tex_co = make_float2(co.x, co.y);
}
int id = -1;
if(node.y > 0) {
uint num_nodes = node.y;
int next_offset = (*offset) + num_nodes;
if(tex_co.x >= 0.0f && tex_co.y < 10.0f && tex_co.y >= 0.0f) {
int tx = (int) tex_co.x;
int ty = (int) tex_co.y;
int tile = ty*10 + tx;
for(int i = 0; i < num_nodes; i++) {
uint4 node = read_node(kg, offset);
if(node.x == tile) {
id = node.y;
break;
}
if(node.z == tile) {
id = node.w;
break;
}
}
if(id != -1) {
tex_co.x -= tx;
tex_co.y -= ty;
}
}
*offset = next_offset;
}
else {
id = read_node(kg, offset).y;
}
float4 f = svm_image_texture(kg, id, tex_co.x, tex_co.y, srgb, use_alpha);
if(stack_valid(out_offset))

View File

@@ -193,7 +193,8 @@ bool ShaderNode::equals(const ShaderNode& other)
/* Graph */
ShaderGraph::ShaderGraph()
ShaderGraph::ShaderGraph(Shader *shader)
: shader(shader)
{
finalized = false;
simplified = false;
@@ -557,7 +558,7 @@ void ShaderGraph::constant_fold(Scene *scene)
void ShaderGraph::simplify_settings(Scene *scene)
{
foreach(ShaderNode *node, nodes) {
node->simplify_settings(scene);
node->simplify_settings(scene, shader);
}
}

View File

@@ -147,7 +147,7 @@ public:
/* Simplify settings used by artists to the ones which are simpler to
* evaluate in the kernel but keep the final result unchanged.
*/
virtual void simplify_settings(Scene * /*scene*/) {};
virtual void simplify_settings(Scene * /*scene*/, Shader * /*shader*/) {};
virtual bool has_surface_emission() { return false; }
virtual bool has_surface_transparent() { return false; }
@@ -246,8 +246,9 @@ public:
bool finalized;
bool simplified;
string displacement_hash;
Shader *shader;
ShaderGraph();
ShaderGraph(Shader *shader);
~ShaderGraph();
ShaderNode *add(ShaderNode *node);

View File

@@ -278,12 +278,14 @@ bool ImageManager::get_image_metadata(const string& filename,
static bool image_equals(ImageManager::Image *image,
const string& filename,
void *builtin_data,
int tile,
InterpolationType interpolation,
ExtensionType extension,
bool use_alpha)
{
return image->filename == filename &&
image->builtin_data == builtin_data &&
image->tile == tile &&
image->interpolation == interpolation &&
image->extension == extension &&
image->use_alpha == use_alpha;
@@ -292,6 +294,7 @@ static bool image_equals(ImageManager::Image *image,
int ImageManager::add_image(const string& filename,
void *builtin_data,
bool animated,
int tile,
float frame,
InterpolationType interpolation,
ExtensionType extension,
@@ -322,6 +325,7 @@ int ImageManager::add_image(const string& filename,
if(img && image_equals(img,
filename,
builtin_data,
tile,
interpolation,
extension,
use_alpha))
@@ -370,6 +374,7 @@ int ImageManager::add_image(const string& filename,
img->metadata = metadata;
img->need_load = true;
img->animated = animated;
img->tile = tile;
img->frame = frame;
img->interpolation = interpolation;
img->extension = extension;
@@ -406,6 +411,7 @@ void ImageManager::remove_image(int flat_slot)
void ImageManager::remove_image(const string& filename,
void *builtin_data,
int tile,
InterpolationType interpolation,
ExtensionType extension,
bool use_alpha)
@@ -417,6 +423,7 @@ void ImageManager::remove_image(const string& filename,
if(images[type][slot] && image_equals(images[type][slot],
filename,
builtin_data,
tile,
interpolation,
extension,
use_alpha))
@@ -434,6 +441,7 @@ void ImageManager::remove_image(const string& filename,
*/
void ImageManager::tag_reload_image(const string& filename,
void *builtin_data,
int tile,
InterpolationType interpolation,
ExtensionType extension,
bool use_alpha)
@@ -443,6 +451,7 @@ void ImageManager::tag_reload_image(const string& filename,
if(images[type][slot] && image_equals(images[type][slot],
filename,
builtin_data,
tile,
interpolation,
extension,
use_alpha))
@@ -581,6 +590,7 @@ bool ImageManager::file_load_image(Image *img,
if(FileFormat == TypeDesc::FLOAT) {
builtin_image_float_pixels_cb(img->filename,
img->builtin_data,
img->tile,
(float*)&pixels[0],
num_pixels * components,
img->metadata.builtin_free_cache);
@@ -588,6 +598,7 @@ bool ImageManager::file_load_image(Image *img,
else if(FileFormat == TypeDesc::UINT8) {
builtin_image_pixels_cb(img->filename,
img->builtin_data,
img->tile,
(uchar*)&pixels[0],
num_pixels * components,
img->metadata.builtin_free_cache);

View File

@@ -53,6 +53,7 @@ public:
int add_image(const string& filename,
void *builtin_data,
bool animated,
int tile,
float frame,
InterpolationType interpolation,
ExtensionType extension,
@@ -61,11 +62,13 @@ public:
void remove_image(int flat_slot);
void remove_image(const string& filename,
void *builtin_data,
int tile,
InterpolationType interpolation,
ExtensionType extension,
bool use_alpha);
void tag_reload_image(const string& filename,
void *builtin_data,
int tile,
InterpolationType interpolation,
ExtensionType extension,
bool use_alpha);
@@ -107,11 +110,13 @@ public:
ImageMetaData& metadata)> builtin_image_info_cb;
function<bool(const string &filename,
void *data,
int tile,
unsigned char *pixels,
const size_t pixels_size,
const bool free_cache)> builtin_image_pixels_cb;
function<bool(const string &filename,
void *data,
int tile,
float *pixels,
const size_t pixels_size,
const bool free_cache)> builtin_image_float_pixels_cb;
@@ -125,6 +130,7 @@ public:
bool need_load;
bool animated;
float frame;
int tile;
InterpolationType interpolation;
ExtensionType extension;

View File

@@ -555,9 +555,13 @@ void LightManager::device_update_background(Device *device,
if(node->type == EnvironmentTextureNode::node_type) {
EnvironmentTextureNode *env = (EnvironmentTextureNode*) node;
ImageMetaData metadata;
if(env->image_manager && env->image_manager->get_image_metadata(env->slot, metadata)) {
res.x = max(res.x, metadata.width);
res.y = max(res.y, metadata.height);
if(env->image_manager) {
foreach(int slot, env->slots) {
if(env->image_manager->get_image_metadata(slot, metadata)) {
res.x = max(res.x, metadata.width);
res.y = max(res.y, metadata.height);
}
}
}
}
}

View File

@@ -662,6 +662,61 @@ void Mesh::add_subd_face(int* corners, int num_corners, int shader_, bool smooth
subd_faces.push_back_reserved(face);
}
static void get_uv_tiles_from_attribute(Attribute *attr, int num, vector<bool> &tiles)
{
if(!attr) {
return;
}
const float3 *uv = attr->data_float3();
int size = tiles.size();
for(int i = 0; i < num; i++, uv++) {
float u = uv->x, v = uv->y;
if(u < 0.0f || v < 0.0f || u > 10.0f) continue;
int x = (int) u, y = (int) v;
/* Be conservative in corners - precisely touching the right-upper corner of a tile
* should not load its right-upper neighbor as well. */
if(x && (u == x)) x--;
if(y && (v == y)) y--;
int id = y*10 + x;
if(id >= size) {
tiles.resize(id+1);
size = id;
}
tiles[id] = true;
}
}
void Mesh::get_uv_tiles(ustring map, vector<bool> &tiles)
{
if(map.empty()) {
get_uv_tiles_from_attribute(attributes.find(ATTR_STD_UV),
num_triangles()*3,
tiles);
get_uv_tiles_from_attribute(subd_attributes.find(ATTR_STD_UV),
subd_face_corners.size() + num_ngons,
tiles);
get_uv_tiles_from_attribute(curve_attributes.find(ATTR_STD_UV),
num_curves(),
tiles);
}
else {
get_uv_tiles_from_attribute(attributes.find(map),
num_triangles()*3,
tiles);
get_uv_tiles_from_attribute(subd_attributes.find(map),
subd_face_corners.size() + num_ngons,
tiles);
get_uv_tiles_from_attribute(curve_attributes.find(map),
num_curves(),
tiles);
}
}
void Mesh::compute_bounds()
{
BoundBox bnds = BoundBox::empty;
@@ -1996,8 +2051,7 @@ void MeshManager::device_update_displacement_images(Device *device,
}
ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode*>(node);
int slot = image_node->slot;
if(slot != -1) {
foreach(int slot, image_node->slots) {
bump_images.insert(slot);
}
}

View File

@@ -280,6 +280,8 @@ public:
void add_vertex_normals();
void add_undisplaced();
void get_uv_tiles(ustring map, vector<bool> &tiles);
void pack_shaders(Scene *scene, uint *shader);
void pack_normals(float4 *vnormal);
void pack_verts(const vector<uint>& tri_prim_index,

View File

@@ -18,6 +18,7 @@
#include "render/image.h"
#include "render/integrator.h"
#include "render/light.h"
#include "render/mesh.h"
#include "render/nodes.h"
#include "render/scene.h"
#include "render/svm.h"
@@ -249,21 +250,19 @@ ImageTextureNode::ImageTextureNode()
: ImageSlotTextureNode(node_type)
{
image_manager = NULL;
slot = -1;
is_float = -1;
is_float = false;
is_linear = false;
builtin_data = NULL;
animated = false;
tiles.push_back(0);
}
ImageTextureNode::~ImageTextureNode()
{
if(image_manager) {
image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
extension,
use_alpha);
foreach(int slot, slots) {
image_manager->remove_image(slot);
}
}
}
@@ -271,12 +270,55 @@ ShaderNode *ImageTextureNode::clone() const
{
ImageTextureNode *node = new ImageTextureNode(*this);
node->image_manager = NULL;
node->slot = -1;
node->is_float = -1;
node->slots.clear();
node->is_float = false;
node->is_linear = false;
return node;
}
void ImageTextureNode::simplify_settings(Scene *scene, Shader *shader)
{
if(!scene->params.background) {
/* During interactive renders, all tiles are loaded.
* While we could support updating this when UVs change, that could lead
* to annoying interruptions when loading images while editing UVs. */
return;
}
ShaderInput *vector_in = input("Vector");
ustring attribute;
if(vector_in->link) {
ShaderNode *node = vector_in->link->parent;
if(node->type == UVMapNode::node_type) {
UVMapNode *uvmap = (UVMapNode*) node;
attribute = uvmap->attribute;
}
else if(node->type == TextureCoordinateNode::node_type) {
if(vector_in->link != node->output("UV")) {
return;
}
}
else {
return;
}
}
ccl::vector<bool> used_tiles;
foreach(Mesh *mesh, scene->meshes) {
if(std::find(mesh->used_shaders.begin(), mesh->used_shaders.end(), shader) != mesh->used_shaders.end()) {
mesh->get_uv_tiles(attribute, used_tiles);
}
}
ccl::vector<int> new_tiles;
foreach(int tile, tiles) {
if (tile < used_tiles.size() && used_tiles[tile]) {
new_tiles.push_back(tile);
}
}
tiles.swap(new_tiles);
}
void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
#ifdef WITH_PTEX
@@ -299,27 +341,52 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
ShaderOutput *alpha_out = output("Alpha");
image_manager = compiler.image_manager;
if(is_float == -1) {
ImageMetaData metadata;
slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
interpolation,
extension,
use_alpha,
metadata);
is_float = metadata.is_float;
is_linear = metadata.is_linear;
if(slots.size() < tiles.size()) {
slots.clear();
foreach(int tile, tiles) {
string tile_name;
if(tiles.size() == 1) {
tile_name = filename.string();
}
else {
tile_name = string_printf(filename.c_str(), 1001 + tile);
}
printf("Loading %s\n", tile_name.c_str());
ImageMetaData metadata;
slots.push_back(image_manager->add_image(tile_name,
builtin_data,
animated,
tile,
0,
interpolation,
extension,
use_alpha,
metadata));
if(tile == 0) {
is_float = metadata.is_float;
is_linear = metadata.is_linear;
}
}
}
if(slot != -1) {
bool has_image = false;
foreach(int slot, slots) {
if(slot != -1) {
has_image = true;
break;
}
}
if(has_image) {
int num_nodes = divide_up(slots.size(), 2);
int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
/* TODO(lukas): Avoid extra node for common case of only one tile. */
if(projection != NODE_IMAGE_PROJ_BOX) {
compiler.add_node(NODE_TEX_IMAGE,
slot,
num_nodes,
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign_if_linked(color_out),
@@ -329,7 +396,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
}
else {
compiler.add_node(NODE_TEX_IMAGE_BOX,
slot,
num_nodes,
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign_if_linked(color_out),
@@ -338,6 +405,21 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
__float_as_int(projection_blend));
}
for(int i = 0; i < num_nodes; i++) {
int4 node;
node.x = tiles[2*i];
node.y = slots[2*i];
if(2*i+1 < slots.size()) {
node.z = tiles[2*i+1];
node.w = slots[2*i+1];
}
else {
node.z = -1;
node.w = -1;
}
compiler.add_node(node.x, node.y, node.z, node.w);
}
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
else {
@@ -360,26 +442,28 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
tex_mapping.compile(compiler);
image_manager = compiler.image_manager;
if(is_float == -1) {
if(slots.size() == 0) {
ImageMetaData metadata;
if(builtin_data == NULL) {
image_manager->get_image_metadata(filename.string(), NULL, metadata);
slots.push_back(-1);
}
else {
slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
interpolation,
extension,
use_alpha,
metadata);
slots.push_back(image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
0,
interpolation,
extension,
use_alpha,
metadata));
}
is_float = metadata.is_float;
is_linear = metadata.is_linear;
}
if(slot == -1) {
if(slots[0] == -1) {
compiler.parameter(this, "filename");
}
else {
@@ -389,7 +473,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
* "@i<slot_number>" and check whether file name matches this
* mask in the OSLRenderServices::texture().
*/
compiler.parameter("filename", string_printf("@i%d", slot).c_str());
compiler.parameter("filename", string_printf("@i%d", slots[0]).c_str());
}
if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
compiler.parameter("color_space", "linear");
@@ -446,8 +530,7 @@ EnvironmentTextureNode::EnvironmentTextureNode()
: ImageSlotTextureNode(node_type)
{
image_manager = NULL;
slot = -1;
is_float = -1;
is_float = false;
is_linear = false;
builtin_data = NULL;
animated = false;
@@ -455,12 +538,8 @@ EnvironmentTextureNode::EnvironmentTextureNode()
EnvironmentTextureNode::~EnvironmentTextureNode()
{
if(image_manager) {
image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
EXTENSION_REPEAT,
use_alpha);
if(image_manager && slots.size()) {
image_manager->remove_image(slots[0]);
}
}
@@ -468,8 +547,8 @@ ShaderNode *EnvironmentTextureNode::clone() const
{
EnvironmentTextureNode *node = new EnvironmentTextureNode(*this);
node->image_manager = NULL;
node->slot = -1;
node->is_float = -1;
node->slots.clear();
node->is_float = false;
node->is_linear = false;
return node;
}
@@ -494,26 +573,27 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
ShaderOutput *alpha_out = output("Alpha");
image_manager = compiler.image_manager;
if(slot == -1) {
if(slots.size() == 0) {
ImageMetaData metadata;
slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
interpolation,
EXTENSION_REPEAT,
use_alpha,
metadata);
slots.push_back(image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
0,
interpolation,
EXTENSION_REPEAT,
use_alpha,
metadata));
is_float = metadata.is_float;
is_linear = metadata.is_linear;
}
if(slot != -1) {
if(slots[0] != -1) {
int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1;
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_ENVIRONMENT,
slot,
slots[0],
compiler.encode_uchar4(
vector_offset,
compiler.stack_assign_if_linked(color_out),
@@ -546,30 +626,32 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
* of builtin images.
*/
image_manager = compiler.image_manager;
if(is_float == -1) {
if(slots.size() == 0) {
slots.resize(1);
ImageMetaData metadata;
if(builtin_data == NULL) {
image_manager->get_image_metadata(filename.string(), NULL, metadata);
}
else {
slot = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
interpolation,
EXTENSION_REPEAT,
use_alpha,
metadata);
slots[0] = image_manager->add_image(filename.string(),
builtin_data,
animated,
0,
0,
interpolation,
EXTENSION_REPEAT,
use_alpha,
metadata);
}
is_float = metadata.is_float;
is_linear = metadata.is_linear;
}
if(slot == -1) {
if(slots[0] == -1) {
compiler.parameter(this, "filename");
}
else {
compiler.parameter("filename", string_printf("@i%d", slot).c_str());
compiler.parameter("filename", string_printf("@i%d", slots[0]).c_str());
}
compiler.parameter(this, "projection");
if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
@@ -1495,11 +1577,7 @@ PointDensityTextureNode::PointDensityTextureNode()
PointDensityTextureNode::~PointDensityTextureNode()
{
if(image_manager) {
image_manager->remove_image(filename.string(),
builtin_data,
interpolation,
EXTENSION_CLIP,
true);
image_manager->remove_image(slot);
}
}
@@ -1525,7 +1603,7 @@ void PointDensityTextureNode::add_image()
if(slot == -1) {
ImageMetaData metadata;
slot = image_manager->add_image(filename.string(), builtin_data,
false, 0,
false, 0, 0,
interpolation,
EXTENSION_CLIP,
true,
@@ -2055,7 +2133,7 @@ GlossyBsdfNode::GlossyBsdfNode()
distribution_orig = NBUILTIN_CLOSURES;
}
void GlossyBsdfNode::simplify_settings(Scene *scene)
void GlossyBsdfNode::simplify_settings(Scene *scene, Shader * /*shader*/)
{
if(distribution_orig == NBUILTIN_CLOSURES) {
roughness_orig = roughness;
@@ -2150,7 +2228,7 @@ GlassBsdfNode::GlassBsdfNode()
distribution_orig = NBUILTIN_CLOSURES;
}
void GlassBsdfNode::simplify_settings(Scene *scene)
void GlassBsdfNode::simplify_settings(Scene *scene, Shader * /*shader*/)
{
if(distribution_orig == NBUILTIN_CLOSURES) {
roughness_orig = roughness;
@@ -2245,7 +2323,7 @@ RefractionBsdfNode::RefractionBsdfNode()
distribution_orig = NBUILTIN_CLOSURES;
}
void RefractionBsdfNode::simplify_settings(Scene *scene)
void RefractionBsdfNode::simplify_settings(Scene *scene, Shader * /*shader*/)
{
if(distribution_orig == NBUILTIN_CLOSURES) {
roughness_orig = roughness;

View File

@@ -74,7 +74,7 @@ public:
explicit ImageSlotTextureNode(const NodeType *node_type) : TextureNode(node_type) {
special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
}
int slot;
vector<int> slots;
};
class ImageTextureNode : public ImageSlotTextureNode {
@@ -84,9 +84,10 @@ public:
ShaderNode *clone() const;
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
void simplify_settings(Scene *scene, Shader *shader);
ImageManager *image_manager;
int is_float;
bool is_float;
bool is_linear;
bool use_alpha;
ustring filename;
@@ -98,6 +99,7 @@ public:
float projection_blend;
bool animated;
float3 vector;
ccl::vector<int> tiles;
virtual bool equals(const ShaderNode& other)
{
@@ -118,7 +120,7 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
ImageManager *image_manager;
int is_float;
bool is_float;
bool is_linear;
bool use_alpha;
ustring filename;
@@ -450,7 +452,7 @@ class GlossyBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(GlossyBsdfNode)
void simplify_settings(Scene *scene);
void simplify_settings(Scene *scene, Shader *shader);
bool has_integrator_dependency();
ClosureType get_closure_type() { return distribution; }
@@ -462,7 +464,7 @@ class GlassBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(GlassBsdfNode)
void simplify_settings(Scene *scene);
void simplify_settings(Scene *scene, Shader *shader);
bool has_integrator_dependency();
ClosureType get_closure_type() { return distribution; }
@@ -474,7 +476,7 @@ class RefractionBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(RefractionBsdfNode)
void simplify_settings(Scene *scene);
void simplify_settings(Scene *scene, Shader *shader);
bool has_integrator_dependency();
ClosureType get_closure_type() { return distribution; }

View File

@@ -170,6 +170,8 @@ public:
bool persistent_data;
int texture_limit;
bool background;
SceneParams()
{
shadingsystem = SHADINGSYSTEM_SVM;

View File

@@ -579,7 +579,8 @@ void ShaderManager::add_default(Scene *scene)
{
/* default surface */
{
ShaderGraph *graph = new ShaderGraph();
Shader *shader = new Shader();
ShaderGraph *graph = new ShaderGraph(shader);
DiffuseBsdfNode *diffuse = new DiffuseBsdfNode();
diffuse->color = make_float3(0.8f, 0.8f, 0.8f);
@@ -587,7 +588,6 @@ void ShaderManager::add_default(Scene *scene)
graph->connect(diffuse->output("BSDF"), graph->output()->input("Surface"));
Shader *shader = new Shader();
shader->name = "default_surface";
shader->graph = graph;
scene->shaders.push_back(shader);
@@ -596,7 +596,8 @@ void ShaderManager::add_default(Scene *scene)
/* default light */
{
ShaderGraph *graph = new ShaderGraph();
Shader *shader = new Shader();
ShaderGraph *graph = new ShaderGraph(shader);
EmissionNode *emission = new EmissionNode();
emission->color = make_float3(0.8f, 0.8f, 0.8f);
@@ -605,7 +606,6 @@ void ShaderManager::add_default(Scene *scene)
graph->connect(emission->output("Emission"), graph->output()->input("Surface"));
Shader *shader = new Shader();
shader->name = "default_light";
shader->graph = graph;
scene->shaders.push_back(shader);
@@ -614,9 +614,9 @@ void ShaderManager::add_default(Scene *scene)
/* default background */
{
ShaderGraph *graph = new ShaderGraph();
Shader *shader = new Shader();
ShaderGraph *graph = new ShaderGraph(shader);
shader->name = "default_background";
shader->graph = graph;
scene->shaders.push_back(shader);
@@ -625,9 +625,9 @@ void ShaderManager::add_default(Scene *scene)
/* default empty */
{
ShaderGraph *graph = new ShaderGraph();
Shader *shader = new Shader();
ShaderGraph *graph = new ShaderGraph(shader);
shader->name = "default_empty";
shader->graph = graph;
scene->shaders.push_back(shader);

View File

@@ -736,6 +736,10 @@ class IMAGE_PT_view_properties(Panel):
row.active = uvedit.show_other_objects
row.prop(uvedit, "other_uv_filter", text="Filter")
if ima is None:
row = layout.row()
row.prop(uvedit, "tile_grid_shape", text="Grid Shape")
class IMAGE_UL_render_slots(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
@@ -773,6 +777,33 @@ class IMAGE_PT_render_slots(Panel):
col.operator("image.clear_render_slot", icon='X', text="")
class IMAGE_PT_tile_properties(Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
bl_label = "Tiles"
@classmethod
def poll(cls, context):
sima = context.space_data
return (sima and sima.image and sima.image.source == 'TILED')
def draw(self, context):
layout = self.layout
sima = context.space_data
ima = sima.image
row = layout.row(align=True)
row.operator("image.add_tile")
row.operator("image.remove_tile")
tile = ima.tiles.get(sima.current_tile)
if tile:
col = layout.column(align=True)
col.operator("image.fill_tile")
col.prop(tile, "label")
class IMAGE_PT_tools_transform_uvs(Panel, UVToolsPanel):
bl_label = "Transform"
@@ -1407,6 +1438,7 @@ classes = (
IMAGE_UL_render_slots,
IMAGE_PT_render_slots,
IMAGE_PT_view_properties,
IMAGE_PT_tile_properties,
IMAGE_PT_tools_transform_uvs,
IMAGE_PT_tools_align_uvs,
IMAGE_PT_tools_uvs,

View File

@@ -74,6 +74,7 @@ void BLF_size(int fontid, int size, int dpi);
void BLF_color4ubv(int fontid, const unsigned char rgba[4]);
void BLF_color3ubv(int fontid, const unsigned char rgb[3]);
void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha);
void BLF_color4ub(int fontid, unsigned char r, unsigned char g, unsigned char b, unsigned char alpha);
void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b);
void BLF_color4f(int fontid, float r, float g, float b, float a);
void BLF_color4fv(int fontid, const float rgba[4]);

View File

@@ -513,6 +513,18 @@ void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b)
}
}
void BLF_color4ub(int fontid, unsigned char r, unsigned char g, unsigned char b, unsigned char alpha)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->color[0] = r;
font->color[1] = g;
font->color[2] = b;
font->color[3] = alpha;
}
}
void BLF_color4fv(int fontid, const float rgba[4])
{
FontBLF *font = blf_get(fontid);

View File

@@ -45,6 +45,7 @@ struct Scene;
struct Object;
struct ImageFormatData;
struct ImagePool;
struct ImageTile;
struct Main;
struct ReportList;
struct RenderResult;
@@ -134,6 +135,7 @@ struct RenderResult;
#define IMA_SRC_MOVIE 3
#define IMA_SRC_GENERATED 4
#define IMA_SRC_VIEWER 5
#define IMA_SRC_TILED 6
/* ima->type, how to handle/generate it */
#define IMA_TYPE_IMAGE 0
@@ -194,7 +196,7 @@ struct Image *BKE_image_load_exists(struct Main *bmain, const char *filepath);
/* adds image, adds ibuf, generates color or pattern */
struct Image *BKE_image_add_generated(
struct Main *bmain, unsigned int width, unsigned int height, const char *name,
int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d);
int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d, bool tiled);
/* adds image from imbuf, owns imbuf */
struct Image *BKE_image_add_from_imbuf(struct Main *bmain, struct ImBuf *ibuf, const char *name);
@@ -271,6 +273,19 @@ bool BKE_image_has_alpha(struct Image *image);
/* check if texture has gpu texture code */
bool BKE_image_has_opengl_texture(struct Image *ima);
/* get tile index for tiled images */
void BKE_image_get_tile_label(struct Image *ima, struct ImageTile *tile, char *label, int len_label);
struct ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label);
bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile);
bool BKE_image_fill_tile(struct Image *ima, struct ImageTile *tile, int width, int height, const float color[4], int gen_type);
struct ImageTile *BKE_image_get_tile(struct Image *ima, int tile_number);
struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, struct ImageUser *iuser);
int BKE_image_get_tile_from_pos(struct Image *ima, const float uv[2], float new_uv[2], float ofs[2]);
void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *width, int *height);
void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float size[2]);
void BKE_image_get_aspect(struct Image *image, float *aspx, float *aspy);
@@ -281,14 +296,15 @@ void BKE_image_buf_fill_checker(unsigned char *rect, float *rect_float, int heig
void BKE_image_buf_fill_checker_color(unsigned char *rect, float *rect_float, int height, int width);
/* Cycles hookup */
unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame);
float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame);
unsigned char *BKE_image_get_pixels_for_frame(struct Image *image, int frame, int tile);
float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int tile);
/* Guess offset for the first frame in the sequence */
int BKE_image_sequence_guess_offset(struct Image *image);
bool BKE_image_has_anim(struct Image *image);
bool BKE_image_has_packedfile(struct Image *image);
bool BKE_image_is_animated(struct Image *image);
bool BKE_image_has_multiple_ibufs(struct Image *image);
bool BKE_image_is_dirty(struct Image *image);
void BKE_image_file_format_set(struct Image *image, int ftype, const struct ImbFormatOptions *options);
bool BKE_image_has_loaded_ibuf(struct Image *image);

View File

@@ -435,7 +435,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
Image *ima;
ima = (Image *)id;
if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) {
if (flag & BKE_BPATH_TRAVERSE_RELOAD_EDITED) {
if (!BKE_image_has_packedfile(ima) &&

File diff suppressed because it is too large Load Diff

View File

@@ -237,7 +237,7 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot ++;
}
else if (BKE_image_is_animated(ima) && verbose) {
else if (BKE_image_has_multiple_ibufs(ima) && verbose) {
BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported",
ima->id.name + 2);
}

View File

@@ -262,6 +262,8 @@ MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED
MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool equals_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool equals_v2v2_int(const int v1[2], const int v2[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool compare_v2v2(const float a[2], const float b[2], const float limit) ATTR_WARN_UNUSED_RESULT;
MINLINE bool compare_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT;
MINLINE bool compare_v4v4(const float a[4], const float b[4], const float limit) ATTR_WARN_UNUSED_RESULT;

View File

@@ -1042,6 +1042,11 @@ MINLINE bool equals_v4v4(const float v1[4], const float v2[4])
return ((v1[0] == v2[0]) && (v1[1] == v2[1]) && (v1[2] == v2[2]) && (v1[3] == v2[3]));
}
MINLINE bool equals_v2v2_int(const int v1[2], const int v2[2])
{
return ((v1[0] == v2[0]) && (v1[1] == v2[1]));
}
MINLINE bool compare_v2v2(const float v1[2], const float v2[2], const float limit)
{
return (compare_ff(v1[0], v2[0], limit) &&

View File

@@ -1677,21 +1677,24 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
{
Image *ima = oldmain->image.first;
Scene *sce = oldmain->scene.first;
int a;
fd->imamap = oldnewmap_new();
for (; ima; ima = ima->id.next) {
if (ima->cache)
oldnewmap_insert(fd->imamap, ima->cache, ima->cache, 0);
for (a = 0; a < TEXTARGET_COUNT; a++)
if (ima->gputexture[a])
oldnewmap_insert(fd->imamap, ima->gputexture[a], ima->gputexture[a], 0);
if (ima->rr)
oldnewmap_insert(fd->imamap, ima->rr, ima->rr, 0);
LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots)
if (slot->render)
oldnewmap_insert(fd->imamap, slot->render, slot->render, 0);
LISTBASE_FOREACH(ImageTile*, tile, &ima->tiles) {
for (int a = 0; a < TEXTARGET_COUNT; a++) {
if (tile->gputexture[a]) {
oldnewmap_insert(fd->imamap, tile->gputexture[a], tile->gputexture[a], 0);
}
}
}
LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots)
if (slot->render)
oldnewmap_insert(fd->imamap, slot->render, slot->render, 0);
}
for (; sce; sce = sce->id.next) {
if (sce->nodetree && sce->nodetree->previews) {
@@ -1711,10 +1714,9 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
OldNew *entry = fd->imamap->entries;
Image *ima = oldmain->image.first;
Scene *sce = oldmain->scene.first;
int i;
/* used entries were restored, so we put them to zero */
for (i = 0; i < fd->imamap->nentries; i++, entry++) {
for (int i = 0; i < fd->imamap->nentries; i++, entry++) {
if (entry->nr > 0)
entry->newp = NULL;
}
@@ -1723,16 +1725,23 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
ima->cache = newimaadr(fd, ima->cache);
if (ima->cache == NULL) {
ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
for (i = 0; i < TEXTARGET_COUNT; i++) {
ima->gputexture[i] = NULL;
}
ima->rr = NULL;
LISTBASE_FOREACH(ImageTile*, tile, &ima->tiles) {
for (int j = 0; j < TEXTARGET_COUNT; j++) {
tile->gputexture[j] = NULL;
}
}
}
LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots)
slot->render = newimaadr(fd, slot->render);
for (i = 0; i < TEXTARGET_COUNT; i++)
ima->gputexture[i] = newimaadr(fd, ima->gputexture[i]);
LISTBASE_FOREACH(ImageTile*, tile, &ima->tiles) {
for (int j = 0; j < TEXTARGET_COUNT; j++) {
tile->gputexture[j] = newimaadr(fd, tile->gputexture[j]);
}
}
ima->rr = newimaadr(fd, ima->rr);
}
for (; sce; sce = sce->id.next) {
@@ -3950,11 +3959,15 @@ static void direct_link_image(FileData *fd, Image *ima)
else
ima->cache = NULL;
link_list(fd, &(ima->tiles));
/* if not restored, we keep the binded opengl index */
if (!ima->cache) {
ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
for (int i = 0; i < TEXTARGET_COUNT; i++) {
ima->gputexture[i] = NULL;
LISTBASE_FOREACH(ImageTile*, tile, &ima->tiles) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
tile->gputexture[i] = NULL;
}
}
ima->rr = NULL;
}
@@ -3989,7 +4002,10 @@ static void direct_link_image(FileData *fd, Image *ima)
BLI_listbase_clear(&ima->anims);
ima->preview = direct_link_preview_image(fd, ima->preview);
ima->stereo3d_format = newdataadr(fd, ima->stereo3d_format);
ima->ok = 1;
LISTBASE_FOREACH(ImageTile*, tile, &ima->tiles) {
tile->ok = 1;
}
}

View File

@@ -1490,6 +1490,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
if (!DNA_struct_elem_find(fd->filesdna, "SpaceAction", "char", "mode_prev")) {
for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
@@ -1640,6 +1641,28 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
BKE_screen_view3d_shading_init(&scene->display.shading);
}
}
if (!DNA_struct_elem_find(fd->filesdna, "Image", "short", "num_tiles")) {
for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
ImageTile *tile = MEM_callocN(sizeof(ImageTile), "Image Tiles");
tile->ok = 1;
BLI_addtail(&ima->tiles, tile);
}
}
if (!DNA_struct_elem_find(fd->filesdna, "SpaceImage", "int", "tile_grid_shape[2]")) {
for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
sima->tile_grid_shape[0] = 1;
sima->tile_grid_shape[1] = 1;
}
}
}
}
}
}
}

View File

@@ -2210,6 +2210,8 @@ static void write_image(WriteData *wd, Image *ima)
}
writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format);
writelist(wd, DATA, ImageTile, &ima->tiles);
ima->packedfile = NULL;
writelist(wd, DATA, RenderSlot, &ima->renderslots);

View File

@@ -155,7 +155,8 @@ void ViewerOperation::initImage()
/* zero size can happen if no image buffers exist to define a sensible resolution */
if (ibuf->x > 0 && ibuf->y > 0)
imb_addrectfloatImBuf(ibuf);
ima->ok = IMA_OK_LOADED;
ImageTile *tile = BKE_image_get_tile(ima, 0);
tile->ok = IMA_OK_LOADED;
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
}

View File

@@ -32,6 +32,7 @@
#include "BLI_utildefines.h"
#include "BLI_rand.h"
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
@@ -568,7 +569,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
}
static WORKBENCH_MaterialData *get_or_create_material_data(
WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int color_type)
WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int color_type, int image_tile)
{
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_PassList *psl = vedata->psl;
@@ -583,6 +584,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.image_tile = image_tile;
uint hash = workbench_material_get_hash(&material_template);
material = BLI_ghash_lookup(wpd->material_hash, SET_UINT_IN_POINTER(hash));
@@ -628,7 +630,7 @@ static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *o
Material *mat = give_current_material(ob, part->omat);
ED_object_get_active_image(ob, part->omat, &image, NULL, NULL, NULL);
int color_type = workbench_material_determine_color_type(wpd, image);
WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, color_type);
WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, color_type, 0);
struct GPUShader *shader = (color_type != V3D_SHADING_TEXTURE_COLOR) ?
wpd->prepass_solid_hair_sh :
@@ -680,23 +682,32 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
bool is_drawn = false;
if (!is_sculpt_mode && TEXTURE_DRAWING_ENABLED(wpd) && ELEM(ob->type, OB_MESH)) {
const Mesh *me = ob->data;
if (me->mloopuv) {
if (me->mloopuv && me->totcol) {
const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
struct GPUBatch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL;
if (materials_len > 0 && geom_array) {
for (int i = 0; i < materials_len; i++) {
if (geom_array[i] == NULL) {
continue;
}
Material *mat = give_current_material(ob, i + 1);
Image *image;
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
int color_type = workbench_material_determine_color_type(wpd, image);
material = get_or_create_material_data(vedata, ob, mat, image, color_type);
DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob);
bool *is_tiled = MEM_mallocN(sizeof(bool)*materials_len, "workbench deferred is tiled");
for(int i = 0; i < materials_len; i++) {
Image *image;
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
is_tiled[i] = image && (image->source == IMA_SRC_TILED);
}
int num_batches = 0;
struct TexpaintCacheBatch *geom_batches = DRW_cache_mesh_surface_texpaint_get(ob, is_tiled, &num_batches);
for (int i = 0; i < num_batches; i++) {
if (geom_batches[i].batch == NULL) {
continue;
}
int matid = geom_batches[i].material + 1;
Material *mat = give_current_material(ob, matid);
Image *image;
ED_object_get_active_image(ob, matid, &image, NULL, NULL, NULL);
int color_type = workbench_material_determine_color_type(wpd, image);
material = get_or_create_material_data(vedata, ob, mat, image, color_type, geom_batches[i].tile);
DRW_shgroup_call_object_add(material->shgrp, geom_batches[i].batch, ob);
is_drawn = true;
}
}
@@ -708,7 +719,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
/* No material split needed */
struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
if (geom) {
material = get_or_create_material_data(vedata, ob, NULL, NULL, wpd->shading.color_type);
material = get_or_create_material_data(vedata, ob, NULL, NULL, wpd->shading.color_type, 0);
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
}
@@ -733,7 +744,7 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
}
Material *mat = give_current_material(ob, i + 1);
material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR);
material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
}

View File

@@ -31,6 +31,7 @@
#include "BLI_dynstr.h"
#include "BLI_utildefines.h"
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_particle.h"
#include "BKE_modifier.h"
@@ -137,7 +138,7 @@ static void workbench_init_object_data(DrawData *dd)
}
static WORKBENCH_MaterialData *get_or_create_material_data(
WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int color_type)
WORKBENCH_Data *vedata, Object *ob, Material *mat, Image *ima, int color_type, int image_tile)
{
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_PassList *psl = vedata->psl;
@@ -153,6 +154,7 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
material_template.object_id = OBJECT_ID_PASS_ENABLED(wpd) ? engine_object_data->object_id : 1;
material_template.color_type = color_type;
material_template.ima = ima;
material_template.image_tile = image_tile;
uint hash = workbench_material_get_hash(&material_template);
material = BLI_ghash_lookup(wpd->material_hash, SET_UINT_IN_POINTER(hash));
@@ -181,9 +183,12 @@ static WORKBENCH_MaterialData *get_or_create_material_data(
/* Depth */
if (workbench_material_determine_color_type(wpd, material->ima) == V3D_SHADING_TEXTURE_COLOR) {
ImageUser iuser = {NULL};
iuser.ok = 1;
iuser.tile = material->image_tile;
material->shgrp_object_outline = DRW_shgroup_create(
e_data.object_outline_texture_sh, psl->object_outline_pass);
GPUTexture *tex = GPU_texture_from_blender(material->ima, NULL, GL_TEXTURE_2D, false, 0.0f);
GPUTexture *tex = GPU_texture_from_blender(material->ima, &iuser, GL_TEXTURE_2D, false, 0.0f);
DRW_shgroup_uniform_texture(material->shgrp_object_outline, "image", tex);
}
else {
@@ -420,7 +425,7 @@ static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, O
Material *mat = give_current_material(ob, part->omat);
ED_object_get_active_image(ob, part->omat, &image, NULL, NULL, NULL);
int color_type = workbench_material_determine_color_type(wpd, image);
WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, color_type);
WORKBENCH_MaterialData *material = get_or_create_material_data(vedata, ob, mat, image, color_type, 0);
struct GPUShader *shader = (color_type != V3D_SHADING_TEXTURE_COLOR)
? wpd->transparent_accum_hair_sh
@@ -490,31 +495,39 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
const Mesh *me = ob->data;
if (me->mloopuv) {
const int materials_len = MAX2(1, (is_sculpt_mode ? 1 : ob->totcol));
struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
struct GPUBatch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL;
if (materials_len > 0 && geom_array) {
for (int i = 0; i < materials_len; i++) {
if (geom_array[i] == NULL) {
continue;
}
Material *mat = give_current_material(ob, i + 1);
Image *image;
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
/* use OB_SOLID when no texture could be determined */
bool *is_tiled = MEM_mallocN(sizeof(bool)*materials_len, "workbench forward is tiled");
for(int i = 0; i < materials_len; i++) {
Image *image;
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
is_tiled[i] = image && (image->source == IMA_SRC_TILED);
}
int color_type = wpd->shading.color_type;
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
/* use OB_SOLID when no texture could be determined */
if (image == NULL) {
color_type = V3D_SHADING_MATERIAL_COLOR;
}
}
int num_batches = 0;
struct TexpaintCacheBatch *geom_batches = DRW_cache_mesh_surface_texpaint_get(ob, is_tiled, &num_batches);
material = get_or_create_material_data(vedata, ob, mat, image, color_type);
DRW_shgroup_call_object_add(material->shgrp_object_outline, geom_array[i], ob);
DRW_shgroup_call_object_add(material->shgrp, geom_array[i], ob);
for (int i = 0; i < num_batches; i++) {
if (geom_batches[i].batch == NULL) {
continue;
}
int matid = geom_batches[i].material + 1;
Material *mat = give_current_material(ob, matid);
Image *image;
ED_object_get_active_image(ob, matid, &image, NULL, NULL, NULL);
/* use OB_SOLID when no texture could be determined */
int color_type = wpd->shading.color_type;
if (color_type == V3D_SHADING_TEXTURE_COLOR) {
/* use OB_SOLID when no texture could be determined */
if (image == NULL) {
color_type = V3D_SHADING_MATERIAL_COLOR;
}
}
material = get_or_create_material_data(vedata, ob, mat, image, color_type, geom_batches[i].tile);
DRW_shgroup_call_object_add(material->shgrp_object_outline, geom_batches[i].batch, ob);
DRW_shgroup_call_object_add(material->shgrp, geom_batches[i].batch, ob);
is_drawn = true;
}
}
@@ -526,7 +539,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
/* No material split needed */
struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
if (geom) {
material = get_or_create_material_data(vedata, ob, NULL, NULL, wpd->shading.color_type);
material = get_or_create_material_data(vedata, ob, NULL, NULL, wpd->shading.color_type, 0);
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat);
DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);
@@ -553,7 +566,7 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob)
}
Material *mat = give_current_material(ob, i + 1);
material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR);
material = get_or_create_material_data(vedata, ob, mat, NULL, V3D_SHADING_MATERIAL_COLOR, 0);
if (is_sculpt_mode) {
DRW_shgroup_call_sculpt_add(material->shgrp_object_outline, ob, ob->obmat);
DRW_shgroup_call_sculpt_add(material->shgrp, ob, ob->obmat);

View File

@@ -131,6 +131,7 @@ uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template)
/* add texture reference */
if (material_template->ima) {
result += BLI_ghashutil_inthash_p_murmur(material_template->ima);
result += BLI_ghashutil_inthash(material_template->image_tile);
}
return result;
@@ -185,7 +186,10 @@ void workbench_material_shgroup_uniform(
WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp, WORKBENCH_MaterialData *material)
{
if (workbench_material_determine_color_type(wpd, material->ima) == V3D_SHADING_TEXTURE_COLOR) {
GPUTexture *tex = GPU_texture_from_blender(material->ima, NULL, GL_TEXTURE_2D, false, 0.0f);
ImageUser iuser = {NULL};
iuser.ok = 1;
iuser.tile = material->image_tile;
GPUTexture *tex = GPU_texture_from_blender(material->ima, &iuser, GL_TEXTURE_2D, false, 0.0f);
DRW_shgroup_uniform_texture(grp, "image", tex);
}
else {
@@ -205,4 +209,5 @@ void workbench_material_copy(WORKBENCH_MaterialData *dest_material, const WORKBE
copy_v4_v4(dest_material->specular_color, source_material->specular_color);
dest_material->roughness = source_material->roughness;
dest_material->ima = source_material->ima;
dest_material->image_tile = source_material->image_tile;
}

View File

@@ -205,6 +205,7 @@ typedef struct WORKBENCH_MaterialData {
int object_id;
int color_type;
Image *ima;
int image_tile;
/* Linked shgroup for drawing */
DRWShadingGroup *shgrp;

View File

@@ -2870,20 +2870,20 @@ GPUBatch **DRW_cache_mesh_surface_shaded_get(
}
/* Return list of batches */
GPUBatch **DRW_cache_mesh_surface_texpaint_get(Object *ob)
TexpaintCacheBatch *DRW_cache_mesh_surface_texpaint_get(Object *ob, bool *is_tiled, int *num_batches)
{
BLI_assert(ob->type == OB_MESH);
Mesh *me = ob->data;
return DRW_mesh_batch_cache_get_surface_texpaint(me);
return DRW_mesh_batch_cache_get_surface_texpaint(me, is_tiled, num_batches);
}
GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(Object *ob)
TexpaintCacheBatch *DRW_cache_mesh_surface_texpaint_single_get(Object *ob, bool is_tiled, int *num_batches)
{
BLI_assert(ob->type == OB_MESH);
Mesh *me = ob->data;
return DRW_mesh_batch_cache_get_surface_texpaint_single(me);
return DRW_mesh_batch_cache_get_surface_texpaint_single(me, is_tiled, num_batches);
}
GPUBatch *DRW_cache_mesh_surface_verts_get(Object *ob)

View File

@@ -32,6 +32,12 @@ struct ModifierData;
struct Object;
struct PTCacheEdit;
typedef struct TexpaintCacheBatch {
struct GPUBatch *batch;
int material;
int tile;
} TexpaintCacheBatch;
void DRW_shape_cache_free(void);
void DRW_shape_cache_reset(void);
@@ -142,8 +148,8 @@ struct GPUBatch *DRW_cache_mesh_verts_weight_overlay_get(struct Object *ob);
struct GPUBatch **DRW_cache_mesh_surface_shaded_get(
struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len,
char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count);
struct GPUBatch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob);
struct GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob);
struct TexpaintCacheBatch *DRW_cache_mesh_surface_texpaint_get(struct Object *ob, bool *is_tiled, int *num_batches);
struct TexpaintCacheBatch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob, bool is_tiled, int *num_batches);
void DRW_cache_mesh_sculpt_coords_ensure(struct Object *ob);

View File

@@ -97,8 +97,8 @@ struct GPUBatch *DRW_lattice_batch_cache_get_overlay_verts(struct Lattice *lt);
struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(
struct Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len,
char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count);
struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me);
struct TexpaintCacheBatch *DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me, bool *is_tiled, int *num_batches);
struct TexpaintCacheBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me, bool is_tiled, int *num_batches);
struct GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_edges(struct Mesh *me, bool use_wire, bool use_sel);
struct GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_faces(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_verts(struct Mesh *me);

View File

@@ -1558,6 +1558,8 @@ typedef struct MeshBatchCache {
GPUVertBuf *pos_with_normals;
GPUVertBuf *tri_aligned_uv; /* Active UV layer (mloopuv) */
int *tri_tiles;
/**
* Other uses are all positions or loose elements.
* This stores all visible elements, needed for selection.
@@ -1599,12 +1601,16 @@ typedef struct MeshBatchCache {
GPUVertFormat shaded_triangles_format;
GPUVertBuf *shaded_triangles_data;
GPUIndexBuf **shaded_triangles_in_order;
GPUIndexBuf **shaded_triangles_in_order_tiled;
GPUIndexBuf **shaded_triangles_in_order_tiled_single;
GPUBatch **shaded_triangles;
/* Texture Paint.*/
/* per-texture batch */
GPUBatch **texpaint_triangles;
GPUBatch *texpaint_triangles_single;
int num_texpaint_batches;
int num_texpaint_batches_single;
TexpaintCacheBatch *texpaint_triangles;
TexpaintCacheBatch *texpaint_triangles_single;
/* Edit Cage Mesh buffers */
GPUVertBuf *ed_tri_pos;
@@ -1801,12 +1807,17 @@ static void mesh_batch_cache_clear_selective(Mesh *me, GPUVertBuf *vert)
}
MEM_SAFE_FREE(cache->shaded_triangles);
if (cache->texpaint_triangles) {
for (int i = 0; i < cache->mat_len; ++i) {
GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]);
for (int i = 0; i < cache->num_texpaint_batches; ++i) {
GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i].batch);
}
}
MEM_SAFE_FREE(cache->texpaint_triangles);
GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single);
if (cache->texpaint_triangles_single) {
for (int i = 0; i < cache->num_texpaint_batches_single; ++i) {
GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single[i].batch);
}
}
MEM_SAFE_FREE(cache->texpaint_triangles_single);
}
/* TODO: add the other ones if needed. */
else {
@@ -1859,6 +1870,7 @@ static void mesh_batch_cache_clear(Mesh *me)
GPU_BATCH_DISCARD_SAFE(cache->triangles_with_weights);
GPU_BATCH_DISCARD_SAFE(cache->triangles_with_vert_colors);
GPU_VERTBUF_DISCARD_SAFE(cache->tri_aligned_uv);
MEM_SAFE_FREE(cache->tri_tiles);
GPU_VERTBUF_DISCARD_SAFE(cache->ed_fcenter_pos_with_nor_and_sel);
GPU_VERTBUF_DISCARD_SAFE(cache->ed_edge_pos);
GPU_VERTBUF_DISCARD_SAFE(cache->ed_vert_pos);
@@ -1877,31 +1889,50 @@ static void mesh_batch_cache_clear(Mesh *me)
DRW_TEXTURE_FREE_SAFE(cache->edges_face_overlay_tx);
GPU_VERTBUF_DISCARD_SAFE(cache->shaded_triangles_data);
if (cache->shaded_triangles_in_order) {
for (int i = 0; i < cache->mat_len; ++i) {
GPU_INDEXBUF_DISCARD_SAFE(cache->shaded_triangles_in_order[i]);
}
}
MEM_SAFE_FREE(cache->shaded_triangles_in_order);
if (cache->shaded_triangles_in_order_tiled) {
for (int i = 0; i < cache->num_texpaint_batches; ++i) {
GPU_INDEXBUF_DISCARD_SAFE(cache->shaded_triangles_in_order_tiled[i]);
}
}
MEM_SAFE_FREE(cache->shaded_triangles_in_order_tiled);
if (cache->shaded_triangles_in_order_tiled_single) {
for (int i = 0; i < cache->num_texpaint_batches_single; ++i) {
GPU_INDEXBUF_DISCARD_SAFE(cache->shaded_triangles_in_order_tiled_single[i]);
}
}
MEM_SAFE_FREE(cache->shaded_triangles_in_order_tiled_single);
if (cache->shaded_triangles) {
for (int i = 0; i < cache->mat_len; ++i) {
GPU_BATCH_DISCARD_SAFE(cache->shaded_triangles[i]);
}
}
MEM_SAFE_FREE(cache->shaded_triangles_in_order);
MEM_SAFE_FREE(cache->shaded_triangles);
MEM_SAFE_FREE(cache->auto_layer_names);
MEM_SAFE_FREE(cache->auto_layer_is_srgb);
if (cache->texpaint_triangles) {
for (int i = 0; i < cache->mat_len; ++i) {
GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]);
for (int i = 0; i < cache->num_texpaint_batches; ++i) {
GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i].batch);
}
}
MEM_SAFE_FREE(cache->texpaint_triangles);
GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single);
MEM_SAFE_FREE(cache->texpaint_triangles_single);
if (cache->texpaint_triangles_single) {
for (int i = 0; i < cache->num_texpaint_batches_single; ++i) {
GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single[i].batch);
}
}
MEM_SAFE_FREE(cache->texpaint_triangles_single);
}
@@ -2143,8 +2174,17 @@ static GPUVertBuf *mesh_batch_cache_get_tri_shading_data(MeshRenderData *rdata,
return cache->shaded_triangles_data;
}
static int get_tile_index_from_uv(const float *uv)
{
int x = uv[0];
int y = uv[1];
CLAMP(x, 0, 9);
CLAMP(y, 0, 9);
return y*10 + x;
}
static GPUVertBuf *mesh_batch_cache_get_tri_uv_active(
MeshRenderData *rdata, MeshBatchCache *cache)
MeshRenderData *rdata, MeshBatchCache *cache, bool has_tiles, bool *is_tiled)
{
BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_LOOPUV));
@@ -2164,6 +2204,20 @@ static GPUVertBuf *mesh_batch_cache_get_tri_uv_active(
}
const int tri_len = mesh_render_data_looptri_len_get(rdata);
const int mat_len = mesh_render_data_mat_len_get(rdata);
if (is_tiled) {
for (int i = 0; i < mat_len; i++) {
if (is_tiled[i]) {
has_tiles = true;
break;
}
}
}
if (has_tiles) {
cache->tri_tiles = MEM_callocN(sizeof(int) * tri_len, "mesh cache tri tiles");
}
GPUVertBuf *vbo = cache->tri_aligned_uv = GPU_vertbuf_create_with_format(&format);
@@ -2184,14 +2238,18 @@ static GPUVertBuf *mesh_batch_cache_get_tri_uv_active(
if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) {
continue;
}
const float *elem = NULL;
for (uint t = 0; t < 3; t++) {
const BMLoop *loop = bm_looptri[t];
const int index = BM_elem_index_get(loop);
if (index != -1) {
const float *elem = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->uv;
elem = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->uv;
GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, elem);
}
}
if (elem && has_tiles) {
cache->tri_tiles[i] = get_tile_index_from_uv(elem);
}
}
}
else {
@@ -2201,6 +2259,9 @@ static GPUVertBuf *mesh_batch_cache_get_tri_uv_active(
GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[0]].uv);
GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[1]].uv);
GPU_vertbuf_attr_set(vbo, attr_id.uv, vidx++, mloopuv[mlt->tri[2]].uv);
if (has_tiles) {
cache->tri_tiles[i] = get_tile_index_from_uv(mloopuv[mlt->tri[2]].uv);
}
}
}
@@ -3564,22 +3625,47 @@ static GPUIndexBuf *mesh_batch_cache_get_loose_edges(MeshRenderData *rdata, Mesh
return cache->ledges_in_order;
}
static GPUIndexBuf **mesh_batch_cache_get_triangles_in_order_split_by_material(
MeshRenderData *rdata, MeshBatchCache *cache)
static inline int get_batch_index_for_tri(bool single, bool texpaint, short mat, int mat_len, int *tri_tiles, int tri)
{
if (single || (mat >= mat_len)) {
mat = 0;
}
if (texpaint) {
return 100*mat + tri_tiles[tri];
}
return mat;
}
static GPUIndexBuf **mesh_batch_cache_get_triangles_in_order_split(
MeshRenderData *rdata, MeshBatchCache *cache, bool single, bool texpaint, int **batch_mapping, int *batch_num)
{
BLI_assert(rdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_POLY));
if (cache->shaded_triangles_in_order == NULL) {
GPUIndexBuf*** shaded_triangles;
if (texpaint) {
shaded_triangles = single? &cache->shaded_triangles_in_order_tiled_single : &cache->shaded_triangles_in_order_tiled;
}
else {
shaded_triangles = &cache->shaded_triangles_in_order;
}
if (*shaded_triangles == NULL) {
const int poly_len = mesh_render_data_polys_len_get(rdata);
const int tri_len = mesh_render_data_looptri_len_get(rdata);
const int mat_len = mesh_render_data_mat_len_get(rdata);
int *mat_tri_len = MEM_callocN(sizeof(*mat_tri_len) * mat_len, __func__);
cache->shaded_triangles_in_order = MEM_callocN(sizeof(*cache->shaded_triangles) * mat_len, __func__);
GPUIndexBufBuilder *elb = MEM_callocN(sizeof(*elb) * mat_len, __func__);
if (cache->tri_tiles == NULL) {
texpaint = false;
}
/* Triangles are split according to material and/or tile index.
* To do this, we first need to find the combinations that are actually used. */
int index_num = (single? 1 : mat_len) * (texpaint? 100 : 1);
int *batch_len = MEM_callocN(sizeof(int) * index_num, __func__);
/* Note that polygons (not triangles) are used here.
* This OK because result is _guaranteed_ to be the same. */
uint tri = 0;
if (rdata->edit_bmesh) {
BMesh *bm = rdata->edit_bmesh->bm;
BMIter fiter;
@@ -3587,26 +3673,67 @@ static GPUIndexBuf **mesh_batch_cache_get_triangles_in_order_split_by_material(
BM_ITER_MESH(efa, &fiter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
const short ma_id = efa->mat_nr < mat_len ? efa->mat_nr : 0;
mat_tri_len[ma_id] += (efa->len - 2);
for(int j = 2; j < efa->len; j++, tri++) {
int index = get_batch_index_for_tri(single, texpaint, efa->mat_nr, mat_len, cache->tri_tiles, tri);
batch_len[index]++;
}
}
}
}
else {
for (uint i = 0; i < poly_len; i++) {
const MPoly *mp = &rdata->mpoly[i]; ;
const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0;
mat_tri_len[ma_id] += (mp->totloop - 2);
const MPoly *mp = &rdata->mpoly[i];
for(int j = 2; j < mp->totloop; j++, tri++) {
int index = get_batch_index_for_tri(single, texpaint, mp->mat_nr, mat_len, cache->tri_tiles, tri);
batch_len[index]++;
}
}
}
/* Now, all combinations that appear in the mesh get an assigned batch index.
* Also, we need to know each batches' length, so the batch_len array is replaced
* with each batches' length (instead of each combinations' length).
* This can be done in one pass since batch_num is guaranteed to be less or equal to i.
*/
int *index_to_batch = MEM_mallocN(sizeof(int) * index_num, __func__);
*batch_num = 0;
for (int i = 0; i < index_num; i++) {
if (batch_len[i] > 0) {
index_to_batch[i] = *batch_num;
batch_len[*batch_num] = batch_len[i];
(*batch_num)++;
}
else {
index_to_batch[i] = -1;
}
}
/* Return the mapping from batches to material/tile pairs to the caller. */
int *mapping = *batch_mapping = MEM_mallocN(sizeof(int) * 2 * (*batch_num), __func__);
for (int i = 0; i < index_num; i++) {
if (index_to_batch[i] >= 0) {
int batch = index_to_batch[i];
if (texpaint) {
mapping[2*batch + 0] = (i / 100);
mapping[2*batch + 1] = (i % 100);
}
else {
mapping[2*batch + 0] = i;
mapping[2*batch + 1] = 0;
}
}
}
*shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * (*batch_num), __func__);
GPUIndexBufBuilder *elb = MEM_callocN(sizeof(*elb) * (*batch_num), __func__);
/* Init ELBs. */
for (int i = 0; i < mat_len; ++i) {
GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, mat_tri_len[i], tri_len * 3);
for (int i = 0; i < *batch_num; ++i) {
GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, batch_len[i], tri_len * 3);
}
/* Populate ELBs. */
uint nidx = 0;
tri = 0;
if (rdata->edit_bmesh) {
BMesh *bm = rdata->edit_bmesh->bm;
BMIter fiter;
@@ -3614,10 +3741,9 @@ static GPUIndexBuf **mesh_batch_cache_get_triangles_in_order_split_by_material(
BM_ITER_MESH(efa, &fiter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
const short ma_id = efa->mat_nr < mat_len ? efa->mat_nr : 0;
for (int j = 2; j < efa->len; j++) {
GPU_indexbuf_add_tri_verts(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2);
nidx += 3;
for(int j = 2; j < efa->len; j++, tri++) {
int index = get_batch_index_for_tri(single, texpaint, efa->mat_nr, mat_len, cache->tri_tiles, tri);
GPU_indexbuf_add_tri_verts(&elb[index_to_batch[index]], 3*tri + 0, 3*tri + 1, 3*tri + 2);
}
}
}
@@ -3625,24 +3751,24 @@ static GPUIndexBuf **mesh_batch_cache_get_triangles_in_order_split_by_material(
else {
for (uint i = 0; i < poly_len; i++) {
const MPoly *mp = &rdata->mpoly[i]; ;
const short ma_id = mp->mat_nr < mat_len ? mp->mat_nr : 0;
for (int j = 2; j < mp->totloop; j++) {
GPU_indexbuf_add_tri_verts(&elb[ma_id], nidx + 0, nidx + 1, nidx + 2);
nidx += 3;
for(int j = 2; j < mp->totloop; j++, tri++) {
int index = get_batch_index_for_tri(single, texpaint, mp->mat_nr, mat_len, cache->tri_tiles, tri);
GPU_indexbuf_add_tri_verts(&elb[index_to_batch[index]], 3*tri + 0, 3*tri + 1, 3*tri + 2);
}
}
}
/* Build ELBs. */
for (int i = 0; i < mat_len; ++i) {
cache->shaded_triangles_in_order[i] = GPU_indexbuf_build(&elb[i]);
for (int i = 0; i < *batch_num; ++i) {
(*shaded_triangles)[i] = GPU_indexbuf_build(&elb[i]);
}
MEM_freeN(mat_tri_len);
MEM_freeN(batch_len);
MEM_freeN(index_to_batch);
MEM_freeN(elb);
}
return cache->shaded_triangles_in_order;
return *shaded_triangles;
}
static GPUVertBuf *mesh_create_edge_pos_with_sel(
@@ -4311,19 +4437,23 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(
cache->shaded_triangles = MEM_callocN(sizeof(*cache->shaded_triangles) * mat_len, __func__);
GPUIndexBuf **el = mesh_batch_cache_get_triangles_in_order_split_by_material(rdata, cache);
int *batch_mapping;
int batch_num;
GPUIndexBuf **el = mesh_batch_cache_get_triangles_in_order_split(rdata, cache, false, false, &batch_mapping, &batch_num);
GPUVertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
GPUVertBuf *vbo_shading = mesh_batch_cache_get_tri_shading_data(rdata, cache);
for (int i = 0; i < mat_len; ++i) {
cache->shaded_triangles[i] = GPU_batch_create(
for (int i = 0; i < batch_num; ++i) {
int mat = batch_mapping[2*i + 0];
cache->shaded_triangles[mat] = GPU_batch_create(
GPU_PRIM_TRIS, vbo, el[i]);
if (vbo_shading) {
GPU_batch_vertbuf_add(cache->shaded_triangles[i], vbo_shading);
GPU_batch_vertbuf_add(cache->shaded_triangles[mat], vbo_shading);
}
}
MEM_SAFE_FREE(batch_mapping);
mesh_render_data_free(rdata);
}
@@ -4336,7 +4466,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(
return cache->shaded_triangles;
}
GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me)
TexpaintCacheBatch *DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me, bool *is_tiled, int *num_batches)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
@@ -4346,28 +4476,33 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me)
MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOPUV;
MeshRenderData *rdata = mesh_render_data_create(me, datatype);
const int mat_len = mesh_render_data_mat_len_get(rdata);
cache->texpaint_triangles = MEM_callocN(sizeof(*cache->texpaint_triangles) * mat_len, __func__);
GPUIndexBuf **el = mesh_batch_cache_get_triangles_in_order_split_by_material(rdata, cache);
GPUVertBuf *vbo_uv = mesh_batch_cache_get_tri_uv_active(rdata, cache, false, is_tiled);
GPUVertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
for (int i = 0; i < mat_len; ++i) {
cache->texpaint_triangles[i] = GPU_batch_create(
int *batch_mapping;
GPUIndexBuf **el = mesh_batch_cache_get_triangles_in_order_split(rdata, cache, false, true, &batch_mapping, &cache->num_texpaint_batches);
cache->texpaint_triangles = MEM_callocN(sizeof(*cache->texpaint_triangles) * cache->num_texpaint_batches, __func__);
for (int i = 0; i < cache->num_texpaint_batches; ++i) {
cache->texpaint_triangles[i].batch = GPU_batch_create(
GPU_PRIM_TRIS, vbo, el[i]);
GPUVertBuf *vbo_uv = mesh_batch_cache_get_tri_uv_active(rdata, cache);
if (vbo_uv) {
GPU_batch_vertbuf_add(cache->texpaint_triangles[i], vbo_uv);
GPU_batch_vertbuf_add(cache->texpaint_triangles[i].batch, vbo_uv);
}
cache->texpaint_triangles[i].material = batch_mapping[2*i + 0];
cache->texpaint_triangles[i].tile = batch_mapping[2*i + 1];
}
MEM_SAFE_FREE(batch_mapping);
mesh_render_data_free(rdata);
}
*num_batches = cache->num_texpaint_batches;
return cache->texpaint_triangles;
}
GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me)
TexpaintCacheBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me, bool is_tiled, int *num_batches)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
@@ -4377,16 +4512,43 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me)
MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOPUV;
MeshRenderData *rdata = mesh_render_data_create(me, datatype);
GPUVertBuf *vbo_uv = mesh_batch_cache_get_tri_uv_active(rdata, cache, is_tiled, NULL);
GPUVertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache);
cache->texpaint_triangles_single = GPU_batch_create(
GPU_PRIM_TRIS, vbo, NULL);
GPUVertBuf *vbo_uv = mesh_batch_cache_get_tri_uv_active(rdata, cache);
if (vbo_uv) {
GPU_batch_vertbuf_add(cache->texpaint_triangles_single, vbo_uv);
if (cache->tri_tiles) {
int *batch_mapping;
GPUIndexBuf **el = mesh_batch_cache_get_triangles_in_order_split(rdata, cache, true, true, &batch_mapping, &cache->num_texpaint_batches_single);
cache->texpaint_triangles_single = MEM_callocN(sizeof(*cache->texpaint_triangles) * cache->num_texpaint_batches_single, __func__);
for (int i = 0; i < cache->num_texpaint_batches_single; ++i) {
cache->texpaint_triangles[i].batch = GPU_batch_create(
GPU_PRIM_TRIS, vbo, el[i]);
if (vbo_uv) {
GPU_batch_vertbuf_add(cache->texpaint_triangles[i].batch, vbo_uv);
}
cache->texpaint_triangles[i].material = batch_mapping[2*i + 0];
cache->texpaint_triangles[i].tile = batch_mapping[2*i + 1];
}
MEM_SAFE_FREE(batch_mapping);
}
else {
cache->texpaint_triangles_single = MEM_callocN(sizeof(*cache->texpaint_triangles), __func__);
cache->texpaint_triangles_single[0].batch = GPU_batch_create(
GPU_PRIM_TRIS, vbo, NULL);
if (vbo_uv) {
GPU_batch_vertbuf_add(cache->texpaint_triangles_single[0].batch, vbo_uv);
}
cache->texpaint_triangles_single[0].material = 0;
cache->texpaint_triangles_single[0].tile = 0;
cache->num_texpaint_batches = 1;
}
mesh_render_data_free(rdata);
}
*num_batches = cache->num_texpaint_batches;
return cache->texpaint_triangles_single;
}

View File

@@ -766,9 +766,18 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, struct
for (GPUInput *input = inputs->first; input; input = input->next) {
/* Textures */
if (input->ima) {
ImageUser *tex_iuser = input->iuser;
/* If there's no specified iuser but we need a different tile, create a temporary one. */
ImageUser iuser = {NULL};
iuser.ok = true;
iuser.tile = input->image_tile;
if (!tex_iuser && iuser.tile != 0)
tex_iuser = &iuser;
double time = 0.0; /* TODO make time variable */
GPUTexture *tex = GPU_texture_from_blender(
input->ima, input->iuser, input->textarget, input->image_isdata, time);
input->ima, tex_iuser, input->textarget, input->image_isdata, time);
if (input->bindtex) {
DRW_shgroup_uniform_texture(grp, input->shadername, tex);

View File

@@ -26,6 +26,8 @@
#include "DRW_engine.h"
#include "DRW_render.h"
#include "BKE_image.h"
#include "BIF_gl.h"
/* If builtin shaders are needed */
@@ -118,7 +120,6 @@ typedef struct PAINT_TEXTURE_PrivateData {
/* This keeps the references of the shading groups for
* easy access in PAINT_TEXTURE_cache_populate() */
DRWShadingGroup *shgroup_fallback;
DRWShadingGroup **shgroup_image_array;
/* face-mask */
DRWShadingGroup *lwire_shgrp;
@@ -189,7 +190,6 @@ static void PAINT_TEXTURE_cache_init(void *vedata)
if (!stl->g_data) {
/* Alloc transient pointers */
stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
stl->g_data->shgroup_image_array = NULL;
}
{
@@ -203,53 +203,6 @@ static void PAINT_TEXTURE_cache_init(void *vedata)
* any given time (i.e. use static vars) */
static float color[4] = {1.0f, 0.0f, 1.0f, 1.0};
DRW_shgroup_uniform_vec4(stl->g_data->shgroup_fallback, "color", color, 1);
MEM_SAFE_FREE(stl->g_data->shgroup_image_array);
const DRWContextState *draw_ctx = DRW_context_state_get();
Object *ob = draw_ctx->obact;
if (ob && ob->type == OB_MESH) {
Scene *scene = draw_ctx->scene;
const bool use_material_slots = (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL);
const Mesh *me = ob->data;
stl->g_data->shgroup_image_array = MEM_mallocN(
sizeof(*stl->g_data->shgroup_image_array) * (use_material_slots ? me->totcol : 1), __func__);
if (use_material_slots) {
for (int i = 0; i < me->totcol; i++) {
Material *ma = give_current_material(ob, i + 1);
Image *ima = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
GPUTexture *tex = ima ?
GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false, 0.0f) : NULL;
if (tex) {
DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
DRW_shgroup_uniform_texture(grp, "image", tex);
DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
stl->g_data->shgroup_image_array[i] = grp;
}
else {
stl->g_data->shgroup_image_array[i] = NULL;
}
}
}
else {
Image *ima = scene->toolsettings->imapaint.canvas;
GPUTexture *tex = ima ?
GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false, 0.0f) : NULL;
if (tex) {
DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
DRW_shgroup_uniform_texture(grp, "image", tex);
DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
stl->g_data->shgroup_image_array[0] = grp;
}
else {
stl->g_data->shgroup_image_array[0] = NULL;
}
}
}
}
/* Face Mask */
@@ -293,29 +246,62 @@ static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob)
if (use_surface) {
if (me->mloopuv != NULL) {
if (use_material_slots) {
struct GPUBatch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL;
if ((me->totcol == 0) || (geom_array == NULL)) {
struct GPUBatch *geom = DRW_cache_mesh_surface_get(ob);
DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom, ob->obmat);
ok = true;
}
else {
for (int i = 0; i < me->totcol; i++) {
if (stl->g_data->shgroup_image_array[i]) {
DRW_shgroup_call_add(stl->g_data->shgroup_image_array[i], geom_array[i], ob->obmat);
//struct GPUBatch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL;
if (me->totcol) {
bool *is_tiled = MEM_mallocN(sizeof(bool)*me->totcol, "paint texture is tiled");
for(int i = 0; i < me->totcol; i++) {
Material *ma = give_current_material(ob, i + 1);
Image *ima = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
is_tiled[i] = ima && (ima->source == IMA_SRC_TILED);
}
int num_batches = 0;
struct TexpaintCacheBatch *geom_batches = DRW_cache_mesh_surface_texpaint_get(ob, is_tiled, &num_batches);
for (int i = 0; i < num_batches; i++) {
ImageUser iuser = {NULL};
iuser.ok = 1;
iuser.tile = geom_batches[i].tile;
Material *ma = give_current_material(ob, geom_batches[i].material + 1);
Image *ima = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
GPUTexture *tex = ima ?
GPU_texture_from_blender(ima, &iuser, GL_TEXTURE_2D, false, 0.0f) : NULL;
if (tex) {
DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
DRW_shgroup_uniform_texture(grp, "image", tex);
DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
DRW_shgroup_call_add(grp, geom_batches[i].batch, ob->obmat);
}
else {
DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom_array[i], ob->obmat);
DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom_batches[i].batch, ob->obmat);
}
ok = true;
}
}
}
else {
struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
if (geom && stl->g_data->shgroup_image_array[0]) {
DRW_shgroup_call_add(stl->g_data->shgroup_image_array[0], geom, ob->obmat);
ok = true;
Image *ima = scene->toolsettings->imapaint.canvas;
if (ima) {
bool is_tiled = (ima->source == IMA_SRC_TILED);
int num_batches = 0;
struct TexpaintCacheBatch *geom_batches = DRW_cache_mesh_surface_texpaint_single_get(ob, is_tiled, &num_batches);
for (int i = 0; i < num_batches; i++) {
ImageUser iuser = {NULL};
iuser.ok = 1;
iuser.tile = geom_batches[i].tile;
GPUTexture *tex = GPU_texture_from_blender(ima, &iuser, GL_TEXTURE_2D, false, 0.0f);
if (tex) {
DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
DRW_shgroup_uniform_texture(grp, "image", tex);
DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
DRW_shgroup_call_add(grp, geom_batches[i].batch, ob->obmat);
ok = true;
}
}
}
}
}
@@ -345,12 +331,9 @@ static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob)
static void PAINT_TEXTURE_cache_finish(void *vedata)
{
PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
/* Do something here! dependant on the objects gathered */
UNUSED_VARS(psl);
MEM_SAFE_FREE(stl->g_data->shgroup_image_array);
}
/* Draw time ! Control rendering pipeline from here */

View File

@@ -48,7 +48,7 @@ struct Mask *ED_space_image_get_mask(struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
bool ED_space_image_color_sample(struct SpaceImage *sima, struct ARegion *ar, int mval[2], float r_col[3]);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile);
void ED_space_image_release_buffer(struct SpaceImage *sima, struct ImBuf *ibuf, void *lock);
bool ED_space_image_has_buffer(struct SpaceImage *sima);

View File

@@ -41,7 +41,7 @@ void ED_keymap_paint(struct wmKeyConfig *keyconf);
/* paint_image.c */
void ED_imapaint_clear_partial_redraw(void);
void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old);
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op, const int mouse[2]);
/* paint_image_undo.c */
void ED_image_undo_push_begin(const char *name);

View File

@@ -106,7 +106,7 @@ void ED_region_visibility_change_update(struct bContext *C, struct ARegion *a
void ED_region_info_draw(struct ARegion *ar, const char *text, float fill_color[4], const bool full_redraw);
void ED_region_info_draw_multiline(ARegion *ar, const char *text_array[], float fill_color[4], const bool full_redraw);
void ED_region_image_metadata_draw(int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy);
void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy);
void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy, float x0, float y0);
float ED_region_blend_alpha(struct ARegion *ar);
void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
bool ED_region_is_overlap(int spacetype, int regiontype);

View File

@@ -1272,7 +1272,7 @@ void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
}
static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
uiBut *but = NULL;
@@ -1313,7 +1313,7 @@ static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
srgb_to_linearrgb_v3_v3(color, color);
}
ED_imapaint_bucket_fill(C, color, op);
ED_imapaint_bucket_fill(C, color, op, event->mval);
}
ED_region_tag_redraw(ar);

View File

@@ -275,9 +275,12 @@ static void refresh_images(BakeImages *bake_images)
int i;
for (i = 0; i < bake_images->size; i++) {
Image *ima = bake_images->data[i].image;
if (ima->ok == IMA_OK_LOADED) {
GPU_free_image(ima);
DEG_id_tag_update(&ima->id, 0);
LISTBASE_FOREACH(ImageTile*, tile, &ima->tiles) {
if (tile->ok == IMA_OK_LOADED) {
GPU_free_image(ima);
DEG_id_tag_update(&ima->id, 0);
break;
}
}
}
}

View File

@@ -982,8 +982,12 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
ImBuf *ibuf = NULL;
ImageUser iuser = {NULL};
if (ima == NULL)
return;
ImageTile *tile = BKE_image_get_tile(ima, 0);
/* ima->ok is zero when Image cannot load */
if (ima == NULL || ima->ok == 0)
if (tile->ok == 0)
return;
/* setup dummy image user */

View File

@@ -2735,15 +2735,15 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame,
GPU_matrix_pop();
}
void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy)
void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy, float x0, float y0)
{
float gridsize, gridstep = 1.0f / 32.0f;
float fac, blendfac;
int x1, y1, x2, y2;
/* the image is located inside (0, 0), (1, 1) as set by view2d */
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x1, &y1);
UI_view2d_view_to_region(&ar->v2d, 1.0f, 1.0f, &x2, &y2);
/* the image is located inside (x0, y0), (x0+1, y0+1) as set by view2d */
UI_view2d_view_to_region(&ar->v2d, x0, y0, &x1, &y1);
UI_view2d_view_to_region(&ar->v2d, x0+1.0f, y0+1.0f, &x2, &y2);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);

View File

@@ -163,7 +163,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
IMB_freeImBuf(tmpibuf);
}
void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
{
if (imapaintpartial.x1 != imapaintpartial.x2 &&
imapaintpartial.y1 != imapaintpartial.y2)
@@ -182,7 +182,7 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
int h = imapaintpartial.y2 - imapaintpartial.y1;
if (w && h) {
/* Testing with partial update in uv editor too */
GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h);
GPU_paint_update_image(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h);
}
}
}
@@ -587,7 +587,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
float color[3];
srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush));
paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint);
paint_2d_bucket_fill(C, color, brush, pop->startmouse, pop->prevmouse, pop->custom_paint);
}
else {
paint_proj_stroke(
@@ -1224,7 +1224,7 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
}
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op, const int mouse[2])
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceImage *sima = CTX_wm_space_image(C);
@@ -1234,7 +1234,8 @@ void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
ED_image_undo_push_begin(op->type->name);
paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
float mouse_init[2] = {mouse[0], mouse[1]};
paint_2d_bucket_fill(C, color, NULL, mouse_init, NULL, NULL);
BKE_undosys_step_push(wm->undo_stack, C, op->type->name);

File diff suppressed because it is too large Load Diff

View File

@@ -193,6 +193,8 @@ BLI_INLINE unsigned char f_to_char(const float val)
* because 'partRedrawRect' and 'touch' values would not be thread safe */
typedef struct ProjPaintImage {
Image *ima;
int tile;
ImageUser iuser;
ImBuf *ibuf;
ImagePaintPartialRedraw *partRedrawRect;
volatile void **undoRect; /* only used to build undo tiles during painting */
@@ -468,6 +470,16 @@ BLI_INLINE const MPoly *ps_tri_index_to_mpoly(const ProjPaintState *ps, int tri_
/* Finish projection painting structs */
static int project_paint_face_paint_tile(Image *ima, const float *uv)
{
if (!ima || ima->source != IMA_SRC_TILED)
return 0;
/* Currently, faces are assumed to belong to one tile, so checking the first loop is enough. */
int tx = (int) uv[0];
int ty = (int) uv[1];
return 10*ty + tx;
}
static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
@@ -664,8 +676,18 @@ static bool project_paint_PickColor(
interp_v2_v2v2v2(uv, UNPACK3(lt_tri_uv), w);
ima = project_paint_face_paint_image(ps, tri_index);
ibuf = BKE_image_get_first_ibuf(ima); /* we must have got the imbuf before getting here */
if (!ibuf) return 0;
int tile_number = project_paint_face_paint_tile(ima, lt_tri_uv[0]);
ImageUser iuser = {NULL};
iuser.ok = 1;
iuser.tile = tile_number;
ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
if (!ibuf) {
iuser.tile = 0;
ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
if (!ibuf) {
return 0;
}
}
if (interp) {
float x, y;
@@ -1052,6 +1074,8 @@ static bool check_seam(
const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt) };
Image *tpage = project_paint_face_paint_image(ps, tri_index);
Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
int orig_tile = project_paint_face_paint_tile(orig_tpage, orig_lt_tri_uv[0]);
BLI_assert(i1_fidx != -1);
@@ -1069,6 +1093,7 @@ static bool check_seam(
/* first test if they have the same image */
if ((orig_tpage == tpage) &&
(orig_tile == tile) &&
cmp_uv(orig_lt_tri_uv[orig_i1_fidx], lt_tri_uv[i1_fidx]) &&
cmp_uv(orig_lt_tri_uv[orig_i2_fidx], lt_tri_uv[i2_fidx]))
{
@@ -2921,6 +2946,7 @@ static void project_bucket_init(
ImBuf *ibuf = NULL;
Image *tpage_last = NULL, *tpage;
ImBuf *tmpibuf = NULL;
int tile_last = 0;
if (ps->image_tot == 1) {
/* Simple loop, no context switching */
@@ -2938,17 +2964,33 @@ static void project_bucket_init(
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
tri_index = GET_INT_FROM_POINTER(node->link);
const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
const float *lt_tri_uv[3] = { PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt) };
/* Image context switching */
tpage = project_paint_face_paint_image(ps, tri_index);
if (tpage_last != tpage) {
int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
if (tpage_last != tpage || tile_last != tile) {
tpage_last = tpage;
tile_last = tile;
for (image_index = 0; image_index < ps->image_tot; image_index++) {
if (ps->projImages[image_index].ima == tpage_last) {
ibuf = ps->projImages[image_index].ibuf;
ProjPaintImage *projIma = &ps->projImages[image_index];
if ((projIma->ima == tpage) && (projIma->tile == tile)) {
ibuf = projIma->ibuf;
break;
}
}
if (ibuf == NULL) {
/* Failed to find the specific tile, fall back to the primary tile. */
for (image_index = 0; image_index < ps->image_tot; image_index++) {
ProjPaintImage *projIma = &ps->projImages[image_index];
if ((projIma->ima == tpage) && (projIma->tile == 0)) {
ibuf = projIma->ibuf;
break;
}
}
}
}
/* context switching done */
@@ -3624,22 +3666,36 @@ static bool project_paint_winclip(
#endif //PROJ_DEBUG_WINCLIP
typedef struct PrepareImageEntry {
struct PrepareImageEntry *next, *prev;
Image *ima;
int tile;
} PrepareImageEntry;
static void project_paint_build_proj_ima(
ProjPaintState *ps, MemArena *arena,
LinkNode *image_LinkList)
ListBase *used_images)
{
ProjPaintImage *projIma;
LinkNode *node;
PrepareImageEntry *entry;
int i;
/* build an array of images we use */
projIma = ps->projImages = BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) {
for (entry = used_images->first, i = 0; entry; entry = entry->next, i++, projIma++) {
memset(&projIma->iuser, 0, sizeof(ImageUser));
projIma->iuser.ok = 1;
projIma->iuser.tile = entry->tile;
int size;
projIma->ima = node->link;
projIma->ima = entry->ima;
projIma->tile = entry->tile;
projIma->touch = 0;
projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, &projIma->iuser, NULL);
if (!projIma->ibuf) {
projIma->iuser.tile = 0;
projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, &projIma->iuser, NULL);
}
size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
partial_redraw_array_init(projIma->partRedrawRect);
@@ -3660,15 +3716,18 @@ static void project_paint_prepare_all_faces(
const bool is_multi_view)
{
/* Image Vars - keep track of images we have used */
LinkNodePair image_LinkList = {NULL, NULL};
ListBase used_images = {NULL};
Image *tpage_last = NULL, *tpage;
TexPaintSlot *slot_last = NULL;
TexPaintSlot *slot = NULL;
int tile_last = -1, tile;
const MLoopTri *lt;
int image_index = -1, tri_index;
int prev_poly = -1;
BLI_assert(ps->image_tot == 0);
for (tri_index = 0, lt = ps->mlooptri_eval; tri_index < ps->totlooptri_eval; tri_index++, lt++) {
bool is_face_sel;
@@ -3709,6 +3768,8 @@ static void project_paint_prepare_all_faces(
ps->poly_to_loop_uv[lt->poly] = mloopuv_base;
tile = project_paint_face_paint_tile(tpage, mloopuv_base[lt->tri[0]].uv);
if (project_paint_clone_face_skip(ps, layer_clone, slot, tri_index)) {
continue;
}
@@ -3766,17 +3827,24 @@ static void project_paint_prepare_all_faces(
}
}
if (tpage_last != tpage) {
if (tpage_last != tpage || tile_last != tile) {
image_index = 0;
for (PrepareImageEntry *e = used_images.first; e; e = e->next, image_index++) {
if (e->ima == tpage && e->tile == tile) {
break;
}
}
image_index = BLI_linklist_index(image_LinkList.list, tpage);
if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) { /* MemArena dosnt have an append func */
BLI_linklist_append(&image_LinkList, tpage);
image_index = ps->image_tot;
if (image_index == ps->image_tot) {
PrepareImageEntry *e = MEM_callocN(sizeof(PrepareImageEntry), "PrepareImageEntry");
e->ima = tpage;
e->tile = tile;
BLI_addtail(&used_images, e);
ps->image_tot++;
}
tpage_last = tpage;
tile_last = tile;
}
if (image_index != -1) {
@@ -3789,11 +3857,11 @@ static void project_paint_prepare_all_faces(
/* build an array of images we use*/
if (ps->is_shared_user == false) {
project_paint_build_proj_ima(ps, arena, image_LinkList.list);
project_paint_build_proj_ima(ps, arena, &used_images);
}
/* we have built the array, discard the linked list */
BLI_linklist_free(image_LinkList.list, NULL);
BLI_freelistN(&used_images);
}
/* run once per stroke before projection painting */
@@ -4036,7 +4104,7 @@ static bool project_image_refresh_tagged(ProjPaintState *ps)
pr = &(projIma->partRedrawRect[i]);
if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
set_imapaintpartial(pr);
imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
imapaint_image_update(NULL, projIma->ima, projIma->ibuf, &projIma->iuser, true);
redraw = 1;
}
@@ -5644,7 +5712,7 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
}
ima = BKE_image_add_generated(
bmain, width, height, imagename, alpha ? 32 : 24, use_float,
gen_type, color, false);
gen_type, color, false, false);
return ima;
}

View File

@@ -181,7 +181,7 @@ typedef struct ImagePaintPartialRedraw {
#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
bool image_texture_paint_poll(struct bContext *C);
void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint);
void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, struct ImageUser *iuser, short texpaint);
struct ImagePaintPartialRedraw *get_imapaintpartial(void);
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th);
@@ -193,7 +193,7 @@ void paint_2d_stroke(
void *ps, const float prev_mval[2], const float mval[2],
const bool eraser, float pressure, float distance, float size);
void paint_2d_bucket_fill(
const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps);
const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
void paint_2d_gradient_fill(
const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
void *paint_proj_new_stroke(

View File

@@ -1790,7 +1790,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
/* if no clip, nothing to do */
if (!clip) {
ED_region_grid_draw(ar, zoomx, zoomy);
ED_region_grid_draw(ar, zoomx, zoomy, 0.0f, 0.0f);
return;
}
@@ -1836,7 +1836,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
draw_movieclip_muted(ar, width, height, zoomx, zoomy);
}
else {
ED_region_grid_draw(ar, zoomx, zoomy);
ED_region_grid_draw(ar, zoomx, zoomy, 0.0f, 0.0f);
}
if (width && height) {

View File

@@ -112,7 +112,7 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf,
if (ibuf->zbuf || ibuf->zbuf_float)
ofs += BLI_strncpy_rlen(str + ofs, IFACE_(" + Z"), len - ofs);
if (ima->source == IMA_SRC_SEQUENCE) {
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
const char *file = BLI_last_slash(ibuf->name);
if (file == NULL)
file = ibuf->name;

View File

@@ -49,6 +49,7 @@
#include "BLI_threads.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -479,7 +480,7 @@ static void sima_draw_zbuffloat_pixels(Scene *scene, float x1, float y1, int rec
MEM_freeN(rectf);
}
static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, Scene *scene, ImBuf *ibuf, float fx, float fy, float zoomx, float zoomy)
static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, Scene *scene, ImBuf *ibuf, float fx, float fy, float zoomx, float zoomy, const char *label)
{
int x, y;
@@ -547,6 +548,24 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar,
if (sima->flag & SI_USE_ALPHA)
GPU_blend(false);
}
if (label && label[0]) {
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
BLF_size(blf_mono_font, 25 * U.pixelsize, U.dpi);
int textwidth = BLF_width(blf_mono_font, label, strlen(label)) + 10;
float opacity;
float stepx = BLI_rcti_size_x(&ar->v2d.mask) / BLI_rctf_size_x(&ar->v2d.cur);
if (textwidth < 0.5f*(stepx - 10)) opacity = 1.0f;
else if (textwidth < (stepx - 10)) opacity = 2.0f - 2.0f*(textwidth / (stepx - 10));
else opacity = 0.0f;
BLF_color4ub(blf_mono_font, 220, 220, 220, 150*opacity);
BLF_position(blf_mono_font, (int) (x + 10), (int) (y + 10), 0);
BLF_draw_ascii(blf_mono_font, label, strlen(label));
glDisable(GL_BLEND);
}
}
/* draw uv edit */
@@ -586,9 +605,13 @@ void draw_image_sample_line(SpaceImage *sima)
immUniformArray4fv("colors", (float *)(float[][4]){{1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}, 2);
immUniform1f("dash_width", 2.0f);
float co[2][2];
add_v2_v2v2(co[0], hist->co[0], hist->draw_offset);
add_v2_v2v2(co[1], hist->co[1], hist->draw_offset);
immBegin(GPU_PRIM_LINES, 2);
immVertex2fv(shdr_dashed_pos, hist->co[0]);
immVertex2fv(shdr_dashed_pos, hist->co[1]);
immVertex2fv(shdr_dashed_pos, co[0]);
immVertex2fv(shdr_dashed_pos, co[1]);
immEnd();
immUnbindProgram();
@@ -633,6 +656,69 @@ static void draw_image_paint_helpers(const bContext *C, ARegion *ar, Scene *scen
}
}
static void draw_udim_tile_grid(unsigned int pos_attr, unsigned int color_attr,
ARegion *ar, int x, int y,
float stepx, float stepy, const float color[3])
{
float x1, y1;
UI_view2d_view_to_region_fl(&ar->v2d, x, y, &x1, &y1);
int gridpos[5][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
for(int i = 0; i < 4; i++) {
immAttrib3fv(color_attr, color);
immVertex2f(pos_attr, x1 + gridpos[i][0]*stepx, y1 + gridpos[i][1]*stepy);
immAttrib3fv(color_attr, color);
immVertex2f(pos_attr, x1 + gridpos[i+1][0]*stepx, y1 + gridpos[i+1][1]*stepy);
}
}
static void draw_image_tiles(ARegion *ar, SpaceImage *sima, Image *ima)
{
int num_tiles;
if (ima) {
num_tiles = BLI_listbase_count(&ima->tiles);
}
else {
num_tiles = sima->tile_grid_shape[0] * sima->tile_grid_shape[1];
}
float stepx = BLI_rcti_size_x(&ar->v2d.mask) / BLI_rctf_size_x(&ar->v2d.cur);
float stepy = BLI_rcti_size_y(&ar->v2d.mask) / BLI_rctf_size_y(&ar->v2d.cur);
GPUVertFormat *format = immVertexFormat();
unsigned int pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
unsigned color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
immBegin(GPU_PRIM_LINES, 8*(num_tiles + 1));
float theme_color[3], selected_color[3];
UI_GetThemeColorShade3fv(TH_BACK, 60.0f, theme_color);
UI_GetThemeColor3fv(TH_FACE_SELECT, selected_color);
if (ima) {
LISTBASE_FOREACH(ImageTile*, tile, &ima->tiles) {
int x = tile->tile_number % 10;
int y = tile->tile_number / 10;
draw_udim_tile_grid(pos, color, ar, x, y, stepx, stepy, theme_color);
}
}
else {
for (int y = 0; y < sima->tile_grid_shape[1]; y++) {
for (int x = 0; x < sima->tile_grid_shape[0]; x++) {
draw_udim_tile_grid(pos, color, ar, x, y, stepx, stepy, theme_color);
}
}
}
int cur_x = sima->curtile % 10, cur_y = sima->curtile / 10;
draw_udim_tile_grid(pos, color, ar, cur_x, cur_y, stepx, stepy, selected_color);
immEnd();
immUnbindProgram();
return;
}
/* draw main image region */
void draw_image_main(const bContext *C, ARegion *ar)
@@ -692,14 +778,35 @@ void draw_image_main(const bContext *C, ARegion *ar)
BKE_image_multiview_index(ima, &sima->iuser);
}
ibuf = ED_space_image_acquire_buffer(sima, &lock);
ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
int main_w = 0;
int main_h = 0;
/* draw the image or grid */
if (ibuf == NULL) {
ED_region_grid_draw(ar, zoomx, zoomy);
if (ima) {
LISTBASE_FOREACH(ImageTile*, tile, &ima->tiles) {
int x = tile->tile_number % 10;
int y = tile->tile_number / 10;
ED_region_grid_draw(ar, zoomx, zoomy, x, y);
}
}
else {
for (int y = 0; y < sima->tile_grid_shape[1]; y++) {
for (int x = 0; x < sima->tile_grid_shape[0]; x++) {
ED_region_grid_draw(ar, zoomx, zoomy, x, y);
}
}
}
}
else {
draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy);
main_w = ibuf->x;
main_h = ibuf->y;
char label[64];
BKE_image_get_tile_label(ima, 0, label, sizeof(label));
draw_image_buffer(C, sima, ar, scene, ibuf, 0.0f, 0.0f, zoomx, zoomy, label);
if (sima->flag & SI_DRAW_METADATA) {
int x, y;
@@ -714,6 +821,28 @@ void draw_image_main(const bContext *C, ARegion *ar)
ED_space_image_release_buffer(sima, ibuf, lock);
if (ima && ima->source == IMA_SRC_TILED) {
LISTBASE_FOREACH(ImageTile*, tile, &ima->tiles) {
if (tile->tile_number == 0)
continue;
ibuf = ED_space_image_acquire_buffer(sima, &lock, tile->tile_number);
if (ibuf) {
int x_pos = tile->tile_number % 10;
int y_pos = tile->tile_number / 10;
char label[64];
BKE_image_get_tile_label(ima, tile, label, sizeof(label));
float tile_zoomx = (zoomx * main_w) / ibuf->x;
float tile_zoomy = (zoomy * main_h) / ibuf->y;
draw_image_buffer(C, sima, ar, scene, ibuf, x_pos, y_pos, tile_zoomx, tile_zoomy, label);
}
ED_space_image_release_buffer(sima, ibuf, lock);
}
}
draw_image_tiles(ar, sima, ima);
/* paint helpers */
if (show_paint)
draw_image_paint_helpers(C, ar, scene, zoomx, zoomy);

View File

@@ -105,7 +105,7 @@ void ED_space_image_set_mask(bContext *C, SpaceImage *sima, Mask *mask)
}
}
ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock)
ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock, int tile)
{
ImBuf *ibuf;
@@ -115,7 +115,9 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock)
return BIF_render_spare_imbuf();
else
#endif
sima->iuser.tile = tile;
ibuf = BKE_image_acquire_ibuf(sima->image, &sima->iuser, r_lock);
sima->iuser.tile = 0;
if (ibuf) {
if (ibuf->rect || ibuf->rect_float)
@@ -142,7 +144,7 @@ bool ED_space_image_has_buffer(SpaceImage *sima)
void *lock;
bool has_buffer;
ibuf = ED_space_image_acquire_buffer(sima, &lock);
ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
has_buffer = (ibuf != NULL);
ED_space_image_release_buffer(sima, ibuf, lock);
@@ -155,7 +157,8 @@ void ED_space_image_get_size(SpaceImage *sima, int *width, int *height)
ImBuf *ibuf;
void *lock;
ibuf = ED_space_image_acquire_buffer(sima, &lock);
/* TODO(lukas): Support tiled images with different sizes */
ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
if (ibuf && ibuf->x > 0 && ibuf->y > 0) {
*width = ibuf->x;

View File

@@ -97,6 +97,11 @@ void IMAGE_OT_read_viewlayers(struct wmOperatorType *ot);
void IMAGE_OT_render_border(struct wmOperatorType *ot);
void IMAGE_OT_clear_render_border(struct wmOperatorType *ot);
void IMAGE_OT_add_tile(struct wmOperatorType *ot);
void IMAGE_OT_remove_tile(struct wmOperatorType *ot);
void IMAGE_OT_fill_tile(struct wmOperatorType *ot);
void IMAGE_OT_select_tile(struct wmOperatorType *ot);
/* image_panels.c */
struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
void image_buttons_register(struct ARegionType *art);

View File

@@ -45,6 +45,9 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_string_utf8.h"
#include "BLI_fileops.h"
#include "BLI_fileops_types.h"
#include "BLI_linklist.h"
#include "BLT_translation.h"
@@ -223,7 +226,7 @@ static bool space_image_file_exists_poll(bContext *C)
bool ret = false;
char name[FILE_MAX];
ibuf = ED_space_image_acquire_buffer(sima, &lock);
ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
if (ibuf) {
BLI_strncpy(name, ibuf->name, FILE_MAX);
BLI_path_abs(name, BKE_main_blendfile_path(bmain));
@@ -1150,6 +1153,52 @@ static int image_cmp_frame(const void *a, const void *b)
return 0;
}
static int image_get_udim(const char *filepath, LinkNodePair *udim_tiles)
{
if (strstr(filepath, "1001") == NULL) {
return 0;
}
char filename[FILE_MAX], dirname[FILE_MAXDIR];
BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
bool is_udim = true;
int max_udim = 0;
unsigned short digits;
char base_head[FILE_MAX], base_tail[FILE_MAX];
int id = BLI_stringdec(filename, base_head, base_tail, &digits);
if (id == 1001) {
struct direntry *dir;
uint totfile = BLI_filelist_dir_contents(dirname, &dir);
for (int i = 0; i < totfile; i++) {
if (!(dir[i].type & S_IFREG)) {
continue;
}
char head[FILE_MAX], tail[FILE_MAX];
id = BLI_stringdec(dir[i].relname, head, tail, &digits);
if (digits > 4 ||
!(STREQLEN(base_head, head, FILE_MAX)) ||
!(STREQLEN(base_tail, tail, FILE_MAX))) {
continue;
}
if (id < 1001 || id >= 2000) {
is_udim = false;
break;
}
BLI_linklist_append(udim_tiles, SET_INT_IN_POINTER(id - 1001));
max_udim = max_ii(max_udim, id);
}
BLI_filelist_free(dir, totfile);
}
return is_udim? (max_udim - 1001) : 0;
}
/**
* Return the start (offset) and the length of the sequence of continuous frames in the list of frames
*
@@ -1157,21 +1206,27 @@ static int image_cmp_frame(const void *a, const void *b)
* \param ofs: [out] offset the first frame number in the sequence.
* \return the number of contiguous frames in the sequence
*/
static int image_sequence_get_len(ListBase *frames, int *ofs)
static int image_sequence_get_len(ImageFrameRange *frame_range, int *ofs, LinkNodePair *udim_tiles)
{
ImageFrame *frame;
BLI_listbase_sort(frames, image_cmp_frame);
BLI_listbase_sort(&frame_range->frames, image_cmp_frame);
frame = frames->first;
frame = frame_range->frames.first;
if (frame) {
int frame_curr = frame->framenr;
(*ofs) = frame_curr;
while (frame && (frame->framenr == frame_curr)) {
frame_curr++;
frame = frame->next;
if (udim_tiles && (frame_curr == 1001)) {
return 1 + image_get_udim(frame_range->filepath, udim_tiles);
}
else {
while (frame && (frame->framenr == frame_curr)) {
frame_curr++;
frame = frame->next;
}
return frame_curr - (*ofs);
}
return frame_curr - (*ofs);
}
*ofs = 0;
return 0;
@@ -1179,7 +1234,8 @@ static int image_sequence_get_len(ListBase *frames, int *ofs)
static Image *image_open_single(
Main *bmain, wmOperator *op, const char *filepath, const char *relbase,
bool is_relative_path, bool use_multiview, int frame_seq_len)
bool is_relative_path, bool use_multiview, int frame_seq_len,
int frame_seq_ofs, LinkNodePair *udim_tiles)
{
bool exists = false;
Image *ima = NULL;
@@ -1215,7 +1271,15 @@ static Image *image_open_single(
}
if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) {
ima->source = IMA_SRC_SEQUENCE;
if (udim_tiles && frame_seq_ofs == 1001) {
ima->source = IMA_SRC_TILED;
for (LinkNode *node = udim_tiles->list; node; node = node->next) {
BKE_image_add_tile(ima, GET_INT_FROM_POINTER(node->link), NULL);
}
}
else {
ima->source = IMA_SRC_SEQUENCE;
}
}
}
@@ -1238,6 +1302,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
const bool use_udim = RNA_boolean_get(op->ptr, "use_udim");
if (!op->customdata)
image_open_init(C, op);
@@ -1254,7 +1319,9 @@ static int image_open_exec(bContext *C, wmOperator *op)
image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all);
for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range; frame_range = frame_range->next) {
int frame_range_ofs;
int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs);
LinkNodePair udim_tiles = {NULL};
int frame_range_seq_len = image_sequence_get_len(frame_range, &frame_range_ofs,
use_udim? &udim_tiles : NULL);
BLI_freelistN(&frame_range->frames);
char filepath_range[FILE_MAX];
@@ -1266,7 +1333,10 @@ static int image_open_exec(bContext *C, wmOperator *op)
Image *ima_range = image_open_single(
bmain, op, filepath_range, BKE_main_blendfile_path(bmain),
is_relative_path, use_multiview, frame_range_seq_len);
is_relative_path, use_multiview, frame_range_seq_len, frame_range_ofs,
use_udim? &udim_tiles : NULL);
BLI_linklist_free(udim_tiles.list, NULL);
/* take the first image */
if ((ima == NULL) && ima_range) {
@@ -1278,10 +1348,17 @@ static int image_open_exec(bContext *C, wmOperator *op)
BLI_freelistN(&frame_ranges_all);
}
else {
int sequence_len = 1;
LinkNodePair udim_tiles = {NULL};
if (use_udim) {
sequence_len = image_get_udim(filepath, &udim_tiles);
}
/* for drag & drop etc. */
ima = image_open_single(
bmain, op, filepath, BKE_main_blendfile_path(bmain),
is_relative_path, use_multiview, 1);
is_relative_path, use_multiview, 1, sequence_len, &udim_tiles);
BLI_linklist_free(udim_tiles.list, NULL);
}
if (ima == NULL) {
@@ -1331,7 +1408,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
/* initialize because of new image */
if (iuser) {
iuser->frames = frame_seq_len;
iuser->frames = (ima->source == IMA_SRC_SEQUENCE)? frame_seq_len : 1;
iuser->sfra = 1;
iuser->framenr = 1;
if (ima->source == IMA_SRC_MOVIE) {
@@ -1464,6 +1541,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_sequence_detection", true, "Detect Sequences",
"Automatically detect animated sequences in selected images (based on file names)");
RNA_def_boolean(ot->srna, "use_udim", true, "Detect UDIMs", "Detect selected UDIM files and load all matching tiles");
}
/******************** Match movie length operator ********************/
@@ -1630,7 +1708,7 @@ static int save_image_options_init(Main *bmain, SaveImageOptions *simopts, Space
const bool guess_path, const bool save_as_render)
{
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
if (ibuf) {
Image *ima = sima->image;
@@ -1698,6 +1776,11 @@ static int save_image_options_init(Main *bmain, SaveImageOptions *simopts, Space
BLI_snprintf(simopts->filepath, sizeof(simopts->filepath), "//%s", ima->id.name + 2);
BLI_path_abs(simopts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
/* append UDIM numbering if not present */
if (ima->source == IMA_SRC_TILED && (BLI_stringdec(ima->name, NULL, NULL, NULL) != 1001)) {
strncat(simopts->filepath, ".1001", sizeof(simopts->filepath) - 6);
}
}
/* color management */
@@ -1811,18 +1894,16 @@ static void save_imbuf_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
* \note ``ima->name`` and ``ibuf->name`` should end up the same.
* \note for multiview the first ``ibuf`` is important to get the settings.
*/
static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, bool do_newpath)
static bool save_image_single(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, bool do_newpath, int tile)
{
Main *bmain = CTX_data_main(C);
Image *ima = ED_space_image(sima);
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
Scene *scene;
RenderResult *rr = NULL;
bool ok = false;
WM_cursor_wait(1);
if (ibuf) {
ImBuf *colormanaged_ibuf = NULL;
const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id);
@@ -2036,11 +2117,49 @@ cleanup:
BKE_image_release_renderresult(scene, ima);
}
WM_cursor_wait(0);
return ok;
}
static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, bool do_newpath)
{
Image *ima = ED_space_image(sima);
if (ima->source == IMA_SRC_TILED) {
if (BLI_stringdec(simopts->filepath, NULL, NULL, NULL) != 1001) {
BKE_reportf(op->reports, RPT_ERROR,
"When saving a tiled image, the path '%s' must contain the UDIM tag 1001", simopts->filepath);
return false;
}
}
WM_cursor_wait(1);
if (!save_image_single(C, sima, op, simopts, do_newpath, 0)) {
WM_cursor_wait(0);
return false;
}
if (ima->source == IMA_SRC_TILED) {
char filepath[FILE_MAX];
BLI_strncpy(filepath, simopts->filepath, sizeof(filepath));
LISTBASE_FOREACH(ImageTile*, tile, &ima->tiles) {
if (tile->tile_number == 0)
continue;
char head[FILE_MAX], tail[FILE_MAX];
unsigned short numlen;
BLI_stringdec(filepath, head, tail, &numlen);
BLI_stringenc(simopts->filepath, head, tail, numlen, 1001 + tile->tile_number);
save_image_single(C, sima, op, simopts, do_newpath, tile->tile_number);
}
BLI_strncpy(simopts->filepath, filepath, sizeof(simopts->filepath));
}
WM_cursor_wait(0);
return true;
}
static void image_save_as_free(wmOperator *op)
{
if (op->customdata) {
@@ -2258,7 +2377,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
if (sima->image == NULL)
return OPERATOR_CANCELLED;
if (sima->image->source != IMA_SRC_SEQUENCE) {
if (ELEM(sima->image->source, IMA_SRC_SEQUENCE, IMA_SRC_TILED)) {
BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences");
return OPERATOR_CANCELLED;
}
@@ -2441,11 +2560,12 @@ static int image_new_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "color", color);
alpha = RNA_boolean_get(op->ptr, "alpha");
stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
bool tiled = RNA_boolean_get(op->ptr, "tiled");
if (!alpha)
color[3] = 1.0f;
ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d, tiled);
if (!ima) {
image_new_free(op);
@@ -2529,6 +2649,9 @@ static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
uiItemL(col[0], "", ICON_NONE);
uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
uiItemL(col[0], "", ICON_NONE);
uiItemR(col[1], &ptr, "tiled", 0, NULL, ICON_NONE);
#if 0
if (is_multiview) {
uiItemL(col[0], "", ICON_NONE);
@@ -2577,6 +2700,8 @@ void IMAGE_OT_new(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_boolean(ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
prop = RNA_def_boolean(ot->srna, "tiled", 0, "Tiled", "Create a tiled image");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
#undef IMA_DEF_NAME
@@ -2704,7 +2829,7 @@ static bool image_pack_test(bContext *C, wmOperator *op)
if (!as_png && BKE_image_has_packedfile(ima))
return 0;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported");
return 0;
}
@@ -2805,7 +2930,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op)
if (!ima || !BKE_image_has_packedfile(ima))
return OPERATOR_CANCELLED;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
return OPERATOR_CANCELLED;
}
@@ -2833,7 +2958,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
if (!ima || !BKE_image_has_packedfile(ima))
return OPERATOR_CANCELLED;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_TILED)) {
BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
return OPERATOR_CANCELLED;
}
@@ -2903,9 +3028,12 @@ static void image_sample_draw(const bContext *C, ARegion *ar, void *arg_info)
/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], float r_col[3])
{
float uv[2];
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &uv[0], &uv[1]);
int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
float fx, fy;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
bool ret = false;
if (ibuf == NULL) {
@@ -2913,12 +3041,10 @@ bool ED_space_image_color_sample(SpaceImage *sima, ARegion *ar, int mval[2], flo
return false;
}
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fx, &fy);
if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
const float *fp;
unsigned char *cp;
int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
CLAMP(y, 0, ibuf->y - 1);
@@ -2944,10 +3070,15 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
{
SpaceImage *sima = CTX_wm_space_image(C);
ARegion *ar = CTX_wm_region(C);
Image *image = ED_space_image(sima);
float uv[2];
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &uv[0], &uv[1]);
int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
ImageSampleInfo *info = op->customdata;
float fx, fy;
Scene *scene = CTX_data_scene(C);
CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
@@ -2957,13 +3088,10 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
return;
}
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
const float *fp;
unsigned char *cp;
int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
Image *image = ED_space_image(sima);
int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
CLAMP(y, 0, ibuf->y - 1);
@@ -3171,11 +3299,28 @@ static int image_sample_line_exec(bContext *C, wmOperator *op)
int x_end = RNA_int_get(op->ptr, "xend");
int y_end = RNA_int_get(op->ptr, "yend");
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
Histogram *hist = &sima->sample_line_hist;
float x1f, y1f, x2f, y2f;
UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
/* If the image has tiles, shift the positions accordingly. */
Image *image = ED_space_image(sima);
int tile = 0, ix = 0, iy = 0;
if (image && image->source == IMA_SRC_TILED) {
ix = (int) x1f;
iy = (int) y1f;
CLAMP(ix, 0, 9);
x1f -= ix;
x2f -= ix;
y1f -= iy;
y2f -= iy;
tile = 10*iy + ix;
}
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
Histogram *hist = &sima->sample_line_hist;
if (ibuf == NULL) {
ED_space_image_release_buffer(sima, ibuf, lock);
@@ -3187,13 +3332,12 @@ static int image_sample_line_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
hist->co[0][0] = x1f;
hist->co[0][1] = y1f;
hist->co[1][0] = x2f;
hist->co[1][1] = y2f;
hist->draw_offset[0] = ix;
hist->draw_offset[1] = iy;
/* enable line drawing */
hist->flag |= HISTO_FLAG_SAMPLELINE;
@@ -3807,3 +3951,227 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************* Add tile operator ****************** */
static bool add_tile_poll(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
return (ima && ima->source == IMA_SRC_TILED && (BKE_image_get_tile(ima, sima->curtile) == NULL));
}
static int add_tile_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = ED_space_image(sima);
if (BKE_image_add_tile(ima, sima->curtile, NULL) == NULL)
return OPERATOR_CANCELLED;
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
return OPERATOR_FINISHED;
}
void IMAGE_OT_add_tile(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add tile";
ot->description = "Adds a tile to the image";
ot->idname = "IMAGE_OT_add_tile";
/* api callbacks */
ot->poll = add_tile_poll;
ot->exec = add_tile_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************* Remove tile operator ****************** */
static bool remove_tile_poll(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
return (ima && ima->source == IMA_SRC_TILED && BKE_image_get_tile(ima, sima->curtile));
}
static int remove_tile_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = ED_space_image(sima);
ImageTile *tile = BKE_image_get_tile(ima, sima->curtile);
if (!BKE_image_remove_tile(ima, tile))
return OPERATOR_CANCELLED;
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
return OPERATOR_FINISHED;
}
void IMAGE_OT_remove_tile(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove tile";
ot->description = "Removes a tile from the image";
ot->idname = "IMAGE_OT_remove_tile";
/* api callbacks */
ot->poll = remove_tile_poll;
ot->exec = remove_tile_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************* Fill tile operator ****************** */
static bool fill_tile_poll(bContext *C)
{
Image *ima = CTX_data_edit_image(C);
SpaceImage *sima = CTX_wm_space_image(C);
return (ima && ima->source == IMA_SRC_TILED && BKE_image_get_tile(ima, sima->curtile));
}
static int fill_tile_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = ED_space_image(sima);
float color[4];
RNA_float_get_array(op->ptr, "color", color);
int gen_type = RNA_enum_get(op->ptr, "generated_type");
int width = RNA_int_get(op->ptr, "width");
int height = RNA_int_get(op->ptr, "height");
ImageTile *tile = BKE_image_get_tile(ima, sima->curtile);
if (!BKE_image_fill_tile(ima, tile, width, height, color, gen_type))
return OPERATOR_CANCELLED;
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
return OPERATOR_FINISHED;
}
static int fill_tile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = ED_space_image(sima);
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
if (ibuf) {
RNA_int_set(op->ptr, "width", ibuf->x);
RNA_int_set(op->ptr, "height", ibuf->y);
BKE_image_release_ibuf(ima, ibuf, NULL);
}
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
}
static void fill_tile_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *split, *col[2];
uiLayout *layout = op->layout;
PointerRNA ptr;
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
/* copy of WM_operator_props_dialog_popup() layout */
split = uiLayoutSplit(layout, 0.5f, false);
col[0] = uiLayoutColumn(split, false);
col[1] = uiLayoutColumn(split, false);
uiItemL(col[0], IFACE_("Color"), ICON_NONE);
uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
uiItemL(col[0], IFACE_("Width"), ICON_NONE);
uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
uiItemL(col[0], IFACE_("Height"), ICON_NONE);
uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
}
void IMAGE_OT_fill_tile(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Fill tile";
ot->description = "Fill the current tile with a generated image";
ot->idname = "IMAGE_OT_fill_tile";
/* api callbacks */
ot->poll = fill_tile_poll;
ot->exec = fill_tile_exec;
ot->invoke = fill_tile_invoke;
ot->ui = fill_tile_draw;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
prop = RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
RNA_def_property_float_array_default(prop, default_color);
RNA_def_enum(ot->srna, "generated_type", rna_enum_image_generated_type_items, IMA_GENTYPE_BLANK,
"Generated Type", "Fill the image with a grid for UV map testing");
prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
RNA_def_property_subtype(prop, PROP_PIXEL);
prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
RNA_def_property_subtype(prop, PROP_PIXEL);
}
/* ********************* Select tile operator ****************** */
static bool image_select_tile_poll(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
if (ima) {
return (ima->source == IMA_SRC_TILED);
}
else {
return (sima->tile_grid_shape[0] > 1) || (sima->tile_grid_shape[1] > 1);
}
}
static int image_select_tile_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
SpaceImage *sima = CTX_wm_space_image(C);
ARegion *ar = CTX_wm_region(C);
float uv[2];
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &uv[0], &uv[1]);
if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 10.0f) {
int tx = (int) uv[0];
int ty = (int) uv[1];
sima->curtile = 10*ty + tx;
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
}
void IMAGE_OT_select_tile(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select tile";
ot->idname = "IMAGE_OT_select_tile";
ot->description = "Use mouse to select a tile of the image";
/* api callbacks */
ot->invoke = image_select_tile_invoke;
ot->poll = image_select_tile_poll;
}

View File

@@ -183,6 +183,9 @@ static SpaceLink *image_new(const ScrArea *UNUSED(area), const Scene *UNUSED(sce
scopes_new(&simage->scopes);
simage->sample_line_hist.height = 100;
simage->tile_grid_shape[0] = 1;
simage->tile_grid_shape[1] = 1;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for image");
@@ -289,6 +292,11 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_read_viewlayers);
WM_operatortype_append(IMAGE_OT_render_border);
WM_operatortype_append(IMAGE_OT_clear_render_border);
WM_operatortype_append(IMAGE_OT_add_tile);
WM_operatortype_append(IMAGE_OT_remove_tile);
WM_operatortype_append(IMAGE_OT_fill_tile);
WM_operatortype_append(IMAGE_OT_select_tile);
}
static void image_keymap(struct wmKeyConfig *keyconf)
@@ -355,6 +363,7 @@ static void image_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "IMAGE_OT_sample", ACTIONMOUSE, KM_PRESS, 0, 0);
RNA_enum_set(WM_keymap_add_item(keymap, "IMAGE_OT_curves_point_set", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "point", 0);
RNA_enum_set(WM_keymap_add_item(keymap, "IMAGE_OT_curves_point_set", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "point", 1);
WM_keymap_add_item(keymap, "IMAGE_OT_select_tile", ACTIONMOUSE, KM_PRESS, KM_ALT, 0);
/* toggle editmode is handy to have while UV unwrapping */
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_mode_set", TABKEY, KM_PRESS, 0, 0);
@@ -929,7 +938,8 @@ static void image_tools_region_draw(const bContext *C, ARegion *ar)
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
/* TODO(lukas): Support tiles in scopes? */
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
/* XXX performance regression if name of scopes category changes! */
PanelCategoryStack *category = UI_panel_category_active_find(ar, "Scopes");

View File

@@ -220,7 +220,7 @@ GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
GPUNodeLink *GPU_uniform(float *num);
GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data);
GPUNodeLink *GPU_uniform_buffer(float *num, GPUType gputype);
GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data);
GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data, int tile);
GPUNodeLink *GPU_cube_map(struct Image *ima, struct ImageUser *iuser, bool is_data);
GPUNodeLink *GPU_image_preview(struct PreviewImage *prv);
GPUNodeLink *GPU_texture(int size, float *pixels);

View File

@@ -515,17 +515,19 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
}
/* assign only one texid per buffer to avoid sampling the same texture twice */
static void codegen_set_texid(GHash *bindhash, GPUInput *input, int *texid, void *key)
static void codegen_set_texid(GHash *bindhash, GPUInput *input, int *texid, void *key1, int key2)
{
if (BLI_ghash_haskey(bindhash, key)) {
GHashPair pair = {key1, SET_INT_IN_POINTER(key2 << 16)};
if (BLI_ghash_haskey(bindhash, &pair)) {
/* Reuse existing texid */
input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, key));
input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, &pair));
}
else {
/* Allocate new texid */
input->texid = *texid;
(*texid)++;
input->bindtex = true;
void *key = BLI_ghashutil_pairalloc(key1, SET_INT_IN_POINTER(key2));
BLI_ghash_insert(bindhash, key, SET_INT_IN_POINTER(input->texid));
}
}
@@ -538,7 +540,7 @@ static void codegen_set_unique_ids(ListBase *nodes)
GPUOutput *output;
int id = 1, texid = 0;
bindhash = BLI_ghash_ptr_new("codegen_set_unique_ids1 gh");
bindhash = BLI_ghash_pair_new("codegen_set_unique_ids1 gh");
definehash = BLI_ghash_ptr_new("codegen_set_unique_ids2 gh");
for (node = nodes->first; node; node = node->next) {
@@ -556,19 +558,19 @@ static void codegen_set_unique_ids(ListBase *nodes)
* the same texture twice */
if (input->link) {
/* input is texture from buffer */
codegen_set_texid(bindhash, input, &texid, input->link);
codegen_set_texid(bindhash, input, &texid, input->link, 0);
}
else if (input->ima) {
/* input is texture from image */
codegen_set_texid(bindhash, input, &texid, input->ima);
codegen_set_texid(bindhash, input, &texid, input->ima, input->image_tile);
}
else if (input->prv) {
/* input is texture from preview render */
codegen_set_texid(bindhash, input, &texid, input->prv);
codegen_set_texid(bindhash, input, &texid, input->prv, 0);
}
else if (input->tex) {
/* input is user created texture, check tex pointer */
codegen_set_texid(bindhash, input, &texid, input->tex);
codegen_set_texid(bindhash, input, &texid, input->tex, 0);
}
/* make sure this pixel is defined exactly once */
@@ -594,7 +596,7 @@ static void codegen_set_unique_ids(ListBase *nodes)
output->id = id++;
}
BLI_ghash_free(bindhash, NULL, NULL);
BLI_ghash_free(bindhash, BLI_ghashutil_pairfree, NULL);
BLI_ghash_free(definehash, NULL, NULL);
}
@@ -1355,6 +1357,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
input->ima = link->ptr1;
input->iuser = link->ptr2;
input->image_isdata = link->image_isdata;
input->image_tile = link->val1;
input->textarget = GL_TEXTURE_2D;
input->textype = GPU_TEX2D;
}
@@ -1652,13 +1655,14 @@ GPUNodeLink *GPU_uniform_buffer(float *num, GPUType gputype)
return link;
}
GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data)
GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data, int tile)
{
GPUNodeLink *link = GPU_node_link_create();
link->image = GPU_NODE_LINK_IMAGE_BLENDER;
link->ptr1 = ima;
link->ptr2 = iuser;
link->val1 = tile;
link->image_isdata = is_data;
return link;

View File

@@ -93,6 +93,7 @@ struct GPUNodeLink {
int texturesize;
void *ptr1, *ptr2;
int val1;
bool dynamic;
GPUDynamicType dynamictype;
@@ -137,6 +138,7 @@ typedef struct GPUInput {
struct Image *ima; /* image */
struct ImageUser *iuser; /* image user */
int image_tile; /* image tile */
struct PreviewImage *prv; /* preview images & icons */
bool image_isdata; /* image does not contain color data */
float *dynamicvec; /* vector data in case it is dynamic */

View File

@@ -224,16 +224,6 @@ float GPU_get_anisotropic(void)
/* Set OpenGL state for an MTFace */
static GPUTexture **gpu_get_image_gputexture(Image *ima, GLenum textarget)
{
if (textarget == GL_TEXTURE_2D)
return &ima->gputexture[TEXTARGET_TEXTURE_2D];
else if (textarget == GL_TEXTURE_CUBE_MAP)
return &ima->gputexture[TEXTARGET_TEXTURE_CUBE_MAP];
return NULL;
}
typedef struct VerifyThreadData {
ImBuf *ibuf;
float *srgb_frect;
@@ -301,18 +291,22 @@ GPUTexture *GPU_texture_from_blender(
return NULL;
}
int gputex_type = (textarget == GL_TEXTURE_CUBE_MAP)? TEXTARGET_TEXTURE_CUBE_MAP : TEXTARGET_TEXTURE_2D;
ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
/* Test if we already have a texture. */
GPUTexture **tex = gpu_get_image_gputexture(ima, textarget);
if (*tex) {
return *tex;
GPUTexture *tex = tile->gputexture[gputex_type];
if (tex) {
return tex;
}
/* Check if we have a valid image. If not, we return a dummy
* texture with zero bindcode so we don't keep trying. */
unsigned int bindcode = 0;
if (ima->ok == 0) {
*tex = GPU_texture_from_bindcode(textarget, bindcode);
return *tex;
if (tile->ok == 0) {
tex = GPU_texture_from_bindcode(textarget, bindcode);
tile->gputexture[gputex_type] = tex;
return tex;
}
/* currently, tpage refresh is used by ima sequences */
@@ -324,8 +318,9 @@ GPUTexture *GPU_texture_from_blender(
/* check if we have a valid image buffer */
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (ibuf == NULL) {
*tex = GPU_texture_from_bindcode(textarget, bindcode);
return *tex;
tex = GPU_texture_from_bindcode(textarget, bindcode);
tile->gputexture[gputex_type] = tex;
return tex;
}
/* flag to determine whether deep format is used */
@@ -393,8 +388,9 @@ GPUTexture *GPU_texture_from_blender(
BKE_image_release_ibuf(ima, ibuf, NULL);
*tex = GPU_texture_from_bindcode(textarget, bindcode);
return *tex;
tex = GPU_texture_from_bindcode(textarget, bindcode);
tile->gputexture[gputex_type] = tex;
return tex;
}
static void **gpu_gen_cube_map(unsigned int *rect, float *frect, int rectw, int recth, bool use_high_bit_depth)
@@ -703,44 +699,43 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
if (mipmap) {
for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
if (BKE_image_has_opengl_texture(ima)) {
bool has_gputexture = false;
LISTBASE_FOREACH(ImageTile *, tile, &ima->tiles) {
if (ima->tpageflag & IMA_MIPMAP_COMPLETE) {
if (ima->gputexture[TEXTARGET_TEXTURE_2D]) {
GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
if (tex) {
GPU_texture_bind(tex, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
GPU_texture_unbind(tex);
}
}
else
GPU_free_image(ima);
}
else
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
if (!has_gputexture) GPU_free_image(ima);
}
}
else {
for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
if (BKE_image_has_opengl_texture(ima)) {
if (ima->gputexture[TEXTARGET_TEXTURE_2D]) {
GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
LISTBASE_FOREACH(ImageTile *, tile, &ima->tiles) {
GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
if (tex) {
GPU_texture_bind(tex, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
GPU_texture_unbind(tex);
}
}
else
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
}
}
/* check if image has been downscaled and do scaled partial update */
static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, ImageTile *tile, float *frect, int x, int y, int w, int h)
{
if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) {
GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
int x_limit = smaller_power_of_2_limit(ibuf->x);
int y_limit = smaller_power_of_2_limit(ibuf->y);
@@ -760,7 +755,7 @@ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
if (rectw + x > x_limit) rectw--;
if (recth + y > y_limit) recth--;
GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
GPU_texture_bind(tex, 0);
/* float rectangles are already continuous in memory so we can use IMB_scaleImBuf */
if (frect) {
@@ -802,7 +797,7 @@ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
GPU_texture_unbind(tex);
return true;
}
@@ -813,9 +808,11 @@ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
if ((!GTS.gpu_mipmap && GPU_get_mipmap()) ||
(ima->gputexture[TEXTARGET_TEXTURE_2D] == NULL) ||
(tex == NULL) ||
(ibuf == NULL) ||
(w == 0) || (h == 0))
{
@@ -833,13 +830,13 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0;
IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data);
if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
if (gpu_check_scaled_image(ibuf, ima, tile, buffer, x, y, w, h)) {
MEM_freeN(buffer);
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
GPU_texture_bind(tex, 0);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, buffer);
MEM_freeN(buffer);
@@ -853,18 +850,18 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
GPU_texture_unbind(tex);
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
if (gpu_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
if (gpu_check_scaled_image(ibuf, ima, tile, NULL, x, y, w, h)) {
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
GPU_texture_bind(ima->gputexture[TEXTARGET_TEXTURE_2D], 0);
GPU_texture_bind(tex, 0);
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
@@ -890,7 +887,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
GPU_texture_unbind(ima->gputexture[TEXTARGET_TEXTURE_2D]);
GPU_texture_unbind(tex);
}
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -1077,11 +1074,14 @@ void GPU_free_image(Image *ima)
return;
}
for (int i = 0; i < TEXTARGET_COUNT; i++) {
/* free glsl image binding */
if (ima->gputexture[i]) {
GPU_texture_free(ima->gputexture[i]);
ima->gputexture[i] = NULL;
LISTBASE_FOREACH(ImageTile *, tile, &ima->tiles) {
for (int i = 0; i < TEXTARGET_COUNT; i++) {
/* free glsl image binding */
GPUTexture *tex = tile->gputexture[i];
if (tex) {
GPU_texture_free(tex);
tile->gputexture[i] = NULL;
}
}
}

View File

@@ -1879,6 +1879,67 @@ void node_tex_image_smart(vec3 co, sampler2D ima, out vec4 color, out float alph
node_tex_image_cubic(co, ima, color, alpha);
}
void node_tex_image_tiled_map(vec3 co, out vec4 color, out vec3 map)
{
float tx = floor(co.x);
float ty = floor(co.y);
if (tx < 0 || ty < 0 || tx >= 10)
map = vec3(0, 0, -1);
else
map = vec3(co.x - tx, co.y - ty, 10*ty + tx);
color = vec4(1.0, 0.0, 1.0, 1.0);
}
void node_tex_image_tile_linear(vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
{
if (map.z == tile_id) {
vec3 co = map.xyy;
node_tex_image_linear(co, ima, color, alpha);
}
else {
color = in_color;
alpha = color.a;
}
}
void node_tex_image_tile_nearest(vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
{
if (map.z == tile_id) {
vec3 co = map.xyy;
node_tex_image_nearest(co, ima, color, alpha);
}
else {
color = in_color;
alpha = color.a;
}
}
void node_tex_image_tile_cubic(vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
{
if (map.z == tile_id) {
vec3 co = map.xyy;
node_tex_image_cubic(co, ima, color, alpha);
}
else {
color = in_color;
alpha = color.a;
}
}
void node_tex_image_tile_smart(vec3 map, float tile_id, sampler2D ima, vec4 in_color, out vec4 color, out float alpha)
{
if (map.z == tile_id) {
vec3 co = map.xyy;
node_tex_image_smart(co, ima, color, alpha);
}
else {
color = in_color;
alpha = color.a;
}
}
void tex_box_sample_linear(vec3 texco,
vec3 N,
sampler2D ima,

View File

@@ -60,6 +60,7 @@ void IMB_moviecache_set_priority_callback(struct MovieCache *cache, MovieCacheGe
void IMB_moviecache_put(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf);
bool IMB_moviecache_put_if_possible(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf);
struct ImBuf *IMB_moviecache_get(struct MovieCache *cache, void *userkey);
void IMB_moviecache_remove(struct MovieCache *cache, void *userkey);
bool IMB_moviecache_has_frame(struct MovieCache *cache, void *userkey);
void IMB_moviecache_free(struct MovieCache *cache);

View File

@@ -415,6 +415,14 @@ bool IMB_moviecache_put_if_possible(MovieCache *cache, void *userkey, ImBuf *ibu
return result;
}
void IMB_moviecache_remove(MovieCache *cache, void *userkey)
{
MovieCacheKey key;
key.cache_owner = cache;
key.userkey = userkey;
BLI_ghash_remove(cache->hash, &key, moviecache_keyfree, moviecache_valfree);
}
ImBuf *IMB_moviecache_get(MovieCache *cache, void *userkey)
{
MovieCacheKey key;

View File

@@ -132,6 +132,7 @@ typedef struct Histogram {
/* sample line only */
/* image coords src -> dst */
float co[2][2];
float draw_offset[2];
} Histogram;

View File

@@ -58,6 +58,9 @@ typedef struct ImageUser {
short pass;
short pad;
int tile; /* current tile (for internal use) */
int pad2;
short multi_index, view, layer; /* listbase indices, for menu browsing or retrieve buffer */
short flag;
} ImageUser;
@@ -85,6 +88,21 @@ typedef struct RenderSlot {
struct RenderResult *render;
} RenderSlot;
enum {
TEXTARGET_TEXTURE_2D = 0,
TEXTARGET_TEXTURE_CUBE_MAP = 1,
TEXTARGET_COUNT = 2
};
typedef struct ImageTile {
struct ImageTile *next, *prev;
struct GPUTexture *gputexture[2]; /* TEXTARGET_COUNT */
char ok;
char pad[3];
int tile_number;
char label[64];
} ImageTile;
/* iuser->flag */
#define IMA_ANIM_ALWAYS 1
#define IMA_ANIM_REFRESHED 2
@@ -92,11 +110,6 @@ typedef struct RenderSlot {
#define IMA_NEED_FRAME_RECALC 8
#define IMA_SHOW_STEREO 16
enum {
TEXTARGET_TEXTURE_2D = 0,
TEXTARGET_TEXTURE_CUBE_MAP = 1,
TEXTARGET_COUNT = 2
};
typedef struct Image {
ID id;
@@ -104,7 +117,6 @@ typedef struct Image {
char name[1024]; /* file path, 1024 = FILE_MAX */
struct MovieCache *cache; /* not written in file */
struct GPUTexture *gputexture[2]; /* not written in file 2 = TEXTARGET_COUNT */
/* sources from: */
ListBase anims;
@@ -119,16 +131,17 @@ typedef struct Image {
/* texture page */
short tpageflag;
short pad2;
unsigned int pad3;
short pad3;
int lastused;
ListBase tiles;
struct PackedFile *packedfile DNA_DEPRECATED; /* deprecated */
struct ListBase packedfiles;
struct PreviewImage *preview;
int lastused;
short ok;
short pad4[3];
int pad2;
/* for generated images */
int gen_x, gen_y;

View File

@@ -922,6 +922,8 @@ typedef struct SpaceImage {
int flag;
int tile_grid_shape[2];
MaskSpaceInfo mask_info;
} SpaceImage;

View File

@@ -59,6 +59,7 @@ static const EnumPropertyItem image_source_items[] = {
{IMA_SRC_MOVIE, "MOVIE", 0, "Movie", "Movie file"},
{IMA_SRC_GENERATED, "GENERATED", 0, "Generated", "Generated image"},
{IMA_SRC_VIEWER, "VIEWER", 0, "Viewer", "Compositing node viewer"},
{IMA_SRC_TILED, "TILED", 0, "Tiled", "Tiled image texture"},
{0, NULL, 0, NULL, NULL}
};
@@ -190,6 +191,7 @@ static const EnumPropertyItem *rna_Image_source_itemf(bContext *UNUSED(C), Point
RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_SEQUENCE);
RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_MOVIE);
RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_GENERATED);
RNA_enum_items_add_value(&item, &totitem, image_source_items, IMA_SRC_TILED);
}
RNA_enum_item_end(&item, &totitem);
@@ -279,13 +281,6 @@ static void rna_Image_resolution_set(PointerRNA *ptr, const float *values)
BKE_image_release_ibuf(im, ibuf, lock);
}
static int rna_Image_bindcode_get(PointerRNA *ptr)
{
Image *ima = (Image *)ptr->data;
GPUTexture *tex = ima->gputexture[TEXTARGET_TEXTURE_2D];
return (tex) ? GPU_texture_opengl_bindcode(tex) : 0;
}
static int rna_Image_depth_get(PointerRNA *ptr)
{
Image *im = (Image *)ptr->data;
@@ -491,6 +486,23 @@ static void rna_render_slots_active_index_range(PointerRNA *ptr, int *min, int *
*max = max_ii(0, BLI_listbase_count(&image->renderslots) - 1);
}
static ImageTile *rna_ImageTile_new(Image *image, int tile_number, const char *label)
{
ImageTile *tile = BKE_image_add_tile(image, tile_number, label);
WM_main_add_notifier(NC_IMAGE | ND_DRAW, NULL);
return tile;
}
static void rna_ImageTile_remove(ID *id, ImageTile *tile)
{
Image *image = (Image *)id;
BKE_image_remove_tile(image, tile);
WM_main_add_notifier(NC_IMAGE | ND_DRAW, NULL);
}
#else
static void rna_def_imageuser(BlenderRNA *brna)
@@ -555,6 +567,11 @@ static void rna_def_imageuser(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "view");
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* image_multi_cb */
RNA_def_property_ui_text(prop, "View", "View in multilayer image");
prop = RNA_def_property(srna, "tile", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "tile");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Tile", "Tile in tiled image");
}
/* image.packed_files */
@@ -632,6 +649,56 @@ static void rna_def_render_slots(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
}
static void rna_def_image_tile(BlenderRNA *brna)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "ImageTile", NULL);
RNA_def_struct_ui_text(srna, "Image Tile", "Properties of the image tile");
prop = RNA_def_property(srna, "label", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "label");
RNA_def_property_ui_text(prop, "Label", "Tile label");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
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", "Number of the position that this tile covers");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
func = RNA_def_function(srna, "remove", "rna_ImageTile_remove");
RNA_def_function_ui_description(func, "Remove this tile from the image");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
}
static void rna_def_image_tiles(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
RNA_def_property_srna(cprop, "ImageTiles");
srna = RNA_def_struct(brna, "ImageTiles", NULL);
RNA_def_struct_sdna(srna, "Image");
RNA_def_struct_ui_text(srna, "Image Tiles", "Collection of the image tiles");
func = RNA_def_function(srna, "new", "rna_ImageTile_new");
RNA_def_function_ui_description(func, "Add a tile to the image");
parm = RNA_def_int(func, "tile_number", 1, 1, INT_MAX, "", "Number of the newly created tile", 1, 100);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "label", NULL, 0, "", "Optional label for the tile");
parm = RNA_def_pointer(func, "result", "ImageTile", "", "Newly created image tile");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "get", "BKE_image_get_tile");
RNA_def_function_ui_description(func, "Get a tile based on its tile number");
parm = RNA_def_int(func, "tile_number", 0, 0, INT_MAX, "", "Number of the tile", 1, 100);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "result", "ImageTile", "", "The tile");
RNA_def_function_return(func, parm);
}
static void rna_def_image(BlenderRNA *brna)
{
StructRNA *srna;
@@ -782,18 +849,18 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Display Aspect", "Display Aspect for this image, does not affect rendering");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "bindcode", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_Image_bindcode_get", NULL, NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Bindcode", "OpenGL bindcode");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "render_slots", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "RenderSlot");
RNA_def_property_collection_sdna(prop, NULL, "renderslots", NULL);
RNA_def_property_ui_text(prop, "Render Slots", "Render slots of the image");
rna_def_render_slots(brna, prop);
prop = RNA_def_property(srna, "tiles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "ImageTile");
RNA_def_property_collection_sdna(prop, NULL, "tiles", NULL);
RNA_def_property_ui_text(prop, "Image Tiles", "Tiles of the image");
rna_def_image_tiles(brna, prop);
/*
* Image.has_data and Image.depth are temporary,
* Update import_obj.py when they are replaced (Arystan)
@@ -875,6 +942,7 @@ static void rna_def_image(BlenderRNA *brna)
void RNA_def_image(BlenderRNA *brna)
{
rna_def_render_slot(brna);
rna_def_image_tile(brna);
rna_def_image(brna);
rna_def_imageuser(brna);
rna_def_image_packed_files(brna);

View File

@@ -181,8 +181,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_is_animated(image)) {
BKE_report(reports, RPT_ERROR, "Unpacking movies or image sequences not supported");
else if (BKE_image_has_multiple_ibufs(image)) {
BKE_report(reports, RPT_ERROR, "Unpacking movies, image sequences and tiled images not supported");
return;
}
else {
@@ -220,9 +220,10 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
}
}
static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int filter, int mag)
static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int tile_number, int filter, int mag)
{
GPUTexture *tex = image->gputexture[TEXTARGET_TEXTURE_2D];
ImageTile *tile = BKE_image_get_tile(image, tile_number);
GPUTexture *tex = tile->gputexture[TEXTARGET_TEXTURE_2D];
int error = GL_NO_ERROR;
if (tex)
@@ -231,6 +232,7 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f
ImageUser iuser = {NULL};
iuser.framenr = frame;
iuser.ok = true;
iuser.tile = tile_number;
void *lock;
ImBuf *ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
@@ -259,7 +261,7 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f
glDeleteTextures(1, (GLuint *)&bindcode);
}
else {
image->gputexture[TEXTARGET_TEXTURE_2D] = GPU_texture_from_bindcode(GL_TEXTURE_2D, bindcode);
tile->gputexture[TEXTARGET_TEXTURE_2D] = GPU_texture_from_bindcode(GL_TEXTURE_2D, bindcode);
}
BKE_image_release_ibuf(image, ibuf, lock);
@@ -267,14 +269,15 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f
return error;
}
static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame, int filter, int mag)
static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame, int tile_number, int filter, int mag)
{
int error = GL_NO_ERROR;
BKE_image_tag_time(image);
if (image->gputexture[TEXTARGET_TEXTURE_2D] == NULL)
error = rna_Image_gl_load(image, reports, frame, filter, mag);
ImageTile *tile = BKE_image_get_tile(image, tile_number);
if (tile->gputexture[TEXTARGET_TEXTURE_2D] == NULL)
error = rna_Image_gl_load(image, reports, frame, tile_number, filter, mag);
return error;
}
@@ -359,6 +362,8 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(func, "frame", 0, 0, INT_MAX, "Frame",
"Frame of image sequence or movie", 0, INT_MAX);
RNA_def_int(func, "tile_number", 0, 0, INT_MAX, "Tile",
"Tile of a tiled image", 0, INT_MAX);
RNA_def_int(func, "filter", GL_LINEAR_MIPMAP_NEAREST, -INT_MAX, INT_MAX, "Filter",
"The texture minifying function to use if the image wasn't loaded", -INT_MAX, INT_MAX);
RNA_def_int(func, "mag", GL_LINEAR, -INT_MAX, INT_MAX, "Magnification",
@@ -372,6 +377,8 @@ void RNA_api_image(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_int(func, "frame", 0, 0, INT_MAX, "Frame",
"Frame of image sequence or movie", 0, INT_MAX);
RNA_def_int(func, "tile_number", 0, 0, INT_MAX, "Tile",
"Tile of a tiled image", 0, INT_MAX);
RNA_def_int(func, "filter", GL_LINEAR_MIPMAP_NEAREST, -INT_MAX, INT_MAX, "Filter",
"The texture minifying function", -INT_MAX, INT_MAX);
RNA_def_int(func, "mag", GL_LINEAR, -INT_MAX, INT_MAX, "Magnification",

View File

@@ -330,13 +330,13 @@ static Lamp *rna_Main_lights_new(Main *bmain, const char *name, int type)
return lamp;
}
static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, bool alpha, bool float_buffer, bool stereo3d)
static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, bool alpha, bool float_buffer, bool stereo3d, bool tiled)
{
char safe_name[MAX_ID_NAME - 2];
rna_idname_validate(name, safe_name);
float color[4] = {0.0, 0.0, 0.0, 1.0};
Image *image = BKE_image_add_generated(bmain, width, height, safe_name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d);
Image *image = BKE_image_add_generated(bmain, width, height, safe_name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d, tiled);
id_us_min(&image->id);
return image;
}
@@ -1004,6 +1004,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_boolean(func, "alpha", 0, "Alpha", "Use alpha channel");
RNA_def_boolean(func, "float_buffer", 0, "Float Buffer", "Create an image with floating point color");
RNA_def_boolean(func, "stereo3d", 0, "Stereo 3D", "Create left and right views");
RNA_def_boolean(func, "tiled", 0, "Tiled", "Create a tiled image");
/* return type */
parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block");
RNA_def_function_return(func, parm);

View File

@@ -1069,7 +1069,7 @@ static const EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(
void *lock;
int zbuf, alpha, totitem = 0;
ibuf = ED_space_image_acquire_buffer(sima, &lock);
ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
alpha = ibuf && (ibuf->channels == 4);
zbuf = ibuf && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1));
@@ -1174,7 +1174,8 @@ static void rna_SpaceImageEditor_scopes_update(struct bContext *C, struct Pointe
ImBuf *ibuf;
void *lock;
ibuf = ED_space_image_acquire_buffer(sima, &lock);
/* TODO(lukas): Support tiles in scopes? */
ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
if (ibuf) {
ED_space_image_scopes_update(C, sima, ibuf, true);
WM_main_add_notifier(NC_IMAGE, sima->image);
@@ -2235,6 +2236,14 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Draw Modified Edges", "Draw edges after modifiers are applied");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "tile_grid_shape", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "tile_grid_shape");
RNA_def_property_array(prop, 2);
RNA_def_property_int_default(prop, 1);
RNA_def_property_range(prop, 1, 10);
RNA_def_property_ui_text(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, "show_other_objects", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_OTHER);
RNA_def_property_ui_text(prop, "Draw Other Objects", "Draw other selected objects that share the same image");
@@ -3376,6 +3385,12 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, "rna_SpaceImageEditor_zoom_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Zoom", "Zoom factor");
prop = RNA_def_property(srna, "current_tile", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "curtile");
RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_text(prop, "Current Tile", "The currently selected tile");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
/* image draw */
prop = RNA_def_property(srna, "show_repeat", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_DRAW_TILE);

View File

@@ -75,9 +75,9 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE
node_shader_gpu_tex_mapping(mat, node, in, out);
if (tex->projection == SHD_PROJ_EQUIRECTANGULAR)
GPU_stack_link(mat, node, "node_tex_environment_equirectangular", in, out, GPU_image(ima, iuser, isdata));
GPU_stack_link(mat, node, "node_tex_environment_equirectangular", in, out, GPU_image(ima, iuser, isdata, 0));
else
GPU_stack_link(mat, node, "node_tex_environment_mirror_ball", in, out, GPU_image(ima, iuser, isdata));
GPU_stack_link(mat, node, "node_tex_environment_mirror_ball", in, out, GPU_image(ima, iuser, isdata, 0));
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&

View File

@@ -67,6 +67,12 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
"tex_box_sample_cubic",
"tex_box_sample_smart"
};
static const char *names_tiled[] = {
"node_tex_image_tile_linear",
"node_tex_image_tile_nearest",
"node_tex_image_tile_cubic",
"node_tex_image_tile_smart"
};
Image *ima = (Image *)node->id;
ImageUser *iuser = NULL;
@@ -98,46 +104,59 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
node_shader_gpu_tex_mapping(mat, node, in, out);
switch (tex->projection) {
case SHD_PROJ_FLAT:
GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
break;
case SHD_PROJ_BOX:
GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL),
GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
&norm);
GPU_link(mat, "direction_transform_m4v3", norm,
GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
&norm);
GPU_link(mat, gpu_node_name, in[0].link,
norm,
GPU_image(ima, iuser, isdata),
&col1,
&col2,
&col3);
if (do_color_correction) {
GPU_link(mat, "srgb_to_linearrgb", col1, &col1);
GPU_link(mat, "srgb_to_linearrgb", col2, &col2);
GPU_link(mat, "srgb_to_linearrgb", col3, &col3);
}
GPU_link(mat, "node_tex_image_box", in[0].link,
norm,
col1, col2, col3,
GPU_image(ima, iuser, isdata),
GPU_uniform(&blend),
&out[0].link,
&out[1].link);
break;
case SHD_PROJ_SPHERE:
GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
GPU_link(mat, "point_map_to_sphere", in[0].link, &in[0].link);
GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
break;
case SHD_PROJ_TUBE:
GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
GPU_link(mat, "point_map_to_tube", in[0].link, &in[0].link);
GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata));
break;
if (ima->source == IMA_SRC_TILED) {
GPUNodeLink *map;
GPU_link(mat, "node_tex_image_tiled_map", in[0].link, &out[0].link, &map);
LISTBASE_FOREACH(ImageTile *, tile, &ima->tiles) {
float tile_number = tile->tile_number;
GPU_link(mat, names_tiled[tex->interpolation],
map, GPU_uniform(&tile_number),
GPU_image(ima, iuser, isdata, tile->tile_number),
out[0].link, &out[0].link, &out[1].link);
}
}
else {
switch (tex->projection) {
case SHD_PROJ_FLAT:
GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata, 0));
break;
case SHD_PROJ_BOX:
GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL),
GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
&norm);
GPU_link(mat, "direction_transform_m4v3", norm,
GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
&norm);
GPU_link(mat, gpu_node_name, in[0].link,
norm,
GPU_image(ima, iuser, isdata, 0),
&col1,
&col2,
&col3);
if (do_color_correction) {
GPU_link(mat, "srgb_to_linearrgb", col1, &col1);
GPU_link(mat, "srgb_to_linearrgb", col2, &col2);
GPU_link(mat, "srgb_to_linearrgb", col3, &col3);
}
GPU_link(mat, "node_tex_image_box", in[0].link,
norm,
col1, col2, col3,
GPU_image(ima, iuser, isdata, 0),
GPU_uniform(&blend),
&out[0].link,
&out[1].link);
break;
case SHD_PROJ_SPHERE:
GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
GPU_link(mat, "point_map_to_sphere", in[0].link, &in[0].link);
GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata, 0));
break;
case SHD_PROJ_TUBE:
GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
GPU_link(mat, "point_map_to_tube", in[0].link, &in[0].link);
GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata, 0));
break;
}
}
if (do_color_correction && (tex->projection != SHD_PROJ_BOX)) {