UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
135 changed files with 1327 additions and 3919 deletions
Showing only changes of commit be8a76df53 - Show all commits

View File

@ -333,10 +333,7 @@ option(WITH_MOD_OCEANSIM "Enable Ocean Modifier" ON)
# Image format support
option(WITH_IMAGE_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" ON)
option(WITH_IMAGE_OPENJPEG "Enable OpenJpeg Support (http://www.openjpeg.org)" ON)
option(WITH_IMAGE_TIFF "Enable LibTIFF Support" ON)
option(WITH_IMAGE_DDS "Enable DDS Image Support" ON)
option(WITH_IMAGE_CINEON "Enable CINEON and DPX Image Support" ON)
option(WITH_IMAGE_HDR "Enable HDR Image Support" ON)
option(WITH_IMAGE_WEBP "Enable WebP Image Support" ON)
# Audio/Video format support
@ -648,15 +645,15 @@ if(WIN32)
endif()
# Compiler tool-chain.
if(UNIX AND NOT APPLE)
if(UNIX)
if(CMAKE_COMPILER_IS_GNUCC)
option(WITH_LINKER_GOLD "Use ld.gold linker which is usually faster than ld.bfd" ON)
mark_as_advanced(WITH_LINKER_GOLD)
option(WITH_LINKER_LLD "Use ld.lld linker which is usually faster than ld.gold" OFF)
mark_as_advanced(WITH_LINKER_LLD)
endif()
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
option(WITH_LINKER_MOLD "Use ld.mold linker which is usually faster than ld.gold & ld.lld." OFF)
option(WITH_LINKER_LLD "Use ld.lld linker which is usually faster than ld.gold" OFF)
mark_as_advanced(WITH_LINKER_LLD)
option(WITH_LINKER_MOLD "Use ld.mold linker which is usually faster than ld.gold & ld.lld. Needs \"sold\" subscription on macOS." OFF)
mark_as_advanced(WITH_LINKER_MOLD)
endif()
endif()
@ -896,9 +893,6 @@ set_and_warn_dependency(WITH_IMAGE_OPENEXR WITH_ALEMBIC OFF)
set_and_warn_dependency(WITH_IMAGE_OPENEXR WITH_VULKAN_BACKEND OFF)
set_and_warn_dependency(WITH_IMAGE_OPENEXR WITH_CYCLES_OSL OFF)
# Haru needs `TIFFFaxBlackCodes` & `TIFFFaxWhiteCodes` symbols from TIFF.
set_and_warn_dependency(WITH_IMAGE_TIFF WITH_HARU OFF)
# auto enable openimageio for cycles
if(WITH_CYCLES)
# auto enable llvm for cycles_osl
@ -1941,11 +1935,8 @@ if(FIRST_RUN)
info_cfg_text("Image Formats:")
info_cfg_option(WITH_IMAGE_CINEON)
info_cfg_option(WITH_IMAGE_DDS)
info_cfg_option(WITH_IMAGE_HDR)
info_cfg_option(WITH_IMAGE_OPENEXR)
info_cfg_option(WITH_IMAGE_OPENJPEG)
info_cfg_option(WITH_IMAGE_TIFF)
info_cfg_text("Audio:")
info_cfg_option(WITH_CODEC_AVI)

View File

@ -26,11 +26,8 @@ set(WITH_HARU ON CACHE BOOL "" FORCE)
set(WITH_IK_ITASC ON CACHE BOOL "" FORCE)
set(WITH_IK_SOLVER ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_CINEON ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_DDS ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_HDR ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_OPENEXR ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_OPENJPEG ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_TIFF ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_WEBP ON CACHE BOOL "" FORCE)
set(WITH_INPUT_NDOF ON CACHE BOOL "" FORCE)
set(WITH_INPUT_IME ON CACHE BOOL "" FORCE)

View File

@ -27,11 +27,8 @@ set(WITH_HARU OFF CACHE BOOL "" FORCE)
set(WITH_IK_ITASC OFF CACHE BOOL "" FORCE)
set(WITH_IK_SOLVER OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_CINEON OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_DDS OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_HDR OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_OPENEXR OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_OPENJPEG OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_TIFF OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_WEBP OFF CACHE BOOL "" FORCE)
set(WITH_INPUT_IME OFF CACHE BOOL "" FORCE)
set(WITH_INPUT_NDOF OFF CACHE BOOL "" FORCE)

View File

@ -27,11 +27,8 @@ set(WITH_HARU ON CACHE BOOL "" FORCE)
set(WITH_IK_ITASC ON CACHE BOOL "" FORCE)
set(WITH_IK_SOLVER ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_CINEON ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_DDS ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_HDR ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_OPENEXR ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_OPENJPEG ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_TIFF ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_WEBP ON CACHE BOOL "" FORCE)
set(WITH_INPUT_NDOF ON CACHE BOOL "" FORCE)
set(WITH_INPUT_IME ON CACHE BOOL "" FORCE)

View File

@ -221,10 +221,8 @@ find_package(PNG REQUIRED)
set(JPEG_ROOT ${LIBDIR}/jpeg)
find_package(JPEG REQUIRED)
if(WITH_IMAGE_TIFF)
set(TIFF_ROOT ${LIBDIR}/tiff)
find_package(TIFF REQUIRED)
endif()
set(TIFF_ROOT ${LIBDIR}/tiff)
find_package(TIFF REQUIRED)
if(WITH_IMAGE_WEBP)
set(WEBP_ROOT_DIR ${LIBDIR}/webp)
@ -453,6 +451,31 @@ if(WITH_COMPILER_CCACHE)
endif()
endif()
unset(_custom_LINKER_FUSE_FLAG)
if(WITH_LINKER_LLD)
find_program(LLD_PROGRAM ld.lld)
if(LLD_PROGRAM)
set(_custom_LINKER_FUSE_FLAG "-fuse-ld=lld")
else()
message(WARNING "LLD linker NOT found, disabling WITH_LINKER_LLD")
set(WITH_LINKER_LLD OFF)
endif()
endif()
if(WITH_LINKER_MOLD)
find_program(MOLD_PROGRAM mold)
if(MOLD_PROGRAM)
set(_custom_LINKER_FUSE_FLAG "-fuse-ld=mold")
else()
message(WARNING "Mold linker NOT found, disabling WITH_LINKER_MOLD")
set(WITH_LINKER_MOLD OFF)
endif()
endif()
if(_custom_LINKER_FUSE_FLAG)
add_link_options(${_custom_LINKER_FUSE_FLAG})
endif()
if(WITH_COMPILER_ASAN)
list(APPEND PLATFORM_BUNDLED_LIBRARIES ${COMPILER_ASAN_LIBRARY})
endif()

View File

@ -109,6 +109,10 @@ find_package_wrapper(ZLIB REQUIRED)
find_package_wrapper(Zstd REQUIRED)
find_package_wrapper(Epoxy REQUIRED)
# XXX Linking errors with debian static tiff :/
# find_package_wrapper(TIFF REQUIRED)
find_package(TIFF)
if(WITH_VULKAN_BACKEND)
find_package_wrapper(Vulkan REQUIRED)
find_package_wrapper(ShaderC REQUIRED)
@ -190,13 +194,6 @@ if(WITH_IMAGE_OPENJPEG)
set_and_warn_library_found("OpenJPEG" OPENJPEG_FOUND WITH_IMAGE_OPENJPEG)
endif()
if(WITH_IMAGE_TIFF)
# XXX Linking errors with debian static tiff :/
# find_package_wrapper(TIFF)
find_package(TIFF)
set_and_warn_library_found("TIFF" TIFF_FOUND WITH_IMAGE_TIFF)
endif()
if(WITH_OPENAL)
find_package_wrapper(OpenAL)
set_and_warn_library_found("OpenAL" OPENAL_FOUND WITH_OPENAL)

View File

@ -487,14 +487,12 @@ if(WITH_IMAGE_OPENEXR)
endif()
endif()
if(WITH_IMAGE_TIFF)
# Try to find tiff first then complain and set static and maybe wrong paths
windows_find_package(TIFF)
if(NOT TIFF_FOUND)
warn_hardcoded_paths(libtiff)
set(TIFF_LIBRARY ${LIBDIR}/tiff/lib/libtiff.lib)
set(TIFF_INCLUDE_DIR ${LIBDIR}/tiff/include)
endif()
# Try to find tiff first then complain and set static and maybe wrong paths
windows_find_package(TIFF)
if(NOT TIFF_FOUND)
warn_hardcoded_paths(libtiff)
set(TIFF_LIBRARY ${LIBDIR}/tiff/lib/libtiff.lib)
set(TIFF_INCLUDE_DIR ${LIBDIR}/tiff/include)
endif()
if(WITH_JACK)

View File

@ -3,6 +3,7 @@
from __future__ import annotations
import bpy
from bpy.app.translations import contexts as i18n_contexts
from bpy_extras.node_utils import find_node_input
from bl_ui.utils import PresetPanel
@ -318,7 +319,7 @@ class CYCLES_RENDER_PT_sampling_path_guiding(CyclesButtonsPanel, Panel):
col = layout.column(align=True)
col.prop(cscene, "use_surface_guiding", text="Surface")
col.prop(cscene, "use_volume_guiding", text="Volume")
col.prop(cscene, "use_volume_guiding", text="Volume", text_ctxt=i18n_contexts.id_id)
class CYCLES_RENDER_PT_sampling_path_guiding_debug(CyclesDebugButtonsPanel, Panel):
@ -530,7 +531,7 @@ class CYCLES_RENDER_PT_light_paths_max_bounces(CyclesButtonsPanel, Panel):
col.prop(cscene, "diffuse_bounces", text="Diffuse")
col.prop(cscene, "glossy_bounces", text="Glossy")
col.prop(cscene, "transmission_bounces", text="Transmission")
col.prop(cscene, "volume_bounces", text="Volume")
col.prop(cscene, "volume_bounces", text="Volume", text_ctxt=i18n_contexts.id_id)
col = layout.column(align=True)
col.prop(cscene, "transparent_max_bounces", text="Transparent")
@ -980,7 +981,7 @@ class CYCLES_RENDER_PT_passes_light(CyclesButtonsPanel, Panel):
col.prop(view_layer, "use_pass_transmission_indirect", text="Indirect")
col.prop(view_layer, "use_pass_transmission_color", text="Color")
col = layout.column(heading="Volume", align=True)
col = layout.column(heading="Volume", heading_ctxt=i18n_contexts.id_id, align=True)
col.prop(cycles_view_layer, "use_pass_volume_direct", text="Direct")
col.prop(cycles_view_layer, "use_pass_volume_indirect", text="Indirect")
@ -1577,6 +1578,7 @@ class CYCLES_WORLD_PT_surface(CyclesButtonsPanel, Panel):
class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel):
bl_label = "Volume"
bl_translation_context = i18n_contexts.id_id
bl_context = "world"
bl_options = {'DEFAULT_CLOSED'}
@ -1696,6 +1698,7 @@ class CYCLES_WORLD_PT_settings_surface(CyclesButtonsPanel, Panel):
class CYCLES_WORLD_PT_settings_volume(CyclesButtonsPanel, Panel):
bl_label = "Volume"
bl_translation_context = i18n_contexts.id_id
bl_parent_id = "CYCLES_WORLD_PT_settings"
bl_context = "world"
@ -1791,6 +1794,7 @@ class CYCLES_MATERIAL_PT_surface(CyclesButtonsPanel, Panel):
class CYCLES_MATERIAL_PT_volume(CyclesButtonsPanel, Panel):
bl_label = "Volume"
bl_translation_context = i18n_contexts.id_id
bl_context = "material"
bl_options = {'DEFAULT_CLOSED'}
@ -1874,6 +1878,7 @@ class CYCLES_MATERIAL_PT_settings_surface(CyclesButtonsPanel, Panel):
class CYCLES_MATERIAL_PT_settings_volume(CyclesButtonsPanel, Panel):
bl_label = "Volume"
bl_translation_context = i18n_contexts.id_id
bl_parent_id = "CYCLES_MATERIAL_PT_settings"
bl_context = "material"

View File

@ -921,7 +921,7 @@ static void export_hair_curves(Scene *scene,
std::copy(b_attr_radius, b_attr_radius + num_keys, curve_radius);
}
else {
std::fill(curve_radius, curve_radius + num_curves, 0.005f);
std::fill(curve_radius, curve_radius + num_keys, 0.005f);
}
/* Export curves and points. */

View File

@ -244,7 +244,7 @@ static void export_pointcloud_motion(PointCloud *pointcloud,
const int num_points = pointcloud->num_points();
/* Point cloud attributes are stored as float4 with the radius in the w element.
* This is explict now as float3 is no longer interchangeable with float4 as it
* This is explicit now as float3 is no longer interchangeable with float4 as it
* is packed now. */
float4 *mP = attr_mP->data_float4() + motion_step * num_points;
bool have_motion = false;

View File

@ -1167,8 +1167,8 @@ BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHRefer
void BVHBuild::rotate(BVHNode *node, int max_depth, int iterations)
{
/* in tested scenes, this resulted in slightly slower raytracing, so disabled
* it for now. could be implementation bug, or depend on the scene */
/* In tested scenes, this resulted in slightly slower ray-tracing, so disabled
* it for now. could be implementation bug, or depend on the scene. */
if (node)
for (int i = 0; i < iterations; i++)
rotate(node, max_depth);

View File

@ -181,7 +181,7 @@ string OptiXDevice::compile_kernel_get_common_cflags(const uint kernel_features)
/* Add OptiX SDK include directory to include paths. */
common_cflags += string_printf(" -I\"%s\"", get_optix_include_dir().c_str());
/* Specialization for shader raytracing. */
/* Specialization for shader ray-tracing. */
if (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) {
common_cflags += " --keep-device-functions";
}
@ -483,7 +483,7 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
group_descs[PG_HITL].hitgroup.entryFunctionNameAH = "__anyhit__kernel_optix_local_hit";
}
/* Shader raytracing replaces some functions with direct callables. */
/* Shader ray-tracing replaces some functions with direct callables. */
if (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) {
group_descs[PG_RGEN_SHADE_SURFACE_RAYTRACE].kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN;
group_descs[PG_RGEN_SHADE_SURFACE_RAYTRACE].raygen.module = optix_module;
@ -584,7 +584,7 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
load_osl_kernels();
}
else if (kernel_features & (KERNEL_FEATURE_NODE_RAYTRACE | KERNEL_FEATURE_MNEE)) {
/* Create shader raytracing and MNEE pipeline. */
/* Create shader ray-tracing and MNEE pipeline. */
vector<OptixProgramGroup> pipeline_groups;
pipeline_groups.reserve(NUM_PROGRAM_GROUPS);
if (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) {

View File

@ -834,7 +834,7 @@ enum ShaderDataFlag {
SD_NEED_VOLUME_ATTRIBUTES = (1 << 28),
/* Shader has emission */
SD_HAS_EMISSION = (1 << 29),
/* Shader has raytracing */
/* Shader has ray-tracing. */
SD_HAS_RAYTRACE = (1 << 30),
/* Use back side for direct light sampling. */
SD_MIS_BACK = (1 << 31),

View File

@ -5726,7 +5726,7 @@ void SeparateHSVNode::compile(OSLCompiler &compiler)
compiler.add(this, "node_separate_hsv");
}
/* Hue Saturation Value */
/* Hue/Saturation/Value */
NODE_DEFINE(HSVNode)
{

View File

@ -204,7 +204,8 @@ GHOST_ContextEGL::GHOST_ContextEGL(const GHOST_System *const system,
m_swap_interval(1),
m_sharedContext(
choose_api(api, s_gl_sharedContext, s_gles_sharedContext, s_vg_sharedContext)),
m_sharedCount(choose_api(api, s_gl_sharedCount, s_gles_sharedCount, s_vg_sharedCount))
m_sharedCount(choose_api(api, s_gl_sharedCount, s_gles_sharedCount, s_vg_sharedCount)),
m_surface_from_native_window(false)
{
}
@ -454,6 +455,7 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
if (m_nativeWindow != 0) {
m_surface = ::eglCreateWindowSurface(m_display, m_config, m_nativeWindow, nullptr);
m_surface_from_native_window = true;
}
else {
static const EGLint pb_attrib_list[] = {
@ -598,8 +600,12 @@ error:
GHOST_TSuccess GHOST_ContextEGL::releaseNativeHandles()
{
m_nativeWindow = 0;
m_nativeDisplay = nullptr;
m_nativeWindow = 0;
if (m_surface_from_native_window) {
m_surface = EGL_NO_SURFACE;
}
return GHOST_kSuccess;
}

View File

@ -122,6 +122,11 @@ class GHOST_ContextEGL : public GHOST_Context {
EGLContext &m_sharedContext;
EGLint &m_sharedCount;
/**
* True when the surface is created from `m_nativeWindow`.
*/
bool m_surface_from_native_window;
static EGLContext s_gl_sharedContext;
static EGLint s_gl_sharedCount;

View File

@ -6339,14 +6339,15 @@ GHOST_TSuccess GHOST_SystemWayland::disposeContext(GHOST_IContext *context)
#ifdef USE_EVENT_BACKGROUND_THREAD
std::lock_guard lock_server_guard{*server_mutex};
#endif
struct wl_surface *wl_surface = (struct wl_surface *)((GHOST_Context *)context)->getUserData();
/* Delete the context before the window so the context is able to release
* native resources (such as the #EGLSurface) before WAYLAND frees them. */
delete context;
wl_egl_window *egl_window = (wl_egl_window *)wl_surface_get_user_data(wl_surface);
wl_egl_window_destroy(egl_window);
wl_surface_destroy(wl_surface);
delete context;
return GHOST_kSuccess;
}

View File

@ -2157,7 +2157,7 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
Atom target = m_atom.UTF8_STRING;
Window owner;
/* from xclip.c doOut() v0.11 */
/* From `xclip.c` `doOut()` v0.11. */
char *sel_buf;
ulong sel_len = 0;
XEvent evt;
@ -2614,13 +2614,13 @@ static bool match_token(const char *haystack, const char *needle)
/* Determining if an X device is a Tablet style device is an imperfect science.
* We rely on common conventions around device names as well as the type reported
* by Wacom tablets. This code will likely need to be expanded for alternate tablet types
* by WACOM tablets. This code will likely need to be expanded for alternate tablet types
*
* Wintab refers to any device that interacts with the tablet as a cursor,
* WINTAB refers to any device that interacts with the tablet as a cursor,
* (stylus, eraser, tablet mouse, airbrush, etc)
* this is not to be confused with wacom x11 configuration "cursor" device.
* Wacoms x11 config "cursor" refers to its device slot (which we mirror with
* our gSysCursors) for puck like devices (tablet mice essentially).
* this is not to be confused with WACOM X11 configuration "cursor" device.
* WACOM tablets X11 configuration "cursor" refers to its device slot (which we mirror with
* our `gSysCursors`) for puck like devices (tablet mice essentially).
*/
static GHOST_TTabletMode tablet_mode_from_name(const char *name, const char *type)
{

View File

@ -138,8 +138,6 @@ enum eGWL_PendingWindowActions {
* The state of the window frame has changed, apply the state from #GWL_Window::frame_pending.
*/
PENDING_WINDOW_FRAME_CONFIGURE = 0,
/** The EGL buffer must be resized to match #GWL_WindowFrame::size. */
PENDING_EGL_WINDOW_RESIZE,
# ifdef GHOST_OPENGL_ALPHA
/** Draw an opaque region behind the window. */
PENDING_OPAQUE_SET,
@ -150,7 +148,17 @@ enum eGWL_PendingWindowActions {
*/
PENDING_OUTPUT_SCALE_UPDATE,
PENDING_WINDOW_SURFACE_SCALE,
/**
* Workaround for a bug/glitch in WLROOTS based compositors (RIVER for e.g.).
* Deferring the scale update one even-loop cycle resolves a bug
* where the output enter/exit events cause the surface buffer being an invalid size.
*
* While these kinds of glitches might be ignored in some cases,
* this caused newly created windows to immediately loose the connection to WAYLAND
* (crashing from a user perspective).
*/
PENDING_OUTPUT_SCALE_UPDATE_DEFERRED,
/**
* The surface needs a commit to run.
* Use this to avoid committing immediately which can cause flickering when other operations
@ -669,20 +677,20 @@ static void gwl_window_pending_actions_handle(GWL_Window *win)
if (actions[PENDING_WINDOW_FRAME_CONFIGURE]) {
gwl_window_frame_update_from_pending(win);
}
if (actions[PENDING_EGL_WINDOW_RESIZE]) {
wl_egl_window_resize(win->egl_window, UNPACK2(win->frame.size), 0, 0);
}
# ifdef GHOST_OPENGL_ALPHA
if (actions[PENDING_OPAQUE_SET]) {
win->ghost_window->setOpaque();
}
# endif
if (actions[PENDING_OUTPUT_SCALE_UPDATE_DEFERRED]) {
gwl_window_pending_actions_tag(win, PENDING_OUTPUT_SCALE_UPDATE);
/* Force postponing scale update to ensure all scale information has been taken into account
* before the actual update is performed. Failing to do so tends to cause flickering. */
actions[PENDING_OUTPUT_SCALE_UPDATE] = false;
}
if (actions[PENDING_OUTPUT_SCALE_UPDATE]) {
win->ghost_window->outputs_changed_update_scale();
}
if (actions[PENDING_WINDOW_SURFACE_SCALE]) {
wl_surface_set_buffer_scale(win->wl_surface, win->frame.buffer_scale);
}
if (actions[PENDING_WINDOW_SURFACE_COMMIT]) {
wl_surface_commit(win->wl_surface);
}
@ -727,19 +735,11 @@ static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
}
if (surface_needs_egl_resize) {
#ifdef USE_EVENT_BACKGROUND_THREAD
gwl_window_pending_actions_tag(win, PENDING_EGL_WINDOW_RESIZE);
#else
wl_egl_window_resize(win->egl_window, UNPACK2(win->frame.size), 0, 0);
#endif
}
if (surface_needs_buffer_scale) {
#ifdef USE_EVENT_BACKGROUND_THREAD
gwl_window_pending_actions_tag(win, PENDING_WINDOW_SURFACE_SCALE);
#else
wl_surface_set_buffer_scale(win->wl_surface, win->frame.buffer_scale);
#endif
}
if (surface_needs_commit) {
@ -1936,7 +1936,10 @@ GHOST_TSuccess GHOST_WindowWayland::notify_decor_redraw()
void GHOST_WindowWayland::outputs_changed_update_scale_tag()
{
#ifdef USE_EVENT_BACKGROUND_THREAD
gwl_window_pending_actions_tag(window_, PENDING_OUTPUT_SCALE_UPDATE);
/* NOTE: if deferring causes problems, it could be isolated to the first scale initialization
* See: #GWL_WindowFrame::is_scale_init. */
gwl_window_pending_actions_tag(window_, PENDING_OUTPUT_SCALE_UPDATE_DEFERRED);
#else
outputs_changed_update_scale();
#endif

View File

@ -355,7 +355,7 @@ def script_paths(*, subdir=None, user_pref=True, check_all=False, use_user=True)
:arg subdir: Optional subdir.
:type subdir: string
:arg user_pref: Include the user preference script path.
:arg user_pref: Include the user preference script paths.
:type user_pref: bool
:arg check_all: Include local, user and system paths rather just the paths Blender uses.
:type check_all: bool
@ -387,6 +387,9 @@ def script_paths(*, subdir=None, user_pref=True, check_all=False, use_user=True)
if use_user:
base_paths.append(path_user)
if user_pref:
base_paths.extend(script_paths_pref())
scripts = []
for path in base_paths:
if not path:

View File

@ -1,10 +1,49 @@
# SPDX-License-Identifier: GPL-2.0-or-later
__all__ = (
"connect_virtual_socket",
"find_node_input",
)
def connect_sockets(input, output):
"""
Connect sockets in a node tree.
This is useful because the links created through the normal Python API are
invalid when one of the sockets is a virtual socket (grayed out sockets in
Group Input and Group Output nodes).
It replaces node_tree.links.new(input, output)
"""
import bpy
# Swap sockets if they are not passed in the proper order
if input.is_output and not output.is_output:
input, output = output, input
input_node = output.node
output_node = input.node
if input_node.id_data is not output_node.id_data:
print("Sockets do not belong to the same node tree")
return
if type(input) == type(output) == bpy.types.NodeSocketVirtual:
print("Cannot connect two virtual sockets together")
return
if output_node.type == 'GROUP_OUTPUT' and type(input) == bpy.types.NodeSocketVirtual:
output_node.id_data.outputs.new(type(output).__name__, output.name)
input = output_node.inputs[-2]
if input_node.type == 'GROUP_INPUT' and type(output) == bpy.types.NodeSocketVirtual:
output_node.id_data.inputs.new(type(input).__name__, input.name)
output = input_node.outputs[-2]
return input_node.id_data.links.new(input, output)
# XXX Names are not unique. Returns the first match.
def find_node_input(node, name):
for input in node.inputs:

View File

@ -580,7 +580,6 @@ class Mesh(bpy_types.ID):
vertex_indices = tuple(chain.from_iterable(faces))
loop_starts = tuple(islice(chain([0], accumulate(face_lengths)), faces_len))
self.polygons.foreach_set("loop_total", face_lengths)
self.polygons.foreach_set("loop_start", loop_starts)
self.polygons.foreach_set("vertices", vertex_indices)
@ -1097,6 +1096,10 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
layout.menu(cls.__name__, icon='COLLAPSEMENU')
class AssetShelf(StructRNA, metaclass=RNAMeta):
__slots__ = ()
class NodeTree(bpy_types.ID, metaclass=RNAMetaPropGroup):
__slots__ = ()

View File

@ -242,7 +242,6 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
mesh.vertices.foreach_set("co", verts_loc)
mesh.polygons.foreach_set("loop_start", range(0, nbr_loops, 4))
mesh.polygons.foreach_set("loop_total", (4,) * nbr_polys)
mesh.loops.foreach_set("vertex_index", faces)
if self.generate_uvs:

View File

@ -868,7 +868,6 @@ class CLIP_OT_setup_tracking_scene(Operator):
mesh.polygons.add(nbr_polys)
mesh.polygons.foreach_set("loop_start", range(0, nbr_loops, 4))
mesh.polygons.foreach_set("loop_total", (4,) * nbr_polys)
mesh.loops.foreach_set("vertex_index", faces)
mesh.update()

View File

@ -618,7 +618,6 @@ class MakeDupliFace(Operator):
mesh.vertices.foreach_set("co", face_verts)
mesh.loops.foreach_set("vertex_index", faces)
mesh.polygons.foreach_set("loop_start", range(0, nbr_faces * 4, 4))
mesh.polygons.foreach_set("loop_total", (4,) * nbr_faces)
mesh.update() # generates edge data
ob_new = bpy.data.objects.new(mesh.name, mesh)

View File

@ -121,8 +121,16 @@ class QuickFur(ObjectModeOperator, Operator):
material = bpy.data.materials.new("Fur Material")
mesh_with_zero_area = False
mesh_missing_uv_map = False
modifier_apply_error = False
for mesh_object in mesh_objects:
mesh = mesh_object.data
if len(mesh.uv_layers) == 0:
mesh_missing_uv_map = True
continue
with context.temp_override(active_object=mesh_object):
bpy.ops.object.curves_empty_hair_add()
curves_object = context.active_object
@ -132,7 +140,11 @@ class QuickFur(ObjectModeOperator, Operator):
area = 0.0
for poly in mesh.polygons:
area += poly.area
density = count / area
if area == 0.0:
mesh_with_zero_area = True
density = 10
else:
density = count / area
generate_modifier = curves_object.modifiers.new(name="Generate", type='NODES')
generate_modifier.node_group = generate_group
@ -166,7 +178,10 @@ class QuickFur(ObjectModeOperator, Operator):
if self.apply_hair_guides:
with context.temp_override(object=curves_object):
bpy.ops.object.modifier_apply(modifier=generate_modifier.name)
try:
bpy.ops.object.modifier_apply(modifier=generate_modifier.name)
except:
modifier_apply_error = True
curves_object.modifiers.move(0, len(curves_object.modifiers) - 1)
@ -174,6 +189,13 @@ class QuickFur(ObjectModeOperator, Operator):
for modifier in curves_object.modifiers:
modifier.node_group = modifier.node_group
if mesh_with_zero_area:
self.report({'WARNING'}, "Mesh has no face area")
if mesh_missing_uv_map:
self.report({'WARNING'}, "Mesh UV map required")
if modifier_apply_error and not mesh_with_zero_area:
self.report({'WARNING'}, "Unable to apply \"Generate\" modifier")
return {'FINISHED'}

View File

@ -592,6 +592,7 @@ class NODE_MT_category_GEO_VECTOR(Menu):
class NODE_MT_category_GEO_VOLUME(Menu):
bl_idname = "NODE_MT_category_GEO_VOLUME"
bl_label = "Volume"
bl_translation_context = i18n_contexts.id_id
def draw(self, context):
layout = self.layout

View File

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Panel
from bpy.app.translations import contexts as i18n_contexts
from rna_prop_ui import PropertyPanel
from bl_ui.utils import PresetPanel
@ -67,6 +68,7 @@ class DATA_PT_context_camera(CameraButtonsPanel, Panel):
class DATA_PT_lens(CameraButtonsPanel, Panel):
bl_label = "Lens"
bl_translation_context = i18n_contexts.id_camera
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from bpy.types import Panel
from bpy.app.translations import contexts as i18n_contexts
class DataButtonsPanel:
@ -15,6 +16,7 @@ class DataButtonsPanel:
class DATA_PT_empty(DataButtonsPanel, Panel):
bl_label = "Empty"
bl_translation_context = i18n_contexts.id_id
def draw(self, context):
layout = self.layout

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.app.translations import contexts as i18n_contexts
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
@ -89,7 +90,7 @@ class DATA_PT_EEVEE_light(DataButtonsPanel, Panel):
col.prop(light, "diffuse_factor", text="Diffuse")
col.prop(light, "specular_factor", text="Specular")
col.prop(light, "volume_factor", text="Volume")
col.prop(light, "volume_factor", text="Volume", text_ctxt=i18n_contexts.id_id)
col.separator()

View File

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Menu, Panel, UIList
from bpy.app.translations import contexts as i18n_contexts
from rna_prop_ui import PropertyPanel
from bpy_extras.node_utils import find_node_input
@ -176,6 +177,7 @@ class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel):
class EEVEE_MATERIAL_PT_volume(MaterialButtonsPanel, Panel):
bl_label = "Volume"
bl_translation_context = i18n_contexts.id_id
bl_context = "material"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_EEVEE'}

View File

@ -164,8 +164,8 @@ class RENDER_PT_time_stretching(RenderOutputButtonsPanel, Panel):
rd = context.scene.render
col = layout.column(align=True)
col.prop(rd, "frame_map_old", text="Old")
col.prop(rd, "frame_map_new", text="New")
col.prop(rd, "frame_map_old", text="Old", text_ctxt=i18n_contexts.time)
col.prop(rd, "frame_map_new", text="New", text_ctxt=i18n_contexts.time)
class RENDER_PT_post_processing(RenderOutputButtonsPanel, Panel):

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from bpy.types import Menu, Panel, UIList, ViewLayer
from bpy.app.translations import contexts as i18n_contexts
from rna_prop_ui import PropertyPanel
@ -140,7 +141,7 @@ class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel):
col.prop(view_layer, "use_pass_glossy_direct", text="Light")
col.prop(view_layer, "use_pass_glossy_color", text="Color")
col = layout.column(heading="Volume", align=True)
col = layout.column(heading="Volume", heading_ctxt=i18n_contexts.id_id, align=True)
col.prop(view_layer_eevee, "use_pass_volume_direct", text="Light")
col = layout.column(heading="Other", align=True)

View File

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Panel
from bpy.app.translations import contexts as i18n_contexts
from rna_prop_ui import PropertyPanel
from bpy_extras.node_utils import find_node_input
@ -115,6 +116,7 @@ class EEVEE_WORLD_PT_surface(WorldButtonsPanel, Panel):
class EEVEE_WORLD_PT_volume(WorldButtonsPanel, Panel):
bl_label = "Volume"
bl_translation_context = i18n_contexts.id_id
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_EEVEE'}

View File

@ -890,6 +890,7 @@ class CLIP_PT_tracking_lens(Panel):
bl_region_type = 'UI'
bl_category = "Track"
bl_label = "Lens"
bl_translation_context = i18n_contexts.id_camera
bl_parent_id = 'CLIP_PT_tracking_camera'
bl_options = {'DEFAULT_CLOSED'}

View File

@ -1762,7 +1762,7 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
sub.use_property_decorate = True
split = sub.split(factor=0.4, align=True)
split.alignment = 'RIGHT'
split.label(text="Volume")
split.label(text="Volume", text_ctxt=i18n_contexts.id_sound)
split.prop(scene, "audio_volume", text="")
sub.use_property_decorate = False
@ -1993,7 +1993,7 @@ class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel):
split = col.split(factor=0.4)
split.alignment = 'RIGHT'
split.label(text="Volume")
split.label(text="Volume", text_ctxt=i18n_contexts.id_sound)
split.prop(strip, "volume", text="")
audio_channels = context.scene.render.ffmpeg.audio_channels

View File

@ -66,12 +66,12 @@ class TEXT_HT_footer(Header):
if text.filepath:
if text.is_dirty:
row.label(
text=iface_("File: *%s (unsaved)" % text.filepath),
text=iface_("File: *%s (unsaved)") % text.filepath,
translate=False,
)
else:
row.label(
text=iface_("File: %s" % text.filepath),
text=iface_("File: %s") % text.filepath,
translate=False,
)
else:

View File

@ -418,7 +418,7 @@ class USERPREF_PT_edit_objects_duplicate_data(EditingPanel, CenterAlignMixIn, Pa
col.prop(edit, "use_duplicate_surface", text="Surface")
col.prop(edit, "use_duplicate_text", text="Text")
# col.prop(edit, "use_duplicate_texture", text="Texture") # Not implemented.
col.prop(edit, "use_duplicate_volume", text="Volume")
col.prop(edit, "use_duplicate_volume", text="Volume", text_ctxt=i18n_contexts.id_id)
class USERPREF_PT_edit_cursor(EditingPanel, CenterAlignMixIn, Panel):
@ -1951,7 +1951,7 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
addon_user_dirs = tuple(
p for p in (
*[os.path.join(pref_p, "addons") for pref_p in bpy.utils.script_path_user()],
*[os.path.join(pref_p, "addons") for pref_p in bpy.utils.script_paths_pref()],
bpy.utils.user_resource('SCRIPTS', path="addons"),
)
if p

View File

@ -1961,8 +1961,8 @@ class VIEW3D_MT_paint_gpencil(Menu):
layout.separator()
layout.operator("gpencil.vertex_color_invert", text="Invert")
layout.operator("gpencil.vertex_color_levels", text="Levels")
layout.operator("gpencil.vertex_color_hsv", text="Hue Saturation Value")
layout.operator("gpencil.vertex_color_brightness_contrast", text="Bright/Contrast")
layout.operator("gpencil.vertex_color_hsv", text="Hue/Saturation/Value")
layout.operator("gpencil.vertex_color_brightness_contrast", text="Brightness/Contrast")
class VIEW3D_MT_select_gpencil(Menu):
@ -2310,7 +2310,7 @@ class VIEW3D_MT_add(Menu):
layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT')
if context.preferences.experimental.use_new_point_cloud_type:
layout.operator("object.pointcloud_add", text="Point Cloud", icon='OUTLINER_OB_POINTCLOUD')
layout.menu("VIEW3D_MT_volume_add", text="Volume", icon='OUTLINER_OB_VOLUME')
layout.menu("VIEW3D_MT_volume_add", text="Volume", text_ctxt=i18n_contexts.id_id, icon='OUTLINER_OB_VOLUME')
layout.operator_menu_enum("object.gpencil_add", "type", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL')
layout.separator()
@ -3059,8 +3059,8 @@ class VIEW3D_MT_paint_vertex(Menu):
layout.operator("paint.vertex_color_invert", text="Invert")
layout.operator("paint.vertex_color_levels", text="Levels")
layout.operator("paint.vertex_color_hsv", text="Hue Saturation Value")
layout.operator("paint.vertex_color_brightness_contrast", text="Bright/Contrast")
layout.operator("paint.vertex_color_hsv", text="Hue/Saturation/Value")
layout.operator("paint.vertex_color_brightness_contrast", text="Brightness/Contrast")
class VIEW3D_MT_hook(Menu):

View File

@ -165,10 +165,6 @@ if(WITH_IMAGE_OPENEXR)
add_subdirectory(imbuf/intern/openexr)
endif()
if(WITH_IMAGE_DDS)
add_subdirectory(imbuf/intern/dds)
endif()
if(WITH_IMAGE_CINEON)
add_subdirectory(imbuf/intern/cineon)
endif()

View File

@ -524,7 +524,8 @@ typedef struct SculptAttribute {
/* Sculpt usage */
SculptAttributeParams params;
/* Used to keep track of which preallocated SculptAttribute instances
/**
* Used to keep track of which pre-allocated SculptAttribute instances
* inside of SculptSession.temp_attribute are used.
*/
bool used;

View File

@ -119,14 +119,14 @@ typedef struct PTCacheID {
unsigned int default_step;
unsigned int max_step;
/* flags defined in DNA_object_force_types.h */
/** flags defined in `DNA_object_force_types.h`. */
unsigned int data_types, info_types;
/* Copies point data to cache data. */
/** Copies point data to cache data. */
int (*write_point)(int index, void *calldata, void **data, int cfra);
/* Copies cache data to point data. */
/** Copies cache data to point data. */
void (*read_point)(int index, void *calldata, void **data, float cfra, const float *old_data);
/* Interpolated between previously read point data and cache data. */
/** Interpolated between previously read point data and cache data. */
void (*interpolate_point)(int index,
void *calldata,
void **data,
@ -135,32 +135,34 @@ typedef struct PTCacheID {
float cfra2,
const float *old_data);
/* copies point data to cache data */
/** Copies point data to cache data. */
int (*write_stream)(PTCacheFile *pf, void *calldata);
/* copies cache cata to point data */
/** Copies cache data to point data. */
int (*read_stream)(PTCacheFile *pf, void *calldata);
/* copies custom extradata to cache data */
/** Copies custom #PTCacheMem::extradata to cache data. */
void (*write_extra_data)(void *calldata, struct PTCacheMem *pm, int cfra);
/* copies custom extradata to cache data */
/** Copies custom #PTCacheMem::extradata to cache data. */
void (*read_extra_data)(void *calldata, struct PTCacheMem *pm, float cfra);
/* copies custom extradata to cache data */
/** Copies custom #PTCacheMem::extradata to cache data */
void (*interpolate_extra_data)(
void *calldata, struct PTCacheMem *pm, float cfra, float cfra1, float cfra2);
/* Total number of simulated points
* (the cfra parameter is just for using same function pointer with totwrite). */
/**
* Total number of simulated points
* (the `cfra` parameter is just for using same function pointer with `totwrite`).
*/
int (*totpoint)(void *calldata, int cfra);
/* report error if number of points does not match */
/** Report error if number of points does not match */
void (*error)(const struct ID *owner_id, void *calldata, const char *message);
/* number of points written for current cache frame */
/** Number of points written for current cache frame. */
int (*totwrite)(void *calldata, int cfra);
int (*write_header)(PTCacheFile *pf);
int (*read_header)(PTCacheFile *pf);
struct PointCache *cache;
/* used for setting the current cache from ptcaches list */
/** Used for setting the current cache from `ptcaches` list. */
struct PointCache **cache_ptr;
struct ListBase *ptcaches;
} PTCacheID;

View File

@ -594,26 +594,14 @@ if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
if(WITH_IMAGE_TIFF)
add_definitions(-DWITH_TIFF)
endif()
if(WITH_IMAGE_OPENJPEG)
add_definitions(-DWITH_OPENJPEG)
endif()
if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
endif()
if(WITH_IMAGE_CINEON)
add_definitions(-DWITH_CINEON)
endif()
if(WITH_IMAGE_HDR)
add_definitions(-DWITH_HDR)
endif()
if(WITH_IMAGE_WEBP)
add_definitions(-DWITH_WEBP)
endif()

View File

@ -699,7 +699,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
* places that wish to use the original mesh but with deformed
* coordinates (like vertex paint). */
if (r_deform) {
mesh_deform = BKE_mesh_copy_for_eval(mesh_input, true);
mesh_deform = BKE_mesh_copy_for_eval(mesh_final, false);
}
}

View File

@ -80,28 +80,22 @@ int BKE_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options)
if (imtype == R_IMF_IMTYPE_IRIS) {
return IMB_FTYPE_IMAGIC;
}
#ifdef WITH_HDR
if (imtype == R_IMF_IMTYPE_RADHDR) {
return IMB_FTYPE_RADHDR;
}
#endif
if (imtype == R_IMF_IMTYPE_PNG) {
r_options->quality = 15;
return IMB_FTYPE_PNG;
}
#ifdef WITH_DDS
if (imtype == R_IMF_IMTYPE_DDS) {
return IMB_FTYPE_DDS;
}
#endif
if (imtype == R_IMF_IMTYPE_BMP) {
return IMB_FTYPE_BMP;
}
#ifdef WITH_TIFF
if (imtype == R_IMF_IMTYPE_TIFF) {
return IMB_FTYPE_TIF;
}
#endif
if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
return IMB_FTYPE_OPENEXR;
}
@ -139,27 +133,21 @@ char BKE_ftype_to_imtype(const int ftype, const ImbFormatOptions *options)
if (ftype == IMB_FTYPE_IMAGIC) {
return R_IMF_IMTYPE_IRIS;
}
#ifdef WITH_HDR
if (ftype == IMB_FTYPE_RADHDR) {
return R_IMF_IMTYPE_RADHDR;
}
#endif
if (ftype == IMB_FTYPE_PNG) {
return R_IMF_IMTYPE_PNG;
}
#ifdef WITH_DDS
if (ftype == IMB_FTYPE_DDS) {
return R_IMF_IMTYPE_DDS;
}
#endif
if (ftype == IMB_FTYPE_BMP) {
return R_IMF_IMTYPE_BMP;
}
#ifdef WITH_TIFF
if (ftype == IMB_FTYPE_TIF) {
return R_IMF_IMTYPE_TIFF;
}
#endif
if (ftype == IMB_FTYPE_OPENEXR) {
return R_IMF_IMTYPE_OPENEXR;
}
@ -327,11 +315,9 @@ char BKE_imtype_from_arg(const char *imtype_arg)
if (STREQ(imtype_arg, "IRIS")) {
return R_IMF_IMTYPE_IRIS;
}
#ifdef WITH_DDS
if (STREQ(imtype_arg, "DDS")) {
return R_IMF_IMTYPE_DDS;
}
#endif
if (STREQ(imtype_arg, "JPEG")) {
return R_IMF_IMTYPE_JPEG90;
}
@ -353,16 +339,12 @@ char BKE_imtype_from_arg(const char *imtype_arg)
if (STREQ(imtype_arg, "BMP")) {
return R_IMF_IMTYPE_BMP;
}
#ifdef WITH_HDR
if (STREQ(imtype_arg, "HDR")) {
return R_IMF_IMTYPE_RADHDR;
}
#endif
#ifdef WITH_TIFF
if (STREQ(imtype_arg, "TIFF")) {
return R_IMF_IMTYPE_TIFF;
}
#endif
#ifdef WITH_OPENEXR
if (STREQ(imtype_arg, "OPEN_EXR")) {
return R_IMF_IMTYPE_OPENEXR;
@ -422,13 +404,11 @@ static bool do_add_image_extension(char *string,
extension = extension_test;
}
}
#ifdef WITH_HDR
else if (imtype == R_IMF_IMTYPE_RADHDR) {
if (!BLI_path_extension_check(string, extension_test = ".hdr")) {
extension = extension_test;
}
}
#endif
else if (ELEM(imtype,
R_IMF_IMTYPE_PNG,
R_IMF_IMTYPE_FFMPEG,
@ -440,13 +420,11 @@ static bool do_add_image_extension(char *string,
extension = extension_test;
}
}
#ifdef WITH_DDS
else if (imtype == R_IMF_IMTYPE_DDS) {
if (!BLI_path_extension_check(string, extension_test = ".dds")) {
extension = extension_test;
}
}
#endif
else if (ELEM(imtype, R_IMF_IMTYPE_TARGA, R_IMF_IMTYPE_RAWTGA)) {
if (!BLI_path_extension_check(string, extension_test = ".tga")) {
extension = extension_test;
@ -457,13 +435,11 @@ static bool do_add_image_extension(char *string,
extension = extension_test;
}
}
#ifdef WITH_TIFF
else if (imtype == R_IMF_IMTYPE_TIFF) {
if (!BLI_path_extension_check_n(string, extension_test = ".tif", ".tiff", nullptr)) {
extension = extension_test;
}
}
#endif
else if (imtype == R_IMF_IMTYPE_PSD) {
if (!BLI_path_extension_check(string, extension_test = ".psd")) {
extension = extension_test;
@ -617,11 +593,9 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf)
if (imtype == R_IMF_IMTYPE_IRIS) {
ibuf->ftype = IMB_FTYPE_IMAGIC;
}
#ifdef WITH_HDR
else if (imtype == R_IMF_IMTYPE_RADHDR) {
ibuf->ftype = IMB_FTYPE_RADHDR;
}
#endif
else if (ELEM(imtype,
R_IMF_IMTYPE_PNG,
R_IMF_IMTYPE_FFMPEG,
@ -639,15 +613,12 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf)
ibuf->foptions.quality = compress;
}
}
#ifdef WITH_DDS
else if (imtype == R_IMF_IMTYPE_DDS) {
ibuf->ftype = IMB_FTYPE_DDS;
}
#endif
else if (imtype == R_IMF_IMTYPE_BMP) {
ibuf->ftype = IMB_FTYPE_BMP;
}
#ifdef WITH_TIFF
else if (imtype == R_IMF_IMTYPE_TIFF) {
ibuf->ftype = IMB_FTYPE_TIF;
@ -667,7 +638,6 @@ void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf)
ibuf->foptions.flag |= TIF_COMPRESS_PACKBITS;
}
}
#endif
#ifdef WITH_OPENEXR
else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
ibuf->ftype = IMB_FTYPE_OPENEXR;
@ -787,11 +757,9 @@ void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf)
if (ftype == IMB_FTYPE_IMAGIC) {
im_format->imtype = R_IMF_IMTYPE_IRIS;
}
#ifdef WITH_HDR
else if (ftype == IMB_FTYPE_RADHDR) {
im_format->imtype = R_IMF_IMTYPE_RADHDR;
}
#endif
else if (ftype == IMB_FTYPE_PNG) {
im_format->imtype = R_IMF_IMTYPE_PNG;
@ -801,16 +769,12 @@ void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf)
im_format->compress = quality;
}
#ifdef WITH_DDS
else if (ftype == IMB_FTYPE_DDS) {
im_format->imtype = R_IMF_IMTYPE_DDS;
}
#endif
else if (ftype == IMB_FTYPE_BMP) {
im_format->imtype = R_IMF_IMTYPE_BMP;
}
#ifdef WITH_TIFF
else if (ftype == IMB_FTYPE_TIF) {
im_format->imtype = R_IMF_IMTYPE_TIFF;
if (custom_flags & TIF_16BIT) {
@ -829,7 +793,6 @@ void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf)
im_format->tiff_codec = R_IMF_TIFF_CODEC_PACKBITS;
}
}
#endif
#ifdef WITH_OPENEXR
else if (ftype == IMB_FTYPE_OPENEXR) {

View File

@ -139,7 +139,7 @@ static void mask_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_list(reader, &mask->masklayers);
LISTBASE_FOREACH (MaskLayer *, masklay, &mask->masklayers) {
/* can't use newdataadr since it's a pointer within an array */
/* Can't use #newdataadr since it's a pointer within an array. */
MaskSplinePoint *act_point_search = NULL;
BLO_read_list(reader, &masklay->splines);

View File

@ -278,7 +278,6 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
MutableSpan<MPoly> legacy_polys = BKE_mesh_legacy_convert_offsets_to_polys(
mesh, temp_arrays_for_legacy_format, poly_layers);
mesh->poly_offset_indices = nullptr;
BKE_mesh_legacy_convert_hide_layers_to_flags(mesh, legacy_polys);
BKE_mesh_legacy_convert_selection_layers_to_flags(mesh, legacy_polys);
@ -292,6 +291,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
mesh->active_color_attribute = nullptr;
mesh->default_color_attribute = nullptr;
BKE_mesh_legacy_convert_loose_edges_to_flag(mesh);
mesh->poly_offset_indices = nullptr;
/* Set deprecated mesh data pointers for forward compatibility. */
mesh->medge = const_cast<MEdge *>(mesh->edges().data());

View File

@ -1642,7 +1642,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
pcent_dst = blender::bke::mesh::poly_center_calc(
{reinterpret_cast<const blender::float3 *>(vert_positions_dst),
numverts_dst},
corner_verts_src.slice(poly_dst));
blender::Span(corner_verts_dst, numloops_dst).slice(poly_dst));
pcent_dst_valid = true;
}
pcent_src = poly_cents_src[pidx_src];

View File

@ -2131,16 +2131,16 @@ static const char *get_obdata_defname(int type)
case OB_POINTCLOUD:
return DATA_("PointCloud");
case OB_VOLUME:
return DATA_("Volume");
return CTX_DATA_(BLT_I18NCONTEXT_ID_ID, "Volume");
case OB_EMPTY:
return DATA_("Empty");
return CTX_DATA_(BLT_I18NCONTEXT_ID_ID, "Empty");
case OB_GPENCIL_LEGACY:
return DATA_("GPencil");
case OB_LIGHTPROBE:
return DATA_("LightProbe");
default:
CLOG_ERROR(&LOG, "Internal error, bad type: %d", type);
return DATA_("Empty");
return CTX_DATA_(BLT_I18NCONTEXT_ID_ID, "Empty");
}
}

View File

@ -37,13 +37,13 @@ struct MultiresDisplacementData {
const MultiresModifierData *mmd;
blender::OffsetIndices<int> polys;
const MDisps *mdisps;
/* Indexed by ptex face index, contains polygon/corner which corresponds
/* Indexed by PTEX face index, contains polygon/corner which corresponds
* to it.
*
* NOTE: For quad polygon this is an index of first corner only, since
* there we only have one ptex. */
* there we only have one PTEX. */
PolyCornerIndex *ptex_poly_corner;
/* Indexed by coarse face index, returns first ptex face index corresponding
/* Indexed by coarse face index, returns first PTEX face index corresponding
* to that coarse face. */
int *face_ptex_offset;
/* Sanity check, is used in debug builds.
@ -52,7 +52,7 @@ struct MultiresDisplacementData {
};
/* Denotes which grid to use to average value of the displacement read from the
* grid which corresponds to the ptex face. */
* grid which corresponds to the PTEX face. */
typedef enum eAverageWith {
AVERAGE_WITH_NONE,
AVERAGE_WITH_ALL,
@ -175,12 +175,12 @@ static void average_read_displacement_object(MultiresDisplacementData *data,
{
const PolyCornerIndex *poly_corner = &data->ptex_poly_corner[ptex_face_index];
const int num_corners = data->polys[poly_corner->poly_index].size();
/* Get (u, v) coordinate within the other ptex face which corresponds to
/* Get (u, v) coordinate within the other PTEX face which corresponds to
* the grid coordinates. */
float u, v;
average_convert_grid_coord_to_ptex(num_corners, corner_index, grid_u, grid_v, &u, &v);
/* Construct tangent matrix which corresponds to partial derivatives
* calculated for the other ptex face. */
* calculated for the other PTEX face. */
float tangent_matrix[3][3];
average_construct_tangent_matrix(
data->subdiv, num_corners, ptex_face_index, corner_index, u, v, tangent_matrix);
@ -208,7 +208,7 @@ static void average_get_other_ptex_and_corner(MultiresDisplacementData *data,
start_ptex_face_index + *r_other_corner_index;
}
/* NOTE: Grid coordinates are relatiev to the other grid already. */
/* NOTE: Grid coordinates are relative to the other grid already. */
static void average_with_other(SubdivDisplacement *displacement,
const int ptex_face_index,
const int corner,
@ -380,7 +380,7 @@ static void displacement_data_init_mapping(SubdivDisplacement *displacement, con
const int num_ptex_faces = count_num_ptex_faces(mesh);
/* Allocate memory. */
data->ptex_poly_corner = static_cast<PolyCornerIndex *>(
MEM_malloc_arrayN(num_ptex_faces, sizeof(*data->ptex_poly_corner), "ptex poly corner"));
MEM_malloc_arrayN(num_ptex_faces, sizeof(*data->ptex_poly_corner), "PTEX poly corner"));
/* Fill in offsets. */
int ptex_face_index = 0;
PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;

View File

@ -85,7 +85,8 @@ struct SubdivMeshContext {
static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
{
Mesh *subdiv_mesh = ctx->subdiv_mesh;
ctx->num_uv_layers = CustomData_number_of_layers(&subdiv_mesh->ldata, CD_PROP_FLOAT2);
ctx->num_uv_layers = std::min(CustomData_number_of_layers(&subdiv_mesh->ldata, CD_PROP_FLOAT2),
MAX_MTFACE);
for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
ctx->uv_layers[layer_index] = static_cast<float2 *>(CustomData_get_layer_n_for_write(
&subdiv_mesh->ldata, CD_PROP_FLOAT2, layer_index, subdiv_mesh->totloop));

View File

@ -173,11 +173,16 @@ int BLI_wcwidth(char32_t ucs) ATTR_WARN_UNUSED_RESULT;
int BLI_wcswidth(const char32_t *pwcs, size_t n) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Upper and lowercase for 32-bit characters for all scripts that distinguish case. One-to-one
* mappings so this doesn't work corectly for uppercase Σ (two lowercase forms) and lowercase ß
* won't become "SS".
* Return the uppercase of a 32-bit character or the character when no case change is needed.
*
* \note A 1:1 mapping doesn't account for multiple characters as part of conversion in some cases.
*/
char32_t BLI_str_utf32_char_to_upper(char32_t wc);
/**
* Return the lowercase of a 32-bit character or the character when no case change is needed.
*
* \note A 1:1 mapping doesn't account for multiple characters as part of conversion in some cases.
*/
char32_t BLI_str_utf32_char_to_lower(char32_t wc);
/**

View File

@ -399,7 +399,17 @@ int BLI_str_utf8_char_width_safe(const char *p)
return (columns < 0) ? 1 : columns;
}
char32_t BLI_str_utf32_char_to_upper(char32_t wc)
/* -------------------------------------------------------------------- */
/** \name UTF32 Case Conversion
*
* \warning the lower/uppercase form of some characters use multiple characters.
* These cases are not accounted for by this conversion function.
* A common example is the German `eszett` / `scharfes`.
* Supporting such cases would have to operate on a character array, with support for resizing.
* (for reference - Python's upper/lower functions support this).
* \{ */
char32_t BLI_str_utf32_char_to_upper(const char32_t wc)
{
if (wc < U'\xFF') { /* Latin. */
if ((wc <= U'z' && wc >= U'a') || (wc <= U'\xF6' && wc >= U'\xE0') ||
@ -420,7 +430,7 @@ char32_t BLI_str_utf32_char_to_upper(char32_t wc)
if (wc <= U'\x24E9' && wc >= U'\x24D0') { /* Enclosed Numerals. */
return wc - 26;
}
if (wc <= U'\xFF5A' && wc >= U'\xFF41') { /* Fullwidth Forms. */
if (wc <= U'\xFF5A' && wc >= U'\xFF41') { /* Full-width Forms. */
return wc - 32;
}
@ -506,7 +516,7 @@ char32_t BLI_str_utf32_char_to_upper(char32_t wc)
return wc;
}
char32_t BLI_str_utf32_char_to_lower(char32_t wc)
char32_t BLI_str_utf32_char_to_lower(const char32_t wc)
{
if (wc < U'\xD8') { /* Latin. */
if ((wc <= U'Z' && wc >= U'A') || (wc <= U'\xD6' && wc >= U'\xC0')) {
@ -525,7 +535,7 @@ char32_t BLI_str_utf32_char_to_lower(char32_t wc)
if (wc <= U'\x24CF' && wc >= U'\x24B6') { /* Enclosed Numerals. */
return wc + 26;
}
if (wc <= U'\xFF3A' && wc >= U'\xFF21') { /* Fullwidth Forms. */
if (wc <= U'\xFF3A' && wc >= U'\xFF21') { /* Full-width Forms. */
return wc + 32;
}
@ -611,7 +621,7 @@ char32_t BLI_str_utf32_char_to_lower(char32_t wc)
return wc;
}
/* -------------------------------------------------------------------- */
/** \} */ /* -------------------------------------------------------------------- */
/* copied from glib's gutf8.c, added 'Err' arg */

View File

@ -2237,32 +2237,6 @@ static void *restore_pointer_by_name(IDNameLib_Map *id_map, ID *id, ePointerUser
#endif
}
static void lib_link_seq_clipboard_pt_restore(ID *id, IDNameLib_Map *id_map)
{
if (id) {
/* clipboard must ensure this */
BLI_assert(id->newid != nullptr);
id->newid = static_cast<ID *>(restore_pointer_by_name(id_map, id->newid, USER_REAL));
}
}
static bool lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt)
{
IDNameLib_Map *id_map = static_cast<IDNameLib_Map *>(arg_pt);
lib_link_seq_clipboard_pt_restore(reinterpret_cast<ID *>(seq->scene), id_map);
lib_link_seq_clipboard_pt_restore(reinterpret_cast<ID *>(seq->scene_camera), id_map);
lib_link_seq_clipboard_pt_restore(reinterpret_cast<ID *>(seq->clip), id_map);
lib_link_seq_clipboard_pt_restore(reinterpret_cast<ID *>(seq->mask), id_map);
lib_link_seq_clipboard_pt_restore(reinterpret_cast<ID *>(seq->sound), id_map);
return true;
}
static void lib_link_clipboard_restore(IDNameLib_Map *id_map)
{
/* update IDs stored in sequencer clipboard */
SEQ_for_each_callback(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data)
{
const int cb_flag = cb_data->cb_flag;
@ -2674,9 +2648,6 @@ void blo_lib_link_restore(Main *oldmain,
* that is just some minor harmless double-processing. */
lib_link_main_data_restore(id_map, newmain);
/* update IDs stored in all possible clipboards */
lib_link_clipboard_restore(id_map);
BKE_main_idmap_destroy(id_map);
}

View File

@ -97,7 +97,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_view3d.face_retopology);
}
if (!USER_VERSION_ATLEAST(306, 5)) {
if (!USER_VERSION_ATLEAST(306, 6)) {
FROM_DEFAULT_V4_UCHAR(space_view3d.asset_shelf.back);
FROM_DEFAULT_V4_UCHAR(space_view3d.asset_shelf.header_back);
}

View File

@ -82,55 +82,55 @@ const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid
#define BLT_I18NCONTEXT_ID_ACTION "Action"
#define BLT_I18NCONTEXT_ID_ARMATURE "Armature"
#define BLT_I18NCONTEXT_ID_BRUSH "Brush"
#define BLT_I18NCONTEXT_ID_CAMERA "Camera"
#define BLT_I18NCONTEXT_ID_CACHEFILE "CacheFile"
#define BLT_I18NCONTEXT_ID_CAMERA "Camera"
#define BLT_I18NCONTEXT_ID_COLLECTION "Collection"
#define BLT_I18NCONTEXT_ID_CURVES "Curves"
#define BLT_I18NCONTEXT_ID_CURVE_LEGACY "Curve"
#define BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE "FreestyleLineStyle"
#define BLT_I18NCONTEXT_ID_GPENCIL "GPencil"
#define BLT_I18NCONTEXT_ID_CURVES "Curves"
#define BLT_I18NCONTEXT_ID_ID "ID"
#define BLT_I18NCONTEXT_ID_IMAGE "Image"
// #define BLT_I18NCONTEXT_ID_IPO "Ipo" /* DEPRECATED */
#define BLT_I18NCONTEXT_ID_SHAPEKEY "Key"
#define BLT_I18NCONTEXT_ID_SIMULATION "Simulation"
#define BLT_I18NCONTEXT_ID_LIGHT "Light"
#define BLT_I18NCONTEXT_ID_LIBRARY "Library"
#define BLT_I18NCONTEXT_ID_LATTICE "Lattice"
#define BLT_I18NCONTEXT_ID_LIBRARY "Library"
#define BLT_I18NCONTEXT_ID_LIGHT "Light"
#define BLT_I18NCONTEXT_ID_LIGHTPROBE "LightProbe"
#define BLT_I18NCONTEXT_ID_MASK "Mask"
#define BLT_I18NCONTEXT_ID_MATERIAL "Material"
#define BLT_I18NCONTEXT_ID_METABALL "Metaball"
#define BLT_I18NCONTEXT_ID_MESH "Mesh"
#define BLT_I18NCONTEXT_ID_METABALL "Metaball"
#define BLT_I18NCONTEXT_ID_MOVIECLIP "MovieClip"
#define BLT_I18NCONTEXT_ID_NODETREE "NodeTree"
#define BLT_I18NCONTEXT_ID_OBJECT "Object"
#define BLT_I18NCONTEXT_ID_PAINTCURVE "PaintCurve"
#define BLT_I18NCONTEXT_ID_PALETTE "Palette"
#define BLT_I18NCONTEXT_ID_PARTICLESETTINGS "ParticleSettings"
#define BLT_I18NCONTEXT_ID_POINTCLOUD "PointCloud"
#define BLT_I18NCONTEXT_ID_LIGHTPROBE "LightProbe"
#define BLT_I18NCONTEXT_ID_SCENE "Scene"
#define BLT_I18NCONTEXT_ID_SCREEN "Screen"
#define BLT_I18NCONTEXT_ID_SEQUENCE "Sequence"
#define BLT_I18NCONTEXT_ID_SPEAKER "Speaker"
#define BLT_I18NCONTEXT_ID_SHAPEKEY "Key"
#define BLT_I18NCONTEXT_ID_SIMULATION "Simulation"
#define BLT_I18NCONTEXT_ID_SOUND "Sound"
#define BLT_I18NCONTEXT_ID_TEXTURE "Texture"
#define BLT_I18NCONTEXT_ID_SPEAKER "Speaker"
#define BLT_I18NCONTEXT_ID_TEXT "Text"
#define BLT_I18NCONTEXT_ID_TEXTURE "Texture"
#define BLT_I18NCONTEXT_ID_VFONT "VFont"
#define BLT_I18NCONTEXT_ID_VOLUME "Volume"
#define BLT_I18NCONTEXT_ID_WORLD "World"
#define BLT_I18NCONTEXT_ID_WORKSPACE "WorkSpace"
#define BLT_I18NCONTEXT_ID_WINDOWMANAGER "WindowManager"
#define BLT_I18NCONTEXT_ID_MOVIECLIP "MovieClip"
#define BLT_I18NCONTEXT_ID_MASK "Mask"
#define BLT_I18NCONTEXT_ID_WORKSPACE "WorkSpace"
#define BLT_I18NCONTEXT_ID_WORLD "World"
/* Editors-types contexts. */
#define BLT_I18NCONTEXT_EDITOR_VIEW3D "View3D"
#define BLT_I18NCONTEXT_EDITOR_FILEBROWSER "File browser"
#define BLT_I18NCONTEXT_EDITOR_VIEW3D "View3D"
/* Generic contexts. */
#define BLT_I18NCONTEXT_VIRTUAL_REALITY "Virtual reality"
#define BLT_I18NCONTEXT_CONSTRAINT "Constraint"
#define BLT_I18NCONTEXT_COLOR "Color"
#define BLT_I18NCONTEXT_AMOUNT "Amount"
#define BLT_I18NCONTEXT_COLOR "Color"
#define BLT_I18NCONTEXT_CONSTRAINT "Constraint"
#define BLT_I18NCONTEXT_TIME "Time"
#define BLT_I18NCONTEXT_UNIT "Unit"
/* Helper for bpy.app.i18n object... */
@ -155,25 +155,25 @@ typedef struct {
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ACTION, "id_action"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ARMATURE, "id_armature"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_BRUSH, "id_brush"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CAMERA, "id_camera"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CACHEFILE, "id_cachefile"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CAMERA, "id_camera"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_COLLECTION, "id_collection"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CURVES, "id_curves"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CURVE_LEGACY, "id_curve"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, "id_fs_linestyle"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_GPENCIL, "id_gpencil"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_CURVES, "id_curves"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ID, "id_id"), \
BLT_I18NCONTEXTS_ITEM( \
BLT_I18NCONTEXT_ID_IMAGE, \
"id_image"), /* BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_IPO, "id_ipo"), */ \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SHAPEKEY, "id_shapekey"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_LIGHT, "id_light"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_LIBRARY, "id_library"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_LATTICE, "id_lattice"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_LIBRARY, "id_library"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_LIGHT, "id_light"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_LIGHTPROBE, "id_lightprobe"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_MASK, "id_mask"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_MATERIAL, "id_material"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_METABALL, "id_metaball"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_MESH, "id_mesh"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_METABALL, "id_metaball"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_MOVIECLIP, "id_movieclip"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_NODETREE, "id_nodetree"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_OBJECT, "id_object"), \
@ -181,26 +181,26 @@ typedef struct {
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_PALETTE, "id_palette"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_PARTICLESETTINGS, "id_particlesettings"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_POINTCLOUD, "id_pointcloud"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_LIGHTPROBE, "id_lightprobe"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SCENE, "id_scene"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SCREEN, "id_screen"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SEQUENCE, "id_sequence"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SHAPEKEY, "id_shapekey"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SIMULATION, "id_simulation"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SPEAKER, "id_speaker"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SOUND, "id_sound"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_TEXTURE, "id_texture"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SPEAKER, "id_speaker"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_TEXT, "id_text"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_TEXTURE, "id_texture"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_VFONT, "id_vfont"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_VOLUME, "id_volume"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WORLD, "id_world"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WORKSPACE, "id_workspace"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "id_windowmanager"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_EDITOR_VIEW3D, "editor_view3d"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WORKSPACE, "id_workspace"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_WORLD, "id_world"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_EDITOR_FILEBROWSER, "editor_filebrowser"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_VIRTUAL_REALITY, "virtual_reality"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_CONSTRAINT, "constraint"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_COLOR, "color"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_EDITOR_VIEW3D, "editor_view3d"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_AMOUNT, "amount"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_COLOR, "color"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_CONSTRAINT, "constraint"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_TIME, "time"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_UNIT, "unit"), \
{ \
NULL, NULL, NULL \

View File

@ -172,7 +172,7 @@ class Operation {
void release_inputs();
/* Release the results that were allocated in the execute method but are not actually needed.
* This can be the case if the execute method allocated a dummy texture for an unndeeded result,
* This can be the case if the execute method allocated a dummy texture for an unneeded result,
* see the description of Result::allocate_texture() for more information. This is called after
* the evaluation of the operation. */
void release_unneeded_results();

View File

@ -41,7 +41,7 @@ class ShadingView {
/** Matrix to apply to the viewmat. */
const float4x4 &face_matrix_;
/** Raytracing persistent buffers. Only opaque and refraction can have surface tracing. */
/** Ray-tracing persistent buffers. Only opaque and refraction can have surface tracing. */
// RaytraceBuffer rt_buffer_opaque_;
// RaytraceBuffer rt_buffer_refract_;
DepthOfFieldBuffer dof_buffer_;

View File

@ -1714,7 +1714,7 @@ static int gpencil_strokes_paste_exec(bContext *C, wmOperator *op)
* doesn't exist already depending on REC button status.
*/
/* Multiframe paste. */
/* Multi-frame paste. */
if (is_multiedit) {
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
/* Active frame is copied later, so don't need duplicate the stroke here. */

View File

@ -331,7 +331,7 @@ static int gpencil_vertexpaint_hsv_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_vertex_color_hsv(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Vertex Paint Hue Saturation Value";
ot->name = "Vertex Paint Hue/Saturation/Value";
ot->idname = "GPENCIL_OT_vertex_color_hsv";
ot->description = "Adjust vertex color HSV values";

View File

@ -420,9 +420,9 @@ static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Vertex Paint Hue Saturation Value";
ot->name = "Vertex Paint Hue/Saturation/Value";
ot->idname = "PAINT_OT_vertex_color_hsv";
ot->description = "Adjust vertex color HSV values";
ot->description = "Adjust vertex color Hue/Saturation/Value";
/* api callbacks */
ot->exec = vertex_color_hsv_exec;

View File

@ -784,7 +784,7 @@ static void sculpt_undo_geometry_restore_data(SculptUndoNodeGeometry *geometry,
&geometry->ldata, &mesh->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop);
CustomData_copy(
&geometry->pdata, &mesh->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly);
mesh->poly_offset_indices = static_cast<int *>(geometry->poly_offset_indices);
mesh->poly_offset_indices = static_cast<int *>(MEM_dupallocN(geometry->poly_offset_indices));
BKE_mesh_runtime_clear_cache(mesh);
}

View File

@ -66,26 +66,14 @@ if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
if(WITH_IMAGE_TIFF)
add_definitions(-DWITH_TIFF)
endif()
if(WITH_IMAGE_OPENJPEG)
add_definitions(-DWITH_OPENJPEG)
endif()
if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
endif()
if(WITH_IMAGE_CINEON)
add_definitions(-DWITH_CINEON)
endif()
if(WITH_IMAGE_HDR)
add_definitions(-DWITH_HDR)
endif()
if(WITH_IMAGE_WEBP)
add_definitions(-DWITH_WEBP)
endif()

View File

@ -54,10 +54,6 @@ if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
if(WITH_IMAGE_TIFF)
add_definitions(-DWITH_TIFF)
endif()
if(WITH_IMAGE_CINEON)
add_definitions(-DWITH_CINEON)
endif()

View File

@ -1052,7 +1052,7 @@ static void create_inspection_string_for_geometry_socket(std::stringstream &ss,
break;
}
case GEO_COMPONENT_TYPE_VOLUME: {
ss << TIP_("Volume");
ss << CTX_TIP_(BLT_I18NCONTEXT_ID_ID, "Volume");
break;
}
case GEO_COMPONENT_TYPE_EDIT: {

View File

@ -2167,39 +2167,18 @@ static void outliner_do_data_operation(
});
}
static Base *outliner_batch_delete_hierarchy(
ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base)
static void outliner_batch_delete_object_tag(ReportList *reports,
Main *bmain,
Scene *scene,
Object *object)
{
Base *child_base, *base_next;
Object *object, *parent;
if (!base) {
return nullptr;
}
BKE_view_layer_synced_ensure(scene, view_layer);
object = base->object;
for (child_base = static_cast<Base *>(BKE_view_layer_object_bases_get(view_layer)->first);
child_base;
child_base = base_next) {
base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != object);
parent = parent->parent) {
/* pass */
}
if (parent) {
base_next = outliner_batch_delete_hierarchy(reports, bmain, view_layer, scene, child_base);
}
}
base_next = base->next;
if (object->id.tag & LIB_TAG_INDIRECT) {
BKE_reportf(reports,
RPT_WARNING,
"Cannot delete indirectly linked object '%s'",
base->object->id.name + 2);
return base_next;
BKE_reportf(
reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", object->id.name + 2);
BLI_assert((object->id.tag & LIB_TAG_DOIT) == 0);
}
/* FIXME: This code checking object usercount won't work as expected if a same object belongs to
* more than one collection in the scene. */
if (ID_REAL_USERS(object) <= 1 && ID_EXTRA_USERS(object) == 0 &&
BKE_library_ID_is_indirectly_used(bmain, object)) {
BKE_reportf(reports,
@ -2208,41 +2187,105 @@ static Base *outliner_batch_delete_hierarchy(
"one user",
object->id.name + 2,
scene->id.name + 2);
return base_next;
BLI_assert((object->id.tag & LIB_TAG_DOIT) == 0);
}
DEG_id_tag_update_ex(bmain, &object->id, ID_RECALC_BASE_FLAGS);
BKE_scene_collections_object_remove(bmain, scene, object, false);
if (object->id.us == 0) {
object->id.tag |= LIB_TAG_DOIT;
}
return base_next;
object->id.tag |= LIB_TAG_DOIT;
}
static void object_batch_delete_hierarchy_fn(bContext *C,
ReportList *reports,
Scene *scene,
Object *ob)
static void outliner_batch_delete_object_hierarchy_tag(
ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base)
{
Object *object = base->object;
BLI_assert(object != nullptr);
outliner_batch_delete_object_tag(reports, bmain, scene, object);
/* Even though the object itself may not be deletable, some of its children may still be
* deletable. */
for (Base *base_iter = static_cast<Base *>(BKE_view_layer_object_bases_get(view_layer)->first);
base_iter != nullptr;
base_iter = base_iter->next) {
Object *parent_ob_iter;
for (parent_ob_iter = base_iter->object->parent;
(parent_ob_iter != nullptr && parent_ob_iter != object &&
(parent_ob_iter->id.tag & LIB_TAG_DOIT) == 0);
parent_ob_iter = parent_ob_iter->parent) {
/* pass */
}
if (parent_ob_iter != nullptr) {
/* There is one or more parents to current iterated object that also need to be deleted,
* process the parenting chain again to tag them as such.
*
* NOTE: Since objects that cannot be deleted are not tagged, the relevant 'parenting'
* branches may be looped over more than once. Would not expect this to be a real issue in
* practice though. */
for (parent_ob_iter = base_iter->object;
(parent_ob_iter != nullptr && parent_ob_iter != object &&
(parent_ob_iter->id.tag & LIB_TAG_DOIT) == 0);
parent_ob_iter = parent_ob_iter->parent) {
outliner_batch_delete_object_tag(reports, bmain, scene, parent_ob_iter);
}
}
}
}
static void object_batch_delete_hierarchy_tag_fn(bContext *C,
ReportList *reports,
Scene *scene,
Object *ob)
{
if (ob->id.tag & LIB_TAG_DOIT) {
/* Object has already been processed and tagged for removal as part of another parenting
* hierarchy. */
#ifndef NDEBUG
ViewLayer *view_layer = CTX_data_view_layer(C);
BKE_view_layer_synced_ensure(scene, view_layer);
BLI_assert(BKE_view_layer_base_find(view_layer, ob) == nullptr);
#endif
return;
}
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obedit = CTX_data_edit_object(C);
BKE_view_layer_synced_ensure(scene, view_layer);
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base) {
/* Check also library later. */
for (; obedit && (obedit != base->object); obedit = obedit->parent) {
/* pass */
}
if (obedit == base->object) {
ED_object_editmode_exit(C, EM_FREEDATA);
if (base == nullptr) {
return;
}
/* Exit Edit mode if the active object or one of its children are being edited. */
for (; obedit && (obedit != base->object); obedit = obedit->parent) {
/* pass */
}
if (obedit == base->object) {
ED_object_editmode_exit(C, EM_FREEDATA);
}
Main *bmain = CTX_data_main(C);
outliner_batch_delete_object_hierarchy_tag(reports, bmain, view_layer, scene, base);
}
static void outliner_batch_delete_object_hierarchy(Main *bmain, Scene *scene)
{
LISTBASE_FOREACH (Object *, ob_iter, &bmain->objects) {
if ((ob_iter->id.tag & LIB_TAG_DOIT) == 0) {
continue;
}
outliner_batch_delete_hierarchy(reports, CTX_data_main(C), view_layer, scene, base);
BKE_scene_collections_object_remove(bmain, scene, ob_iter, false);
/* Check on all objects tagged for deletion, these that are still in use (e.g. in collections
* from another scene) should not be deleted. They also need to be tagged for depsgraph update.
*/
if (ob_iter->id.us != 0) {
ob_iter->id.tag &= ~LIB_TAG_DOIT;
DEG_id_tag_update_ex(bmain, &ob_iter->id, ID_RECALC_BASE_FLAGS);
}
}
BKE_id_multi_tagged_delete(bmain);
}
/** \} */
@ -2475,10 +2518,17 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
if (delete_hierarchy) {
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
outliner_do_object_delete(
C, op->reports, scene, object_delete_data.objects_set, object_batch_delete_hierarchy_fn);
BKE_view_layer_synced_ensure(scene, view_layer);
BKE_id_multi_tagged_delete(bmain);
/* #object_batch_delete_hierarchy_fn callback will only remove objects from collections and tag
* them for deletion. */
outliner_do_object_delete(C,
op->reports,
scene,
object_delete_data.objects_set,
object_batch_delete_hierarchy_tag_fn);
outliner_batch_delete_object_hierarchy(bmain, scene);
}
else {
outliner_do_object_delete(

View File

@ -179,7 +179,8 @@ static void sync_viewport_camera_smoothview(bContext *C,
if (other_v3d->camera == ob) {
continue;
}
if (v3d->scenelock) {
/* Checking the other view is needed to prevent local cameras being modified. */
if (v3d->scenelock && other_v3d->scenelock) {
ListBase *lb = (space_link == area->spacedata.first) ? &area->regionbase :
&space_link->regionbase;
for (ARegion *other_region = lb->first; other_region != NULL;

View File

@ -738,10 +738,6 @@ if(WITH_MOD_FLUID)
add_definitions(-DWITH_FLUID)
endif()
if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
endif()
if(WITH_OPENCOLORIO)
add_definitions(-DWITH_OCIO)
endif()

View File

@ -16,7 +16,6 @@ set(INC
set(INC_SYS
${JPEG_INCLUDE_DIR}
${PNG_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
${OPENIMAGEIO_INCLUDE_DIRS}
)
@ -24,13 +23,18 @@ set(INC_SYS
set(SRC
intern/allocimbuf.c
intern/anim_movie.c
intern/bmp.c
intern/colormanagement.c
intern/colormanagement_inline.c
intern/divers.c
intern/filetype.c
intern/filter.c
intern/format_bmp.cc
intern/format_dds.cc
intern/format_hdr.cc
intern/format_png.cc
intern/format_psd.cc
intern/format_targa.cc
intern/format_tiff.cc
intern/imageprocess.c
intern/indexer.c
intern/iris.c
@ -38,13 +42,11 @@ set(SRC
intern/metadata.c
intern/module.c
intern/moviecache.cc
intern/png.c
intern/readimage.c
intern/rectop.c
intern/rotate.c
intern/scaling.c
intern/stereoimbuf.c
intern/targa.c
intern/thumbs.c
intern/thumbs_blend.c
intern/thumbs_font.c
@ -81,7 +83,6 @@ set(LIB
bf_intern_memutil
bf_intern_opencolorio
${PNG_LIBRARIES}
${JPEG_LIBRARIES}
)
@ -96,19 +97,6 @@ else()
)
endif()
if(WITH_IMAGE_TIFF)
list(APPEND INC_SYS
${TIFF_INCLUDE_DIR}
)
list(APPEND SRC
intern/tiff.c
)
list(APPEND LIB
${TIFF_LIBRARY}
)
add_definitions(-DWITH_TIFF)
endif()
if(WITH_IMAGE_OPENJPEG)
list(APPEND INC_SYS
${OPENJPEG_INCLUDE_DIRS}
@ -147,27 +135,16 @@ if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
if(WITH_IMAGE_DDS)
list(APPEND LIB
bf_imbuf_dds
)
add_definitions(-DWITH_DDS)
endif()
if(WITH_IMAGE_CINEON)
list(APPEND SRC
intern/format_dpx.cc
)
list(APPEND LIB
bf_imbuf_cineon
)
add_definitions(-DWITH_CINEON)
endif()
if(WITH_IMAGE_HDR)
list(APPEND SRC
intern/radiance_hdr.c
)
add_definitions(-DWITH_HDR)
endif()
if(WITH_IMAGE_WEBP)
list(APPEND SRC
intern/webp.c

View File

@ -63,20 +63,14 @@ enum eImbFileType {
#ifdef WITH_OPENJPEG
IMB_FTYPE_JP2 = 8,
#endif
#ifdef WITH_HDR
IMB_FTYPE_RADHDR = 9,
#endif
#ifdef WITH_TIFF
IMB_FTYPE_TIF = 10,
#endif
#ifdef WITH_CINEON
IMB_FTYPE_CINEON = 11,
IMB_FTYPE_DPX = 12,
#endif
#ifdef WITH_DDS
IMB_FTYPE_DDS = 13,
#endif
#ifdef WITH_WEBP
IMB_FTYPE_WEBP = 14,
#endif
@ -113,13 +107,11 @@ enum eImbFileType {
#define RAWTGA 1
#ifdef WITH_TIFF
# define TIF_16BIT (1 << 8)
# define TIF_COMPRESS_NONE (1 << 7)
# define TIF_COMPRESS_DEFLATE (1 << 6)
# define TIF_COMPRESS_LZW (1 << 5)
# define TIF_COMPRESS_PACKBITS (1 << 4)
#endif
#define TIF_16BIT (1 << 8)
#define TIF_COMPRESS_NONE (1 << 7)
#define TIF_COMPRESS_DEFLATE (1 << 6)
#define TIF_COMPRESS_LZW (1 << 5)
#define TIF_COMPRESS_PACKBITS (1 << 4)
typedef struct ImbFormatOptions {
short flag;
@ -295,25 +287,24 @@ enum {
/** \} */
/* dds */
#ifdef WITH_DDS
# ifndef DDS_MAKEFOURCC
# define DDS_MAKEFOURCC(ch0, ch1, ch2, ch3) \
((unsigned long)(unsigned char)(ch0) | ((unsigned long)(unsigned char)(ch1) << 8) | \
((unsigned long)(unsigned char)(ch2) << 16) | ((unsigned long)(unsigned char)(ch3) << 24))
# endif /* DDS_MAKEFOURCC */
#ifndef DDS_MAKEFOURCC
# define DDS_MAKEFOURCC(ch0, ch1, ch2, ch3) \
((unsigned long)(unsigned char)(ch0) | ((unsigned long)(unsigned char)(ch1) << 8) | \
((unsigned long)(unsigned char)(ch2) << 16) | ((unsigned long)(unsigned char)(ch3) << 24))
#endif /* DDS_MAKEFOURCC */
/*
* FOURCC codes for DX compressed-texture pixel formats.
*/
# define FOURCC_DDS (DDS_MAKEFOURCC('D', 'D', 'S', ' '))
# define FOURCC_DXT1 (DDS_MAKEFOURCC('D', 'X', 'T', '1'))
# define FOURCC_DXT2 (DDS_MAKEFOURCC('D', 'X', 'T', '2'))
# define FOURCC_DXT3 (DDS_MAKEFOURCC('D', 'X', 'T', '3'))
# define FOURCC_DXT4 (DDS_MAKEFOURCC('D', 'X', 'T', '4'))
# define FOURCC_DXT5 (DDS_MAKEFOURCC('D', 'X', 'T', '5'))
#define FOURCC_DDS (DDS_MAKEFOURCC('D', 'D', 'S', ' '))
#define FOURCC_DX10 (DDS_MAKEFOURCC('D', 'X', '1', '0'))
#define FOURCC_DXT1 (DDS_MAKEFOURCC('D', 'X', 'T', '1'))
#define FOURCC_DXT2 (DDS_MAKEFOURCC('D', 'X', 'T', '2'))
#define FOURCC_DXT3 (DDS_MAKEFOURCC('D', 'X', 'T', '3'))
#define FOURCC_DXT4 (DDS_MAKEFOURCC('D', 'X', 'T', '4'))
#define FOURCC_DXT5 (DDS_MAKEFOURCC('D', 'X', 'T', '5'))
#endif /* DDS */
extern const char *imb_ext_image[];
extern const char *imb_ext_movie[];
extern const char *imb_ext_audio[];

View File

@ -80,11 +80,11 @@ void imb_filetypes_exit(void);
* \{ */
bool imb_is_a_png(const unsigned char *mem, size_t size);
struct ImBuf *imb_loadpng(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_savepng(struct ImBuf *ibuf, const char *filepath, int flags);
struct ImBuf *imb_load_png(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_save_png(struct ImBuf *ibuf, const char *filepath, int flags);
/** \} */
@ -92,12 +92,12 @@ bool imb_savepng(struct ImBuf *ibuf, const char *filepath, int flags);
/** \name Format: TARGA (#IMB_FTYPE_TGA)
* \{ */
bool imb_is_a_targa(const unsigned char *buf, size_t size);
struct ImBuf *imb_loadtarga(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_savetarga(struct ImBuf *ibuf, const char *filepath, int flags);
bool imb_is_a_tga(const unsigned char *mem, size_t size);
struct ImBuf *imb_load_tga(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_save_tga(struct ImBuf *ibuf, const char *filepath, int flags);
/** \} */
@ -157,12 +157,12 @@ struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
* \{ */
bool imb_is_a_bmp(const unsigned char *buf, size_t size);
struct ImBuf *imb_bmp_decode(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
struct ImBuf *imb_load_bmp(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
bool imb_savebmp(struct ImBuf *ibuf, const char *filepath, int flags);
bool imb_save_bmp(struct ImBuf *ibuf, const char *filepath, int flags);
/** \} */
@ -197,11 +197,11 @@ struct ImBuf *imb_load_dpx(const unsigned char *mem,
* \{ */
bool imb_is_a_hdr(const unsigned char *buf, size_t size);
struct ImBuf *imb_loadhdr(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_savehdr(struct ImBuf *ibuf, const char *filepath, int flags);
struct ImBuf *imb_load_hdr(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
bool imb_save_hdr(struct ImBuf *ibuf, const char *filepath, int flags);
/** \} */
@ -209,7 +209,6 @@ bool imb_savehdr(struct ImBuf *ibuf, const char *filepath, int flags);
/** \name Format: TIFF (#IMB_FTYPE_TIF)
* \{ */
void imb_inittiff(void);
bool imb_is_a_tiff(const unsigned char *buf, size_t size);
/**
* Loads a TIFF file.
@ -220,10 +219,10 @@ bool imb_is_a_tiff(const unsigned char *buf, size_t size);
*
* \return A newly allocated #ImBuf structure if successful, otherwise NULL.
*/
struct ImBuf *imb_loadtiff(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
struct ImBuf *imb_load_tiff(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
/**
* Saves a TIFF file.
*
@ -238,12 +237,12 @@ struct ImBuf *imb_loadtiff(const unsigned char *mem,
*
* \return 1 if the function is successful, 0 on failure.
*/
bool imb_savetiff(struct ImBuf *ibuf, const char *filepath, int flags);
bool imb_save_tiff(struct ImBuf *ibuf, const char *filepath, int flags);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Format: TIFF (#IMB_FTYPE_WEBP)
/** \name Format: WEBP (#IMB_FTYPE_WEBP)
* \{ */
bool imb_is_a_webp(const unsigned char *buf, size_t size);
@ -261,13 +260,26 @@ bool imb_savewebp(struct ImBuf *ibuf, const char *name, int flags);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Format: DDS (#IMB_FTYPE_DDS)
* \{ */
bool imb_is_a_dds(const unsigned char *buf, size_t size);
struct ImBuf *imb_load_dds(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Format: PSD (#IMB_FTYPE_PSD)
* \{ */
bool imb_is_a_psd(const unsigned char *buf, size_t size);
struct ImBuf *imb_load_psd(const uchar *mem,
struct ImBuf *imb_load_psd(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);

View File

@ -1,383 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/** \file
* \ingroup imbuf
*/
#include <math.h>
#include "BLI_fileops.h"
#include "BLI_utildefines.h"
#include "imbuf.h"
#include "IMB_filetype.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
/* Some code copied from article on microsoft.com,
* copied here for enhanced BMP support in the future:
* http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0197/mfcp1/mfcp1.htm&nav=/msj/0197/newnav.htm
*/
typedef struct BMPINFOHEADER {
uint biSize;
uint biWidth;
uint biHeight;
ushort biPlanes;
ushort biBitCount;
uint biCompression;
uint biSizeImage;
uint biXPelsPerMeter;
uint biYPelsPerMeter;
uint biClrUsed;
uint biClrImportant;
} BMPINFOHEADER;
#if 0
typedef struct BMPHEADER {
ushort biType;
uint biSize;
ushort biRes1;
ushort biRes2;
uint biOffBits;
} BMPHEADER;
#endif
#define BMP_FILEHEADER_SIZE 14
#define CHECK_HEADER_FIELD(_mem, _field) ((_mem[0] == _field[0]) && (_mem[1] == _field[1]))
#define CHECK_HEADER_FIELD_BMP(_mem) \
(CHECK_HEADER_FIELD(_mem, "BM") || CHECK_HEADER_FIELD(_mem, "BA") || \
CHECK_HEADER_FIELD(_mem, "CI") || CHECK_HEADER_FIELD(_mem, "CP") || \
CHECK_HEADER_FIELD(_mem, "IC") || CHECK_HEADER_FIELD(_mem, "PT"))
static bool checkbmp(const uchar *mem, const size_t size)
{
if (size < (BMP_FILEHEADER_SIZE + sizeof(BMPINFOHEADER))) {
return false;
}
if (!CHECK_HEADER_FIELD_BMP(mem)) {
return false;
}
bool ok = false;
BMPINFOHEADER bmi;
uint u;
/* Skip file-header. */
mem += BMP_FILEHEADER_SIZE;
/* for systems where an int needs to be 4 bytes aligned */
memcpy(&bmi, mem, sizeof(bmi));
u = LITTLE_LONG(bmi.biSize);
/* we only support uncompressed images for now. */
if (u >= sizeof(BMPINFOHEADER)) {
if (bmi.biCompression == 0) {
u = LITTLE_SHORT(bmi.biBitCount);
if (u > 0 && u <= 32) {
ok = true;
}
}
}
return ok;
}
bool imb_is_a_bmp(const uchar *buf, size_t size)
{
return checkbmp(buf, size);
}
static size_t imb_bmp_calc_row_size_in_bytes(size_t x, size_t depth)
{
/* https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader#calculating-surface-stride
*/
return (((x * depth) + 31) & ~31) >> 3;
}
ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
ImBuf *ibuf = NULL;
BMPINFOHEADER bmi;
int ibuf_depth;
const uchar *bmp;
uchar *rect;
ushort col;
bool top_to_bottom = false;
if (checkbmp(mem, size) == 0) {
return NULL;
}
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
/* For systems where an int needs to be 4 bytes aligned. */
memcpy(&bmi, mem + BMP_FILEHEADER_SIZE, sizeof(bmi));
const size_t palette_offset = (size_t)BMP_FILEHEADER_SIZE + LITTLE_LONG(bmi.biSize);
const int depth = LITTLE_SHORT(bmi.biBitCount);
const int xppm = LITTLE_LONG(bmi.biXPelsPerMeter);
const int yppm = LITTLE_LONG(bmi.biYPelsPerMeter);
const int x = LITTLE_LONG(bmi.biWidth);
int y = LITTLE_LONG(bmi.biHeight);
/* Negative height means bitmap is stored top-to-bottom. */
if (y < 0) {
y = -y;
top_to_bottom = true;
}
/* Validate and cross-check offsets and sizes. */
if (x < 1 || !ELEM(depth, 1, 4, 8, 16, 24, 32)) {
return NULL;
}
const size_t pixel_data_offset = (size_t)LITTLE_LONG(*(int *)(mem + 10));
const size_t header_bytes = BMP_FILEHEADER_SIZE + sizeof(BMPINFOHEADER);
const size_t num_actual_data_bytes = size - pixel_data_offset;
const size_t row_size_in_bytes = imb_bmp_calc_row_size_in_bytes(x, depth);
const size_t num_expected_data_bytes = row_size_in_bytes * y;
if (num_actual_data_bytes < num_expected_data_bytes || num_actual_data_bytes > size ||
pixel_data_offset < header_bytes || pixel_data_offset > (size - num_expected_data_bytes) ||
palette_offset < header_bytes || palette_offset > pixel_data_offset) {
return NULL;
}
if (depth <= 8) {
ibuf_depth = 24;
}
else {
ibuf_depth = depth;
}
bmp = mem + pixel_data_offset;
#if 0
printf("palette_offset: %d, x: %d y: %d, depth: %d\n", palette_offset, x, y, depth);
#endif
if (flags & IB_test) {
ibuf = IMB_allocImBuf(x, y, ibuf_depth, 0);
}
else {
ibuf = IMB_allocImBuf(x, y, ibuf_depth, IB_rect);
if (!ibuf) {
return NULL;
}
rect = (uchar *)ibuf->rect;
if (depth <= 8) {
const char(*palette)[4] = (const char(*)[4])(mem + palette_offset);
const int startmask = ((1 << depth) - 1) << 8;
for (size_t i = y; i > 0; i--) {
int bitoffs = 8;
int bitmask = startmask;
int nbytes = 0;
const char *pcol;
if (top_to_bottom) {
rect = (uchar *)&ibuf->rect[(i - 1) * x];
}
for (size_t j = x; j > 0; j--) {
bitoffs -= depth;
bitmask >>= depth;
const int index = (bmp[0] & bitmask) >> bitoffs;
pcol = palette[index];
/* intentionally BGR -> RGB */
rect[0] = pcol[2];
rect[1] = pcol[1];
rect[2] = pcol[0];
rect[3] = 255;
rect += 4;
if (bitoffs == 0) {
/* Advance to the next byte */
bitoffs = 8;
bitmask = startmask;
nbytes += 1;
bmp += 1;
}
}
/* Advance to the next row */
bmp += (row_size_in_bytes - nbytes);
}
}
else if (depth == 16) {
for (size_t i = y; i > 0; i--) {
if (top_to_bottom) {
rect = (uchar *)&ibuf->rect[(i - 1) * x];
}
for (size_t j = x; j > 0; j--) {
col = bmp[0] + (bmp[1] << 8);
rect[0] = ((col >> 10) & 0x1f) << 3;
rect[1] = ((col >> 5) & 0x1f) << 3;
rect[2] = ((col >> 0) & 0x1f) << 3;
rect[3] = 255;
rect += 4;
bmp += 2;
}
}
}
else if (depth == 24) {
const int x_pad = x % 4;
for (size_t i = y; i > 0; i--) {
if (top_to_bottom) {
rect = (uchar *)&ibuf->rect[(i - 1) * x];
}
for (size_t j = x; j > 0; j--) {
rect[0] = bmp[2];
rect[1] = bmp[1];
rect[2] = bmp[0];
rect[3] = 255;
rect += 4;
bmp += 3;
}
/* for 24-bit images, rows are padded to multiples of 4 */
bmp += x_pad;
}
}
else if (depth == 32) {
for (size_t i = y; i > 0; i--) {
if (top_to_bottom) {
rect = (uchar *)&ibuf->rect[(i - 1) * x];
}
for (size_t j = x; j > 0; j--) {
rect[0] = bmp[2];
rect[1] = bmp[1];
rect[2] = bmp[0];
rect[3] = bmp[3];
rect += 4;
bmp += 4;
}
}
}
}
if (ibuf) {
ibuf->ppm[0] = xppm;
ibuf->ppm[1] = yppm;
ibuf->ftype = IMB_FTYPE_BMP;
}
return ibuf;
}
#undef CHECK_HEADER_FIELD_BMP
#undef CHECK_HEADER_FIELD
/* Couple of helper functions for writing our data */
static int putIntLSB(uint ui, FILE *ofile)
{
putc((ui >> 0) & 0xFF, ofile);
putc((ui >> 8) & 0xFF, ofile);
putc((ui >> 16) & 0xFF, ofile);
return putc((ui >> 24) & 0xFF, ofile);
}
static int putShortLSB(ushort us, FILE *ofile)
{
putc((us >> 0) & 0xFF, ofile);
return putc((us >> 8) & 0xFF, ofile);
}
bool imb_savebmp(ImBuf *ibuf, const char *filepath, int UNUSED(flags))
{
BMPINFOHEADER infoheader;
const size_t bytes_per_pixel = (ibuf->planes + 7) >> 3;
BLI_assert(ELEM(bytes_per_pixel, 1, 3));
const size_t pad_bytes_per_scanline = (4 - ibuf->x * bytes_per_pixel % 4) % 4;
const size_t bytesize = (ibuf->x * bytes_per_pixel + pad_bytes_per_scanline) * ibuf->y;
const uchar *data = (const uchar *)ibuf->rect;
FILE *ofile = BLI_fopen(filepath, "wb");
if (ofile == NULL) {
return 0;
}
const bool is_grayscale = bytes_per_pixel == 1;
const size_t palette_size = is_grayscale ? 255 * 4 : 0; /* RGBA32 */
const size_t pixel_array_start = BMP_FILEHEADER_SIZE + sizeof(infoheader) + palette_size;
putShortLSB(19778, ofile); /* "BM" */
putIntLSB(bytesize + pixel_array_start, ofile); /* Total file size */
putShortLSB(0, ofile); /* Res1 */
putShortLSB(0, ofile); /* Res2 */
putIntLSB(pixel_array_start, ofile); /* offset to start of pixel array */
putIntLSB(sizeof(infoheader), ofile);
putIntLSB(ibuf->x, ofile);
putIntLSB(ibuf->y, ofile);
putShortLSB(1, ofile);
putShortLSB(is_grayscale ? 8 : 24, ofile);
putIntLSB(0, ofile);
putIntLSB(bytesize, ofile);
putIntLSB(round(ibuf->ppm[0]), ofile);
putIntLSB(round(ibuf->ppm[1]), ofile);
putIntLSB(0, ofile);
putIntLSB(0, ofile);
/* color palette table, which is just every grayscale color, full alpha */
if (is_grayscale) {
for (char i = 0; i < 255; i++) {
putc(i, ofile);
putc(i, ofile);
putc(i, ofile);
putc(0xFF, ofile);
}
}
if (is_grayscale) {
for (size_t y = 0; y < ibuf->y; y++) {
for (size_t x = 0; x < ibuf->x; x++) {
const size_t ptr = (x + y * ibuf->x) * 4;
if (putc(data[ptr], ofile) == EOF) {
return 0;
}
}
/* Add padding here. */
for (size_t t = 0; t < pad_bytes_per_scanline; t++) {
if (putc(0, ofile) == EOF) {
return 0;
}
}
}
}
else {
/* Need to write out padded image data in BGR format. */
for (size_t y = 0; y < ibuf->y; y++) {
for (size_t x = 0; x < ibuf->x; x++) {
const size_t ptr = (x + y * ibuf->x) * 4;
if (putc(data[ptr + 2], ofile) == EOF) {
return 0;
}
if (putc(data[ptr + 1], ofile) == EOF) {
return 0;
}
if (putc(data[ptr], ofile) == EOF) {
return 0;
}
}
/* Add padding here. */
for (size_t t = 0; t < pad_bytes_per_scanline; t++) {
if (putc(0, ofile) == EOF) {
return 0;
}
}
}
}
fflush(ofile);
fclose(ofile);
return 1;
}

View File

@ -182,21 +182,3 @@ ImBuf *imb_load_cineon(const uchar *mem, size_t size, int flags, char colorspace
}
return imb_load_dpx_cineon(mem, size, 1, flags, colorspace);
}
bool imb_save_dpx(struct ImBuf *buf, const char *filepath, int flags)
{
return imb_save_dpx_cineon(buf, filepath, 0, flags);
}
bool imb_is_a_dpx(const uchar *buf, size_t size)
{
return logImageIsDpx(buf, size);
}
ImBuf *imb_load_dpx(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
if (!imb_is_a_dpx(mem, size)) {
return NULL;
}
return imb_load_dpx_cineon(mem, size, 0, flags, colorspace);
}

View File

@ -20,10 +20,6 @@
# include "openexr/openexr_api.h"
#endif
#ifdef WITH_DDS
# include "dds/dds_api.h"
#endif
const ImFileType IMB_FILE_TYPES[] = {
{
.init = NULL,
@ -41,10 +37,10 @@ const ImFileType IMB_FILE_TYPES[] = {
.init = NULL,
.exit = NULL,
.is_a = imb_is_a_png,
.load = imb_loadpng,
.load = imb_load_png,
.load_filepath = NULL,
.load_filepath_thumbnail = NULL,
.save = imb_savepng,
.save = imb_save_png,
.flag = 0,
.filetype = IMB_FTYPE_PNG,
.default_save_role = COLOR_ROLE_DEFAULT_BYTE,
@ -53,10 +49,10 @@ const ImFileType IMB_FILE_TYPES[] = {
.init = NULL,
.exit = NULL,
.is_a = imb_is_a_bmp,
.load = imb_bmp_decode,
.load = imb_load_bmp,
.load_filepath = NULL,
.load_filepath_thumbnail = NULL,
.save = imb_savebmp,
.save = imb_save_bmp,
.flag = 0,
.filetype = IMB_FTYPE_BMP,
.default_save_role = COLOR_ROLE_DEFAULT_BYTE,
@ -64,11 +60,11 @@ const ImFileType IMB_FILE_TYPES[] = {
{
.init = NULL,
.exit = NULL,
.is_a = imb_is_a_targa,
.load = imb_loadtarga,
.is_a = imb_is_a_tga,
.load = imb_load_tga,
.load_filepath = NULL,
.load_filepath_thumbnail = NULL,
.save = imb_savetarga,
.save = imb_save_tga,
.flag = 0,
.filetype = IMB_FTYPE_TGA,
.default_save_role = COLOR_ROLE_DEFAULT_BYTE,
@ -111,34 +107,30 @@ const ImFileType IMB_FILE_TYPES[] = {
.default_save_role = COLOR_ROLE_DEFAULT_FLOAT,
},
#endif
#ifdef WITH_TIFF
{
.init = imb_inittiff,
.init = NULL,
.exit = NULL,
.is_a = imb_is_a_tiff,
.load = imb_loadtiff,
.load = imb_load_tiff,
.load_filepath = NULL,
.load_filepath_thumbnail = NULL,
.save = imb_savetiff,
.save = imb_save_tiff,
.flag = 0,
.filetype = IMB_FTYPE_TIF,
.default_save_role = COLOR_ROLE_DEFAULT_BYTE,
},
#endif
#ifdef WITH_HDR
{
.init = NULL,
.exit = NULL,
.is_a = imb_is_a_hdr,
.load = imb_loadhdr,
.load = imb_load_hdr,
.load_filepath = NULL,
.load_filepath_thumbnail = NULL,
.save = imb_savehdr,
.save = imb_save_hdr,
.flag = IM_FTYPE_FLOAT,
.filetype = IMB_FTYPE_RADHDR,
.default_save_role = COLOR_ROLE_DEFAULT_FLOAT,
},
#endif
#ifdef WITH_OPENEXR
{
.init = imb_initopenexr,
@ -167,7 +159,6 @@ const ImFileType IMB_FILE_TYPES[] = {
.default_save_role = COLOR_ROLE_DEFAULT_BYTE,
},
#endif
#ifdef WITH_DDS
{
.init = NULL,
.exit = NULL,
@ -180,7 +171,6 @@ const ImFileType IMB_FILE_TYPES[] = {
.filetype = IMB_FTYPE_DDS,
.default_save_role = COLOR_ROLE_DEFAULT_BYTE,
},
#endif
{
.init = NULL,
.exit = NULL,

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "oiio/openimageio_support.hh"
#include "IMB_filetype.h"
#include "IMB_imbuf_types.h"
OIIO_NAMESPACE_USING
using namespace blender::imbuf;
extern "C" {
bool imb_is_a_bmp(const uchar *mem, size_t size)
{
return imb_oiio_check(mem, size, "bmp");
}
ImBuf *imb_load_bmp(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
ImageSpec config, spec;
/* Keep historical behavior - do not use a 1-channel format for a black-white image. */
config.attribute("bmp:monochrome_detect", 0);
ReadContext ctx{mem, size, "bmp", IMB_FTYPE_BMP, flags};
return imb_oiio_read(ctx, config, colorspace, spec);
}
bool imb_save_bmp(struct ImBuf *ibuf, const char *filepath, int flags)
{
const int file_channels = ibuf->planes >> 3;
const TypeDesc data_format = TypeDesc::UINT8;
WriteContext ctx = imb_create_write_context("bmp", ibuf, flags, false);
ImageSpec file_spec = imb_create_write_spec(ctx, file_channels, data_format);
return imb_oiio_write(ctx, filepath, file_spec);
}
}

View File

@ -0,0 +1,319 @@
/* SPDX-License-Identifier: GPL-2.0-or-later AND BSD-3-Clause
* Copyright 2009 Google Inc. All rights reserved. (BSD-3-Clause)
* Copyright 2023 Blender Foundation (GPL-2.0-or-later). */
/**
* Some portions of this file are from the Chromium project and have been adapted
* for Blender use when flipping DDS images to the OpenGL convention.
*/
#include <algorithm>
#include <memory>
#include "oiio/openimageio_support.hh"
#include "IMB_filetype.h"
#include "IMB_imbuf_types.h"
#ifdef __BIG_ENDIAN__
# include "BLI_endian_switch.h"
#endif
OIIO_NAMESPACE_USING
using namespace blender::imbuf;
using std::unique_ptr;
extern "C" {
static void LoadDXTCImage(ImBuf *ibuf, Filesystem::IOMemReader &mem_reader);
bool imb_is_a_dds(const uchar *buf, size_t size)
{
return imb_oiio_check(buf, size, "dds");
}
ImBuf *imb_load_dds(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
ImageSpec config, spec;
ReadContext ctx{mem, size, "dds", IMB_FTYPE_DDS, flags};
ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec);
/* Load compressed DDS information if available. */
if (ibuf && (flags & IB_test) == 0) {
Filesystem::IOMemReader mem_reader(cspan<uchar>(mem, size));
LoadDXTCImage(ibuf, mem_reader);
}
return ibuf;
}
/* A function that flips a DXTC block. */
using FlipBlockFunction = void (*)(uint8_t *block);
/* Flips a full DXT1 block in the y direction. */
static void FlipDXT1BlockFull(uint8_t *block)
{
/* A DXT1 block layout is:
* [0-1] color0.
* [2-3] color1.
* [4-7] color bitmap, 2 bits per pixel.
* So each of the 4-7 bytes represents one line, flipping a block is just
* flipping those bytes. */
uint8_t tmp = block[4];
block[4] = block[7];
block[7] = tmp;
tmp = block[5];
block[5] = block[6];
block[6] = tmp;
}
/* Flips the first 2 lines of a DXT1 block in the y direction. */
static void FlipDXT1BlockHalf(uint8_t *block)
{
/* See layout above. */
uint8_t tmp = block[4];
block[4] = block[5];
block[5] = tmp;
}
/* Flips a full DXT3 block in the y direction. */
static void FlipDXT3BlockFull(uint8_t *block)
{
/* A DXT3 block layout is:
* [0-7] alpha bitmap, 4 bits per pixel.
* [8-15] a DXT1 block. */
/* We can flip the alpha bits at the byte level (2 bytes per line). */
uint8_t tmp = block[0];
block[0] = block[6];
block[6] = tmp;
tmp = block[1];
block[1] = block[7];
block[7] = tmp;
tmp = block[2];
block[2] = block[4];
block[4] = tmp;
tmp = block[3];
block[3] = block[5];
block[5] = tmp;
/* And flip the DXT1 block using the above function. */
FlipDXT1BlockFull(block + 8);
}
/* Flips the first 2 lines of a DXT3 block in the y direction. */
static void FlipDXT3BlockHalf(uint8_t *block)
{
/* See layout above. */
uint8_t tmp = block[0];
block[0] = block[2];
block[2] = tmp;
tmp = block[1];
block[1] = block[3];
block[3] = tmp;
FlipDXT1BlockHalf(block + 8);
}
/* Flips a full DXT5 block in the y direction. */
static void FlipDXT5BlockFull(uint8_t *block)
{
/* A DXT5 block layout is:
* [0] alpha0.
* [1] alpha1.
* [2-7] alpha bitmap, 3 bits per pixel.
* [8-15] a DXT1 block. */
/* The alpha bitmap doesn't easily map lines to bytes, so we have to
* interpret it correctly. Extracted from
* http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
*
* The 6 "bits" bytes of the block are decoded into one 48-bit integer:
*
* bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
* 256 * (bits_4 + 256 * bits_5))))
*
* bits is a 48-bit unsigned-integer, from which a three-bit control code
* is extracted for a texel at location (x,y) in the block using:
*
* code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
*
* where bit 47 is the most significant and bit 0 is the least
* significant bit. */
uint line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]);
uint line_2_3 = block[5] + 256 * (block[6] + 256 * block[7]);
/* swap lines 0 and 1 in line_0_1. */
uint line_1_0 = ((line_0_1 & 0x000fff) << 12) | ((line_0_1 & 0xfff000) >> 12);
/* swap lines 2 and 3 in line_2_3. */
uint line_3_2 = ((line_2_3 & 0x000fff) << 12) | ((line_2_3 & 0xfff000) >> 12);
block[2] = line_3_2 & 0xff;
block[3] = (line_3_2 & 0xff00) >> 8;
block[4] = (line_3_2 & 0xff0000) >> 16;
block[5] = line_1_0 & 0xff;
block[6] = (line_1_0 & 0xff00) >> 8;
block[7] = (line_1_0 & 0xff0000) >> 16;
/* And flip the DXT1 block using the above function. */
FlipDXT1BlockFull(block + 8);
}
/* Flips the first 2 lines of a DXT5 block in the y direction. */
static void FlipDXT5BlockHalf(uint8_t *block)
{
/* See layout above. */
uint line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]);
uint line_1_0 = ((line_0_1 & 0x000fff) << 12) | ((line_0_1 & 0xfff000) >> 12);
block[2] = line_1_0 & 0xff;
block[3] = (line_1_0 & 0xff00) >> 8;
block[4] = (line_1_0 & 0xff0000) >> 16;
FlipDXT1BlockHalf(block + 8);
}
/**
* Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate.
*
* Use to flip vertically to fit OpenGL convention.
*/
static void FlipDXTCImage(ImBuf *ibuf)
{
uint32_t width = ibuf->x;
uint32_t height = ibuf->y;
uint32_t levels = ibuf->dds_data.nummipmaps;
int fourcc = ibuf->dds_data.fourcc;
uint8_t *data = ibuf->dds_data.data;
int data_size = ibuf->dds_data.size;
uint32_t *num_valid_levels = &ibuf->dds_data.nummipmaps;
*num_valid_levels = 0;
/* Must have valid dimensions. */
if (width == 0 || height == 0) {
return;
}
/* Height must be a power-of-two. */
if ((height & (height - 1)) != 0) {
return;
}
FlipBlockFunction full_block_function;
FlipBlockFunction half_block_function;
uint block_bytes = 0;
switch (fourcc) {
case FOURCC_DXT1:
full_block_function = FlipDXT1BlockFull;
half_block_function = FlipDXT1BlockHalf;
block_bytes = 8;
break;
case FOURCC_DXT3:
full_block_function = FlipDXT3BlockFull;
half_block_function = FlipDXT3BlockHalf;
block_bytes = 16;
break;
case FOURCC_DXT5:
full_block_function = FlipDXT5BlockFull;
half_block_function = FlipDXT5BlockHalf;
block_bytes = 16;
break;
default:
return;
}
*num_valid_levels = levels;
uint mip_width = width;
uint mip_height = height;
const uint8_t *data_end = data + data_size;
for (uint i = 0; i < levels; i++) {
uint blocks_per_row = (mip_width + 3) / 4;
uint blocks_per_col = (mip_height + 3) / 4;
uint blocks = blocks_per_row * blocks_per_col;
if (data + block_bytes * blocks > data_end) {
/* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
* on a malformed files. */
*num_valid_levels = i;
break;
}
if (mip_height == 1) {
/* no flip to do, and we're done. */
break;
}
if (mip_height == 2) {
/* flip the first 2 lines in each block. */
for (uint i = 0; i < blocks_per_row; i++) {
half_block_function(data + i * block_bytes);
}
}
else {
/* flip each block. */
for (uint i = 0; i < blocks; i++) {
full_block_function(data + i * block_bytes);
}
/* Swap each block line in the first half of the image with the
* corresponding one in the second half.
* note that this is a no-op if mip_height is 4. */
uint row_bytes = block_bytes * blocks_per_row;
uint8_t *temp_line = new uint8_t[row_bytes];
for (uint y = 0; y < blocks_per_col / 2; y++) {
uint8_t *line1 = data + y * row_bytes;
uint8_t *line2 = data + (blocks_per_col - y - 1) * row_bytes;
memcpy(temp_line, line1, row_bytes);
memcpy(line1, line2, row_bytes);
memcpy(line2, temp_line, row_bytes);
}
delete[] temp_line;
}
/* mip levels are contiguous. */
data += block_bytes * blocks;
mip_width = std::max(1U, mip_width >> 1);
mip_height = std::max(1U, mip_height >> 1);
}
}
static void LoadDXTCImage(ImBuf *ibuf, Filesystem::IOMemReader &mem_reader)
{
/* Reach into memory and pull out the pixel format flags and mipmap counts. This is safe if
* we've made it this far. */
uint32_t flags = 0;
mem_reader.pread(&flags, sizeof(uint32_t), 8);
mem_reader.pread(&ibuf->dds_data.nummipmaps, sizeof(uint32_t), 28);
mem_reader.pread(&ibuf->dds_data.fourcc, sizeof(uint32_t), 84);
#ifdef __BIG_ENDIAN__
BLI_endian_switch_uint32(&ibuf->dds_data.nummipmaps);
#endif
const uint32_t DDSD_MIPMAPCOUNT = 0x00020000U;
if ((flags & DDSD_MIPMAPCOUNT) == 0) {
ibuf->dds_data.nummipmaps = 1;
}
/* Load the compressed data. */
if (ibuf->dds_data.fourcc != FOURCC_DDS) {
uint32_t dds_header_size = 128;
if (ibuf->dds_data.fourcc == FOURCC_DX10) {
dds_header_size += 20;
}
ibuf->dds_data.size = mem_reader.size() - dds_header_size;
ibuf->dds_data.data = (uchar *)malloc(ibuf->dds_data.size);
mem_reader.pread(ibuf->dds_data.data, ibuf->dds_data.size, dds_header_size);
/* Flip compressed image data to match OpenGL convention. */
FlipDXTCImage(ibuf);
}
}
}

View File

@ -0,0 +1,82 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "oiio/openimageio_support.hh"
#include "IMB_colormanagement.h"
#include "IMB_filetype.h"
#include "IMB_imbuf_types.h"
OIIO_NAMESPACE_USING
using namespace blender::imbuf;
extern "C" {
bool imb_is_a_dpx(const uchar *mem, size_t size)
{
return imb_oiio_check(mem, size, "dpx");
}
ImBuf *imb_load_dpx(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
ImageSpec config, spec;
ReadContext ctx{mem, size, "dpx", IMB_FTYPE_DPX, flags};
ctx.use_colorspace_role = COLOR_ROLE_DEFAULT_FLOAT;
ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec);
if (ibuf) {
if (flags & IB_alphamode_detect) {
ibuf->flags |= IB_alphamode_premul;
}
}
return ibuf;
}
bool imb_save_dpx(struct ImBuf *ibuf, const char *filepath, int flags)
{
int bits_per_sample = 8;
if (ibuf->foptions.flag & CINEON_10BIT) {
bits_per_sample = 10;
}
else if (ibuf->foptions.flag & CINEON_12BIT) {
bits_per_sample = 12;
}
else if (ibuf->foptions.flag & CINEON_16BIT) {
bits_per_sample = 16;
}
const int file_channels = ibuf->planes >> 3;
const TypeDesc data_format = bits_per_sample == 8 ? TypeDesc::UINT8 : TypeDesc::UINT16;
WriteContext ctx = imb_create_write_context("dpx", ibuf, flags);
ImageSpec file_spec = imb_create_write_spec(ctx, file_channels, data_format);
const float max_value = powf(2, bits_per_sample) - 1.0f;
file_spec.attribute("oiio:BitsPerSample", bits_per_sample);
file_spec.attribute("dpx:WhiteLevel", 685.0f / 1023.0f * max_value);
file_spec.attribute("dpx:BlackLevel", 95.0f / 1023.0f * max_value);
file_spec.attribute("dpx:HighData", max_value);
file_spec.attribute("dpx:LowData", 0);
file_spec.attribute("dpx:LowQuantity", 0.0f);
if (ibuf->foptions.flag & CINEON_LOG) {
/* VERIFY: This matches previous code but seems odd. Needs a comment if confirmed. */
file_spec.attribute("dpx:Transfer", "Printing density");
file_spec.attribute("dpx:HighQuantity", 2.048f);
}
else {
file_spec.attribute("dpx:Transfer", "Linear");
file_spec.attribute("dpx:HighQuantity", max_value);
}
if (ELEM(bits_per_sample, 8, 16)) {
file_spec.attribute("dpx:Packing", "Packed");
}
else {
file_spec.attribute("dpx:Packing", "Filled, method A");
}
return imb_oiio_write(ctx, filepath, file_spec);
}
}

View File

@ -0,0 +1,50 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "oiio/openimageio_support.hh"
#include "IMB_filetype.h"
#include "IMB_imbuf_types.h"
OIIO_NAMESPACE_USING
using namespace blender::imbuf;
extern "C" {
bool imb_is_a_hdr(const uchar *mem, size_t size)
{
return imb_oiio_check(mem, size, "hdr");
}
ImBuf *imb_load_hdr(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
ImageSpec config, spec;
ReadContext ctx{mem, size, "hdr", IMB_FTYPE_RADHDR, flags};
/* Always create ImBufs with a 4th alpha channel despite the format only supporting 3. */
ctx.use_all_planes = true;
ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec);
if (ibuf) {
if (flags & IB_alphamode_detect) {
ibuf->flags |= IB_alphamode_premul;
}
if (flags & IB_rect) {
IMB_rect_from_float(ibuf);
}
}
return ibuf;
}
bool imb_save_hdr(struct ImBuf *ibuf, const char *filepath, int flags)
{
const int file_channels = 3;
const TypeDesc data_format = TypeDesc::FLOAT;
WriteContext ctx = imb_create_write_context("hdr", ibuf, flags);
ImageSpec file_spec = imb_create_write_spec(ctx, file_channels, data_format);
return imb_oiio_write(ctx, filepath, file_spec);
}
}

View File

@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "oiio/openimageio_support.hh"
#include "IMB_colormanagement.h"
#include "IMB_filetype.h"
#include "IMB_imbuf_types.h"
OIIO_NAMESPACE_USING
using namespace blender::imbuf;
extern "C" {
bool imb_is_a_png(const uchar *mem, size_t size)
{
return imb_oiio_check(mem, size, "png");
}
ImBuf *imb_load_png(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
ImageSpec config, spec;
config.attribute("oiio:UnassociatedAlpha", 1);
ReadContext ctx{mem, size, "png", IMB_FTYPE_PNG, flags};
/* Both 8 and 16 bit PNGs should be in default byte colorspace. */
ctx.use_colorspace_role = COLOR_ROLE_DEFAULT_BYTE;
ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec);
if (ibuf) {
if (spec.format == TypeDesc::UINT16) {
ibuf->flags |= PNG_16BIT;
}
}
return ibuf;
}
bool imb_save_png(struct ImBuf *ibuf, const char *filepath, int flags)
{
const bool is_16bit = (ibuf->foptions.flag & PNG_16BIT);
const int file_channels = ibuf->planes >> 3;
const TypeDesc data_format = is_16bit ? TypeDesc::UINT16 : TypeDesc::UINT8;
WriteContext ctx = imb_create_write_context("png", ibuf, flags, is_16bit);
ImageSpec file_spec = imb_create_write_spec(ctx, file_channels, data_format);
/* Skip if the float buffer was managed already. */
if (is_16bit && (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA))) {
file_spec.attribute("oiio:UnassociatedAlpha", 0);
}
else {
file_spec.attribute("oiio:UnassociatedAlpha", 1);
}
int compression = (int)((float)ibuf->foptions.quality / 11.1111f);
compression = compression < 0 ? 0 : (compression > 9 ? 9 : compression);
file_spec.attribute("png:compressionLevel", compression);
return imb_oiio_write(ctx, filepath, file_spec);
}
}

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "oiio/openimageio_support.hh"
#include "IMB_filetype.h"
#include "IMB_imbuf_types.h"
OIIO_NAMESPACE_USING
using namespace blender::imbuf;
extern "C" {
bool imb_is_a_tga(const uchar *mem, size_t size)
{
return imb_oiio_check(mem, size, "tga");
}
ImBuf *imb_load_tga(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
ImageSpec config, spec;
config.attribute("oiio:UnassociatedAlpha", 1);
ReadContext ctx{mem, size, "tga", IMB_FTYPE_TGA, flags};
return imb_oiio_read(ctx, config, colorspace, spec);
}
bool imb_save_tga(struct ImBuf *ibuf, const char *filepath, int flags)
{
const int file_channels = ibuf->planes >> 3;
const TypeDesc data_format = TypeDesc::UINT8;
WriteContext ctx = imb_create_write_context("tga", ibuf, flags, false);
ImageSpec file_spec = imb_create_write_spec(ctx, file_channels, data_format);
file_spec.attribute("oiio:UnassociatedAlpha", 1);
file_spec.attribute("compression", (ibuf->foptions.flag & RAWTGA) ? "none" : "rle");
return imb_oiio_write(ctx, filepath, file_spec);
}
}

View File

@ -0,0 +1,69 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "oiio/openimageio_support.hh"
#include "IMB_colormanagement.h"
#include "IMB_filetype.h"
#include "IMB_imbuf_types.h"
OIIO_NAMESPACE_USING
using namespace blender::imbuf;
extern "C" {
bool imb_is_a_tiff(const uchar *mem, size_t size)
{
return imb_oiio_check(mem, size, "tif");
}
ImBuf *imb_load_tiff(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
ImageSpec config, spec;
config.attribute("oiio:UnassociatedAlpha", 1);
ReadContext ctx{mem, size, "tif", IMB_FTYPE_TIF, flags};
/* All TIFFs should be in default byte colorspace. */
ctx.use_colorspace_role = COLOR_ROLE_DEFAULT_BYTE;
ImBuf *ibuf = imb_oiio_read(ctx, config, colorspace, spec);
if (ibuf) {
if (flags & IB_alphamode_detect) {
if (spec.nchannels == 4 && spec.format == TypeDesc::UINT16) {
ibuf->flags |= IB_alphamode_premul;
}
}
}
return ibuf;
}
bool imb_save_tiff(struct ImBuf *ibuf, const char *filepath, int flags)
{
const bool is_16bit = ((ibuf->foptions.flag & TIF_16BIT) && ibuf->rect_float);
const int file_channels = ibuf->planes >> 3;
const TypeDesc data_format = is_16bit ? TypeDesc::UINT16 : TypeDesc::UINT8;
WriteContext ctx = imb_create_write_context("tif", ibuf, flags, is_16bit);
ImageSpec file_spec = imb_create_write_spec(ctx, file_channels, data_format);
if (is_16bit && file_channels == 4) {
file_spec.attribute("oiio:UnassociatedAlpha", 0);
}
else {
file_spec.attribute("oiio:UnassociatedAlpha", 1);
}
if (ibuf->foptions.flag & TIF_COMPRESS_DEFLATE) {
file_spec.attribute("compression", "zip");
}
else if (ibuf->foptions.flag & TIF_COMPRESS_LZW) {
file_spec.attribute("compression", "lzw");
}
else if (ibuf->foptions.flag & TIF_COMPRESS_PACKBITS) {
file_spec.attribute("compression", "packbits");
}
return imb_oiio_write(ctx, filepath, file_spec);
}
}

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "openimageio_support.hh"
#include <OpenImageIO/imagebuf.h>
#include <OpenImageIO/imagebufalgo.h>
#include "BLI_blenlib.h"
@ -289,10 +291,19 @@ bool imb_oiio_write(const WriteContext &ctx, const char *filepath, const ImageSp
return false;
}
auto write_op = [&out, &ctx]() {
return out->write_image(
ctx.mem_format, ctx.mem_start, ctx.mem_xstride, -ctx.mem_ystride, AutoStride);
};
ImageBuf orig_buf(ctx.mem_spec, ctx.mem_start, ctx.mem_xstride, -ctx.mem_ystride, AutoStride);
ImageBuf final_buf{};
/* Grayscale images need to be based on luminance weights rather than only
* using a single channel from the source. */
if (file_spec.nchannels == 1) {
float weights[4]{};
IMB_colormanagement_get_luminance_coefficients(weights);
ImageBufAlgo::channel_sum(final_buf, orig_buf, {weights, orig_buf.nchannels()});
}
else {
final_buf = std::move(orig_buf);
}
bool ok = false;
if (ctx.flags & IB_mem) {
@ -302,11 +313,11 @@ bool imb_oiio_write(const WriteContext &ctx, const char *filepath, const ImageSp
imb_addencodedbufferImBuf(ctx.ibuf);
out->set_ioproxy(&writer);
out->open("", file_spec);
ok = write_op();
ok = final_buf.write(out.get());
}
else {
out->open(filepath, file_spec);
ok = write_op();
ok = final_buf.write(out.get());
}
out->close();
@ -330,15 +341,15 @@ WriteContext imb_create_write_context(const char *file_format,
const int mem_channels = ibuf->channels ? ibuf->channels : 4;
ctx.mem_xstride = sizeof(float) * mem_channels;
ctx.mem_ystride = width * ctx.mem_xstride;
ctx.mem_format = TypeDesc::FLOAT;
ctx.mem_start = reinterpret_cast<uchar *>(ibuf->rect_float);
ctx.mem_spec = ImageSpec(width, height, mem_channels, TypeDesc::FLOAT);
}
else {
const int mem_channels = 4;
ctx.mem_xstride = sizeof(uchar) * mem_channels;
ctx.mem_ystride = width * ctx.mem_xstride;
ctx.mem_format = TypeDesc::UINT8;
ctx.mem_start = reinterpret_cast<uchar *>(ibuf->rect);
ctx.mem_spec = ImageSpec(width, height, mem_channels, TypeDesc::UINT8);
}
/* We always write using a negative y-stride so ensure we start at the end. */

View File

@ -40,13 +40,12 @@ struct ReadContext {
struct WriteContext {
const char *file_format;
ImBuf *ibuf;
int flags;
uchar *mem_start;
OIIO::stride_t mem_xstride;
OIIO::stride_t mem_ystride;
OIIO::TypeDesc mem_format;
uchar *mem_start;
int flags;
OIIO::ImageSpec mem_spec;
};
/**

View File

@ -1,814 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/** \file
* \ingroup imbuf
*
* \todo Save floats as 16 bits per channel, currently readonly.
*/
#include <png.h>
#include "BLI_fileops.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "DNA_ID.h" /* ID property definitions. */
#include "MEM_guardedalloc.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_allocimbuf.h"
#include "IMB_filetype.h"
#include "IMB_metadata.h"
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
typedef struct PNGReadStruct {
const uchar *data;
uint size;
uint seek;
} PNGReadStruct;
static void ReadData(png_structp png_ptr, png_bytep data, png_size_t length);
static void WriteData(png_structp png_ptr, png_bytep data, png_size_t length);
static void Flush(png_structp png_ptr);
BLI_INLINE ushort UPSAMPLE_8_TO_16(const uchar _val)
{
return (_val << 8) + _val;
}
bool imb_is_a_png(const uchar *mem, size_t size)
{
const int num_to_check = 8;
if (size < num_to_check) {
return false;
}
bool ok = false;
#if (PNG_LIBPNG_VER_MAJOR == 1) && (PNG_LIBPNG_VER_MINOR == 2)
/* Older version of libpng doesn't use const pointer to memory. */
ok = !png_sig_cmp((png_bytep)mem, 0, num_to_check);
#else
ok = !png_sig_cmp(mem, 0, num_to_check);
#endif
return ok;
}
static void Flush(png_structp png_ptr)
{
(void)png_ptr;
}
static void WriteData(png_structp png_ptr, png_bytep data, png_size_t length)
{
ImBuf *ibuf = (ImBuf *)png_get_io_ptr(png_ptr);
/* if buffer is too small increase it. */
while (ibuf->encodedsize + length > ibuf->encodedbuffersize) {
imb_enlargeencodedbufferImBuf(ibuf);
}
memcpy(ibuf->encodedbuffer + ibuf->encodedsize, data, length);
ibuf->encodedsize += length;
}
static void ReadData(png_structp png_ptr, png_bytep data, png_size_t length)
{
PNGReadStruct *rs = (PNGReadStruct *)png_get_io_ptr(png_ptr);
if (rs) {
if (length <= rs->size - rs->seek) {
memcpy(data, rs->data + rs->seek, length);
rs->seek += length;
return;
}
}
printf("Reached EOF while decoding PNG\n");
longjmp(png_jmpbuf(png_ptr), 1);
}
static float channel_colormanage_noop(float value)
{
return value;
}
/* wrap to avoid macro calling functions multiple times */
BLI_INLINE ushort ftoshort(float val)
{
return unit_float_to_ushort_clamp(val);
}
bool imb_savepng(struct ImBuf *ibuf, const char *filepath, int flags)
{
png_structp png_ptr;
png_infop info_ptr;
uchar *pixels = NULL;
uchar *from, *to;
ushort *pixels16 = NULL, *to16;
float *from_float, from_straight[4];
png_bytepp row_pointers = NULL;
int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY;
FILE *fp = NULL;
bool is_16bit = (ibuf->foptions.flag & PNG_16BIT) != 0;
bool has_float = (ibuf->rect_float != NULL);
int channels_in_float = ibuf->channels ? ibuf->channels : 4;
float (*chanel_colormanage_cb)(float);
size_t num_bytes;
/* use the jpeg quality setting for compression */
int compression;
compression = (int)((float)(ibuf->foptions.quality) / 11.1111f);
compression = compression < 0 ? 0 : (compression > 9 ? 9 : compression);
if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) {
/* float buffer was managed already, no need in color space conversion */
chanel_colormanage_cb = channel_colormanage_noop;
}
else {
/* Standard linear-to-SRGB conversion if float buffer wasn't managed. */
chanel_colormanage_cb = linearrgb_to_srgb;
}
/* for prints */
if (flags & IB_mem) {
filepath = "<memory>";
}
bytesperpixel = (ibuf->planes + 7) >> 3;
if ((bytesperpixel > 4) || (bytesperpixel == 2)) {
printf(
"imb_savepng: Unsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, filepath);
return 0;
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
printf("imb_savepng: Cannot png_create_write_struct for file: '%s'\n", filepath);
return 0;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
printf("imb_savepng: Cannot png_create_info_struct for file: '%s'\n", filepath);
return 0;
}
/* copy image data */
num_bytes = ((size_t)ibuf->x) * ibuf->y * bytesperpixel;
if (is_16bit) {
pixels16 = MEM_mallocN(num_bytes * sizeof(ushort), "png 16bit pixels");
}
else {
pixels = MEM_mallocN(num_bytes * sizeof(uchar), "png 8bit pixels");
}
if (pixels == NULL && pixels16 == NULL) {
printf(
"imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: "
"'%s'\n",
ibuf->x,
ibuf->y,
bytesperpixel,
filepath);
}
/* allocate memory for an array of row-pointers */
row_pointers = (png_bytepp)MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
if (row_pointers == NULL) {
printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", filepath);
}
if ((pixels == NULL && pixels16 == NULL) || (row_pointers == NULL) ||
setjmp(png_jmpbuf(png_ptr))) {
/* On error jump here, and free any resources. */
png_destroy_write_struct(&png_ptr, &info_ptr);
if (pixels) {
MEM_freeN(pixels);
}
if (pixels16) {
MEM_freeN(pixels16);
}
if (row_pointers) {
MEM_freeN(row_pointers);
}
if (fp) {
fflush(fp);
fclose(fp);
}
return 0;
}
from = (uchar *)ibuf->rect;
to = pixels;
from_float = ibuf->rect_float;
to16 = pixels16;
switch (bytesperpixel) {
case 4:
color_type = PNG_COLOR_TYPE_RGBA;
if (is_16bit) {
if (has_float) {
if (channels_in_float == 4) {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
premul_to_straight_v4_v4(from_straight, from_float);
to16[0] = ftoshort(chanel_colormanage_cb(from_straight[0]));
to16[1] = ftoshort(chanel_colormanage_cb(from_straight[1]));
to16[2] = ftoshort(chanel_colormanage_cb(from_straight[2]));
to16[3] = ftoshort(chanel_colormanage_cb(from_straight[3]));
to16 += 4;
from_float += 4;
}
}
else if (channels_in_float == 3) {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to16[0] = ftoshort(chanel_colormanage_cb(from_float[0]));
to16[1] = ftoshort(chanel_colormanage_cb(from_float[1]));
to16[2] = ftoshort(chanel_colormanage_cb(from_float[2]));
to16[3] = 65535;
to16 += 4;
from_float += 3;
}
}
else {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to16[0] = ftoshort(chanel_colormanage_cb(from_float[0]));
to16[2] = to16[1] = to16[0];
to16[3] = 65535;
to16 += 4;
from_float++;
}
}
}
else {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to16[0] = UPSAMPLE_8_TO_16(from[0]);
to16[1] = UPSAMPLE_8_TO_16(from[1]);
to16[2] = UPSAMPLE_8_TO_16(from[2]);
to16[3] = UPSAMPLE_8_TO_16(from[3]);
to16 += 4;
from += 4;
}
}
}
else {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to[0] = from[0];
to[1] = from[1];
to[2] = from[2];
to[3] = from[3];
to += 4;
from += 4;
}
}
break;
case 3:
color_type = PNG_COLOR_TYPE_RGB;
if (is_16bit) {
if (has_float) {
if (channels_in_float == 4) {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
premul_to_straight_v4_v4(from_straight, from_float);
to16[0] = ftoshort(chanel_colormanage_cb(from_straight[0]));
to16[1] = ftoshort(chanel_colormanage_cb(from_straight[1]));
to16[2] = ftoshort(chanel_colormanage_cb(from_straight[2]));
to16 += 3;
from_float += 4;
}
}
else if (channels_in_float == 3) {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to16[0] = ftoshort(chanel_colormanage_cb(from_float[0]));
to16[1] = ftoshort(chanel_colormanage_cb(from_float[1]));
to16[2] = ftoshort(chanel_colormanage_cb(from_float[2]));
to16 += 3;
from_float += 3;
}
}
else {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to16[0] = ftoshort(chanel_colormanage_cb(from_float[0]));
to16[2] = to16[1] = to16[0];
to16 += 3;
from_float++;
}
}
}
else {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to16[0] = UPSAMPLE_8_TO_16(from[0]);
to16[1] = UPSAMPLE_8_TO_16(from[1]);
to16[2] = UPSAMPLE_8_TO_16(from[2]);
to16 += 3;
from += 4;
}
}
}
else {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to[0] = from[0];
to[1] = from[1];
to[2] = from[2];
to += 3;
from += 4;
}
}
break;
case 1:
color_type = PNG_COLOR_TYPE_GRAY;
if (is_16bit) {
if (has_float) {
float rgb[3];
if (channels_in_float == 4) {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
premul_to_straight_v4_v4(from_straight, from_float);
rgb[0] = chanel_colormanage_cb(from_straight[0]);
rgb[1] = chanel_colormanage_cb(from_straight[1]);
rgb[2] = chanel_colormanage_cb(from_straight[2]);
to16[0] = ftoshort(IMB_colormanagement_get_luminance(rgb));
to16++;
from_float += 4;
}
}
else if (channels_in_float == 3) {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
rgb[0] = chanel_colormanage_cb(from_float[0]);
rgb[1] = chanel_colormanage_cb(from_float[1]);
rgb[2] = chanel_colormanage_cb(from_float[2]);
to16[0] = ftoshort(IMB_colormanagement_get_luminance(rgb));
to16++;
from_float += 3;
}
}
else {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to16[0] = ftoshort(chanel_colormanage_cb(from_float[0]));
to16++;
from_float++;
}
}
}
else {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to16[0] = UPSAMPLE_8_TO_16(from[0]);
to16++;
from += 4;
}
}
}
else {
for (i = ibuf->x * ibuf->y; i > 0; i--) {
to[0] = from[0];
to++;
from += 4;
}
}
break;
}
if (flags & IB_mem) {
/* create image in memory */
imb_addencodedbufferImBuf(ibuf);
ibuf->encodedsize = 0;
png_set_write_fn(png_ptr, (png_voidp)ibuf, WriteData, Flush);
}
else {
fp = BLI_fopen(filepath, "wb");
if (!fp) {
png_destroy_write_struct(&png_ptr, &info_ptr);
if (pixels) {
MEM_freeN(pixels);
}
if (pixels16) {
MEM_freeN(pixels16);
}
MEM_freeN(row_pointers);
printf("imb_savepng: Cannot open file for writing: '%s'\n", filepath);
return 0;
}
png_init_io(png_ptr, fp);
}
#if 0
png_set_filter(png_ptr,
0,
PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB |
PNG_FILTER_UP | PNG_FILTER_VALUE_UP | PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG |
PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH | PNG_ALL_FILTERS);
#endif
png_set_compression_level(png_ptr, compression);
/* png image settings */
png_set_IHDR(png_ptr,
info_ptr,
ibuf->x,
ibuf->y,
is_16bit ? 16 : 8,
color_type,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
/* image text info */
if (ibuf->metadata) {
png_text *metadata;
IDProperty *prop;
int num_text = 0;
for (prop = ibuf->metadata->data.group.first; prop; prop = prop->next) {
if (prop->type == IDP_STRING) {
num_text++;
}
}
metadata = MEM_callocN(num_text * sizeof(png_text), "png_metadata");
num_text = 0;
for (prop = ibuf->metadata->data.group.first; prop; prop = prop->next) {
if (prop->type == IDP_STRING) {
metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
metadata[num_text].key = prop->name;
metadata[num_text].text = IDP_String(prop);
num_text++;
}
}
png_set_text(png_ptr, info_ptr, metadata, num_text);
MEM_freeN(metadata);
}
if (ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) {
png_set_pHYs(png_ptr,
info_ptr,
(uint)(ibuf->ppm[0] + 0.5),
(uint)(ibuf->ppm[1] + 0.5),
PNG_RESOLUTION_METER);
}
/* write the file header information */
png_write_info(png_ptr, info_ptr);
#ifdef __LITTLE_ENDIAN__
png_set_swap(png_ptr);
#endif
/* set the individual row-pointers to point at the correct offsets */
if (is_16bit) {
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)((ushort *)pixels16 +
(((size_t)i) * ibuf->x) * bytesperpixel);
}
}
else {
for (i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)((uchar *)pixels + (((size_t)i) * ibuf->x) *
bytesperpixel *
sizeof(uchar));
}
}
/* write out the entire image data in one call */
png_write_image(png_ptr, row_pointers);
/* write the additional chunks to the PNG file (not really needed) */
png_write_end(png_ptr, info_ptr);
/* clean up */
if (pixels) {
MEM_freeN(pixels);
}
if (pixels16) {
MEM_freeN(pixels16);
}
MEM_freeN(row_pointers);
png_destroy_write_struct(&png_ptr, &info_ptr);
if (fp) {
fflush(fp);
fclose(fp);
}
return 1;
}
static void imb_png_warning(png_structp UNUSED(png_ptr), png_const_charp message)
{
/* We suppress iCCP warnings. That's how Blender always used to behave,
* and with new libpng it became too much picky, giving a warning on
* the splash screen even.
*/
if ((G.debug & G_DEBUG) == 0 && STRPREFIX(message, "iCCP")) {
return;
}
fprintf(stderr, "libpng warning: %s\n", message);
}
static void imb_png_error(png_structp UNUSED(png_ptr), png_const_charp message)
{
fprintf(stderr, "libpng error: %s\n", message);
}
ImBuf *imb_loadpng(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
struct ImBuf *ibuf = NULL;
png_structp png_ptr;
png_infop info_ptr;
uchar *pixels = NULL;
ushort *pixels16 = NULL;
png_bytepp row_pointers = NULL;
png_uint_32 width, height;
int bit_depth, color_type;
PNGReadStruct ps;
uchar *from, *to;
ushort *from16;
float *to_float;
uint channels;
if (imb_is_a_png(mem, size) == 0) {
return NULL;
}
/* both 8 and 16 bit PNGs are default to standard byte colorspace */
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
printf("Cannot png_create_read_struct\n");
return NULL;
}
png_set_error_fn(png_ptr, NULL, imb_png_error, imb_png_warning);
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
printf("Cannot png_create_info_struct\n");
return NULL;
}
ps.size = size; /* XXX, 4gig limit! */
ps.data = mem;
ps.seek = 0;
png_set_read_fn(png_ptr, (void *)&ps, ReadData);
if (setjmp(png_jmpbuf(png_ptr))) {
/* On error jump here, and free any resources. */
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
if (pixels) {
MEM_freeN(pixels);
}
if (pixels16) {
MEM_freeN(pixels16);
}
if (row_pointers) {
MEM_freeN(row_pointers);
}
if (ibuf) {
IMB_freeImBuf(ibuf);
}
return NULL;
}
// png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
channels = png_get_channels(png_ptr, info_ptr);
switch (color_type) {
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
break;
case PNG_COLOR_TYPE_PALETTE:
png_set_palette_to_rgb(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
channels = 4;
}
else {
channels = 3;
}
break;
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_GRAY_ALPHA:
if (bit_depth < 8) {
png_set_expand(png_ptr);
bit_depth = 8;
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
/* PNG_COLOR_TYPE_GRAY may also have alpha 'values', like with palette. */
channels = 2;
}
}
break;
default:
printf("PNG format not supported\n");
longjmp(png_jmpbuf(png_ptr), 1);
}
ibuf = IMB_allocImBuf(width, height, 8 * channels, 0);
if (ibuf) {
ibuf->ftype = IMB_FTYPE_PNG;
if (bit_depth == 16) {
ibuf->foptions.flag |= PNG_16BIT;
}
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
int unit_type;
png_uint_32 xres, yres;
if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type)) {
if (unit_type == PNG_RESOLUTION_METER) {
ibuf->ppm[0] = xres;
ibuf->ppm[1] = yres;
}
}
}
}
else {
printf("Couldn't allocate memory for PNG image\n");
}
if (ibuf && ((flags & IB_test) == 0)) {
if (bit_depth == 16) {
imb_addrectfloatImBuf(ibuf, 4);
png_set_swap(png_ptr);
pixels16 = imb_alloc_pixels(ibuf->x, ibuf->y, channels, sizeof(png_uint_16), "pixels");
if (pixels16 == NULL || ibuf->rect_float == NULL) {
printf("Cannot allocate pixels array\n");
longjmp(png_jmpbuf(png_ptr), 1);
}
/* allocate memory for an array of row-pointers */
row_pointers = (png_bytepp)MEM_mallocN((size_t)ibuf->y * sizeof(png_uint_16p),
"row_pointers");
if (row_pointers == NULL) {
printf("Cannot allocate row-pointers array\n");
longjmp(png_jmpbuf(png_ptr), 1);
}
/* set the individual row-pointers to point at the correct offsets */
for (size_t i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)((png_uint_16 *)pixels16 +
(i * ibuf->x) * channels);
}
png_read_image(png_ptr, row_pointers);
/* copy image data */
to_float = ibuf->rect_float;
from16 = pixels16;
switch (channels) {
case 4:
for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to_float[0] = from16[0] / 65535.0;
to_float[1] = from16[1] / 65535.0;
to_float[2] = from16[2] / 65535.0;
to_float[3] = from16[3] / 65535.0;
to_float += 4;
from16 += 4;
}
break;
case 3:
for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to_float[0] = from16[0] / 65535.0;
to_float[1] = from16[1] / 65535.0;
to_float[2] = from16[2] / 65535.0;
to_float[3] = 1.0;
to_float += 4;
from16 += 3;
}
break;
case 2:
for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0;
to_float[3] = from16[1] / 65535.0;
to_float += 4;
from16 += 2;
}
break;
case 1:
for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0;
to_float[3] = 1.0;
to_float += 4;
from16++;
}
break;
}
}
else {
imb_addrectImBuf(ibuf);
pixels = imb_alloc_pixels(ibuf->x, ibuf->y, channels, sizeof(uchar), "pixels");
if (pixels == NULL || ibuf->rect == NULL) {
printf("Cannot allocate pixels array\n");
longjmp(png_jmpbuf(png_ptr), 1);
}
/* allocate memory for an array of row-pointers */
row_pointers = (png_bytepp)MEM_mallocN((size_t)ibuf->y * sizeof(png_bytep), "row_pointers");
if (row_pointers == NULL) {
printf("Cannot allocate row-pointers array\n");
longjmp(png_jmpbuf(png_ptr), 1);
}
/* set the individual row-pointers to point at the correct offsets */
for (int i = 0; i < ibuf->y; i++) {
row_pointers[ibuf->y - 1 - i] = (png_bytep)((uchar *)pixels + (((size_t)i) * ibuf->x) *
channels *
sizeof(uchar));
}
png_read_image(png_ptr, row_pointers);
/* copy image data */
to = (uchar *)ibuf->rect;
from = pixels;
switch (channels) {
case 4:
for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to[0] = from[0];
to[1] = from[1];
to[2] = from[2];
to[3] = from[3];
to += 4;
from += 4;
}
break;
case 3:
for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to[0] = from[0];
to[1] = from[1];
to[2] = from[2];
to[3] = 0xff;
to += 4;
from += 3;
}
break;
case 2:
for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to[0] = to[1] = to[2] = from[0];
to[3] = from[1];
to += 4;
from += 2;
}
break;
case 1:
for (size_t i = (size_t)ibuf->x * (size_t)ibuf->y; i > 0; i--) {
to[0] = to[1] = to[2] = from[0];
to[3] = 0xff;
to += 4;
from++;
}
break;
}
}
if (flags & IB_metadata) {
png_text *text_chunks;
int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL);
IMB_metadata_ensure(&ibuf->metadata);
for (int i = 0; i < count; i++) {
IMB_metadata_set_field(ibuf->metadata, text_chunks[i].key, text_chunks[i].text);
ibuf->flags |= IB_metadata;
}
}
png_read_end(png_ptr, info_ptr);
}
/* clean up */
if (pixels) {
MEM_freeN(pixels);
}
if (pixels16) {
MEM_freeN(pixels16);
}
if (row_pointers) {
MEM_freeN(row_pointers);
}
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
return ibuf;
}

View File

@ -1,438 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbuf
* Radiance High Dynamic Range image file IO
* For description and code for reading/writing of radiance hdr files
* by Greg Ward, refer to:
* http://radsite.lbl.gov/radiance/refer/Notes/picture_format.html
*/
#include "MEM_guardedalloc.h"
#include "BLI_fileops.h"
#include "BLI_utildefines.h"
#include "imbuf.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_allocimbuf.h"
#include "IMB_filetype.h"
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
/* needed constants */
#define MINELEN 8
#define MAXELEN 0x7fff
#define MINRUN 4 /* minimum run length */
#define RED 0
#define GRN 1
#define BLU 2
#define EXP 3
#define COLXS 128
typedef uchar RGBE[4];
typedef float fCOLOR[3];
/* copy source -> dest */
#define COPY_RGBE(c1, c2) \
(c2[RED] = c1[RED], c2[GRN] = c1[GRN], c2[BLU] = c1[BLU], c2[EXP] = c1[EXP])
/* read routines */
static const uchar *oldreadcolrs(RGBE *scan, const uchar *mem, int xmax, const uchar *mem_eof)
{
size_t i, rshift = 0, len = xmax;
while (len > 0) {
if (UNLIKELY(mem_eof - mem < 4)) {
return NULL;
}
scan[0][RED] = *mem++;
scan[0][GRN] = *mem++;
scan[0][BLU] = *mem++;
scan[0][EXP] = *mem++;
if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) {
for (i = scan[0][EXP] << rshift; i > 0 && len > 0; i--) {
COPY_RGBE(scan[-1], scan[0]);
scan++;
len--;
}
rshift += 8;
}
else {
scan++;
len--;
rshift = 0;
}
}
return mem;
}
static const uchar *freadcolrs(RGBE *scan, const uchar *mem, int xmax, const uchar *mem_eof)
{
if (UNLIKELY(mem_eof - mem < 4)) {
return NULL;
}
if (UNLIKELY((xmax < MINELEN) | (xmax > MAXELEN))) {
return oldreadcolrs(scan, mem, xmax, mem_eof);
}
int val = *mem++;
if (val != 2) {
return oldreadcolrs(scan, mem - 1, xmax, mem_eof);
}
scan[0][GRN] = *mem++;
scan[0][BLU] = *mem++;
val = *mem++;
if (scan[0][GRN] != 2 || scan[0][BLU] & 128) {
scan[0][RED] = 2;
scan[0][EXP] = val;
return oldreadcolrs(scan + 1, mem, xmax - 1, mem_eof);
}
if (UNLIKELY(((scan[0][BLU] << 8) | val) != xmax)) {
return NULL;
}
for (size_t i = 0; i < 4; i++) {
if (UNLIKELY(mem_eof - mem < 2)) {
return NULL;
}
for (size_t j = 0; j < xmax;) {
int code = *mem++;
if (code > 128) {
code &= 127;
if (UNLIKELY(code + j > xmax)) {
return NULL;
}
val = *mem++;
while (code--) {
scan[j++][i] = (uchar)val;
}
}
else {
if (UNLIKELY(mem_eof - mem < code)) {
return NULL;
}
if (UNLIKELY(code + j > xmax)) {
return NULL;
}
while (code--) {
scan[j++][i] = *mem++;
}
}
}
}
return mem;
}
/* helper functions */
/* rgbe -> float color */
static void RGBE2FLOAT(RGBE rgbe, fCOLOR fcol)
{
if (rgbe[EXP] == 0) {
fcol[RED] = fcol[GRN] = fcol[BLU] = 0;
}
else {
float f = ldexp(1.0, rgbe[EXP] - (COLXS + 8));
fcol[RED] = f * (rgbe[RED] + 0.5f);
fcol[GRN] = f * (rgbe[GRN] + 0.5f);
fcol[BLU] = f * (rgbe[BLU] + 0.5f);
}
}
/* float color -> rgbe */
static void FLOAT2RGBE(const fCOLOR fcol, RGBE rgbe)
{
int e;
float d = (fcol[RED] > fcol[GRN]) ? fcol[RED] : fcol[GRN];
if (fcol[BLU] > d) {
d = fcol[BLU];
}
if (d <= 1e-32f) {
rgbe[RED] = rgbe[GRN] = rgbe[BLU] = rgbe[EXP] = 0;
}
else {
d = (float)frexp(d, &e) * 256.0f / d;
rgbe[RED] = (uchar)(fcol[RED] * d);
rgbe[GRN] = (uchar)(fcol[GRN] * d);
rgbe[BLU] = (uchar)(fcol[BLU] * d);
rgbe[EXP] = (uchar)(e + COLXS);
}
}
/* ImBuf read */
bool imb_is_a_hdr(const uchar *buf, const size_t size)
{
/* NOTE: `#?RADIANCE` is used by other programs such as `ImageMagik`,
* Although there are some files in the wild that only use `#?` (from looking online).
* If this is ever a problem we could check for the longer header since this is part of the spec.
*
* We could check `32-bit_rle_rgbe` or `32-bit_rle_xyze` too since this is part of the format.
* Currently this isn't needed.
*
* See: http://paulbourke.net/dataformats/pic/
*/
const uchar magic[2] = {'#', '?'};
if (size < sizeof(magic)) {
return false;
}
return memcmp(buf, magic, sizeof(magic)) == 0;
}
struct ImBuf *imb_loadhdr(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
struct ImBuf *ibuf;
RGBE *sline;
fCOLOR fcol;
float *rect_float;
int found = 0;
int width = 0, height = 0;
const uchar *ptr, *mem_eof = mem + size;
char oriY[3], oriX[3];
if (!imb_is_a_hdr(mem, size)) {
return NULL;
}
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
/* find empty line, next line is resolution info */
size_t x;
for (x = 1; x < size; x++) {
if ((mem[x - 1] == '\n') && (mem[x] == '\n')) {
found = 1;
break;
}
}
if ((found && (x < (size - 1))) == 0) {
/* Data not found! */
return NULL;
}
x++;
/* sscanf requires a null-terminated buffer argument */
char buf[32] = {0};
memcpy(buf, &mem[x], MIN2(sizeof(buf) - 1, size - x));
if (sscanf(buf, "%2s %d %2s %d", (char *)&oriY, &height, (char *)&oriX, &width) != 4) {
return NULL;
}
if (width < 1 || height < 1) {
return NULL;
}
/* Checking that width x height does not extend past mem_eof is not easily possible
* since the format uses RLE compression. Can cause excessive memory allocation to occur. */
/* find end of this line, data right behind it */
ptr = (const uchar *)strchr((const char *)&mem[x], '\n');
if (ptr == NULL || ptr >= mem_eof) {
return NULL;
}
ptr++;
if (flags & IB_test) {
ibuf = IMB_allocImBuf(width, height, 32, 0);
}
else {
ibuf = IMB_allocImBuf(width, height, 32, (flags & IB_rect) | IB_rectfloat);
}
if (UNLIKELY(ibuf == NULL)) {
return NULL;
}
ibuf->ftype = IMB_FTYPE_RADHDR;
if (flags & IB_alphamode_detect) {
ibuf->flags |= IB_alphamode_premul;
}
if (flags & IB_test) {
return ibuf;
}
/* read in and decode the actual data */
sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__);
rect_float = ibuf->rect_float;
for (size_t y = 0; y < height; y++) {
ptr = freadcolrs(sline, ptr, width, mem_eof);
if (ptr == NULL) {
printf("WARNING! HDR decode error, image may be just truncated, or completely wrong...\n");
break;
}
for (x = 0; x < width; x++) {
/* Convert to LDR. */
RGBE2FLOAT(sline[x], fcol);
*rect_float++ = fcol[RED];
*rect_float++ = fcol[GRN];
*rect_float++ = fcol[BLU];
*rect_float++ = 1.0f;
}
}
MEM_freeN(sline);
if (oriY[0] == '-') {
IMB_flipy(ibuf);
}
if (flags & IB_rect) {
IMB_rect_from_float(ibuf);
}
return ibuf;
}
/* ImBuf write */
static int fwritecolrs(
FILE *file, int width, int channels, const uchar *ibufscan, const float *fpscan)
{
int beg, c2, count = 0;
fCOLOR fcol;
RGBE rgbe, *rgbe_scan;
if (UNLIKELY((ibufscan == NULL) && (fpscan == NULL))) {
return 0;
}
rgbe_scan = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_write_tmpscan");
/* Convert scan-line. */
for (size_t i = 0, j = 0; i < width; i++) {
if (fpscan) {
fcol[RED] = fpscan[j];
fcol[GRN] = (channels >= 2) ? fpscan[j + 1] : fpscan[j];
fcol[BLU] = (channels >= 3) ? fpscan[j + 2] : fpscan[j];
}
else {
fcol[RED] = (float)ibufscan[j] / 255.0f;
fcol[GRN] = (float)((channels >= 2) ? ibufscan[j + 1] : ibufscan[j]) / 255.0f;
fcol[BLU] = (float)((channels >= 3) ? ibufscan[j + 2] : ibufscan[j]) / 255.0f;
}
FLOAT2RGBE(fcol, rgbe);
COPY_RGBE(rgbe, rgbe_scan[i]);
j += channels;
}
if ((width < MINELEN) | (width > MAXELEN)) { /* OOBs, write out flat */
int x = fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width;
MEM_freeN(rgbe_scan);
return x;
}
/* put magic header */
putc(2, file);
putc(2, file);
putc((uchar)(width >> 8), file);
putc((uchar)(width & 255), file);
/* put components separately */
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < width; j += count) { /* find next run */
for (beg = j; beg < width; beg += count) {
for (count = 1; (count < 127) && ((beg + count) < width) &&
(rgbe_scan[beg + count][i] == rgbe_scan[beg][i]);
count++) {
/* pass */
}
if (count >= MINRUN) {
break; /* long enough */
}
}
if (((beg - j) > 1) && ((beg - j) < MINRUN)) {
c2 = j + 1;
while (rgbe_scan[c2++][i] == rgbe_scan[j][i]) {
if (c2 == beg) { /* short run */
putc((uchar)(128 + beg - j), file);
putc((uchar)(rgbe_scan[j][i]), file);
j = beg;
break;
}
}
}
while (j < beg) { /* write out non-run */
if ((c2 = beg - j) > 128) {
c2 = 128;
}
putc((uchar)(c2), file);
while (c2--) {
putc(rgbe_scan[j++][i], file);
}
}
if (count >= MINRUN) { /* write out run */
putc((uchar)(128 + count), file);
putc(rgbe_scan[beg][i], file);
}
else {
count = 0;
}
}
}
MEM_freeN(rgbe_scan);
return (ferror(file) ? -1 : 0);
}
static void writeHeader(FILE *file, int width, int height)
{
fprintf(file, "#?RADIANCE");
fputc(10, file);
fprintf(file, "# %s", "Created with Blender");
fputc(10, file);
fprintf(file, "EXPOSURE=%25.13f", 1.0);
fputc(10, file);
fprintf(file, "FORMAT=32-bit_rle_rgbe");
fputc(10, file);
fputc(10, file);
fprintf(file, "-Y %d +X %d", height, width);
fputc(10, file);
}
bool imb_savehdr(struct ImBuf *ibuf, const char *filepath, int flags)
{
FILE *file = BLI_fopen(filepath, "wb");
float *fp = NULL;
size_t width = ibuf->x, height = ibuf->y;
uchar *cp = NULL;
(void)flags; /* unused */
if (file == NULL) {
return 0;
}
writeHeader(file, width, height);
if (ibuf->rect) {
cp = (uchar *)ibuf->rect + ibuf->channels * (height - 1) * width;
}
if (ibuf->rect_float) {
fp = ibuf->rect_float + ibuf->channels * (height - 1) * width;
}
for (size_t y = 0; y < height; y++) {
if (fwritecolrs(file, width, ibuf->channels, cp, fp) < 0) {
fclose(file);
printf("HDR write error\n");
return 0;
}
if (cp) {
cp -= ibuf->channels * width;
}
if (fp) {
fp -= ibuf->channels * width;
}
}
fclose(file);
return 1;
}

View File

@ -1,791 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/** \file
* \ingroup imbuf
*/
#ifdef WIN32
# include <io.h>
#endif
#include "BLI_fileops.h"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
#include "imbuf.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_filetype.h"
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
/* this one is only def-ed once, strangely... related to GS? */
#define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0])
/***/
typedef struct TARGA {
uchar numid;
uchar maptyp;
uchar imgtyp;
short maporig;
short mapsize;
uchar mapbits;
short xorig;
short yorig;
short xsize;
short ysize;
uchar pixsize;
uchar imgdes;
} TARGA;
/**
* On-disk header size.
*
* \note In theory it's possible padding would make the struct and on-disk size differ,
* so use a constant instead of `sizeof(TARGA)`.
*/
#define TARGA_HEADER_SIZE 18
/***/
static int tga_out1(uint data, FILE *file)
{
uchar *p;
p = (uchar *)&data;
if (putc(p[0], file) == EOF) {
return EOF;
}
return ~EOF;
}
static int tga_out2(uint data, FILE *file)
{
uchar *p;
p = (uchar *)&data;
if (putc(p[0], file) == EOF) {
return EOF;
}
if (putc(p[1], file) == EOF) {
return EOF;
}
return ~EOF;
}
static int tga_out3(uint data, FILE *file)
{
uchar *p;
p = (uchar *)&data;
if (putc(p[2], file) == EOF) {
return EOF;
}
if (putc(p[1], file) == EOF) {
return EOF;
}
if (putc(p[0], file) == EOF) {
return EOF;
}
return ~EOF;
}
static int tga_out4(uint data, FILE *file)
{
uchar *p;
p = (uchar *)&data;
/* Order = BGRA. */
if (putc(p[2], file) == EOF) {
return EOF;
}
if (putc(p[1], file) == EOF) {
return EOF;
}
if (putc(p[0], file) == EOF) {
return EOF;
}
if (putc(p[3], file) == EOF) {
return EOF;
}
return ~EOF;
}
static bool makebody_tga(ImBuf *ibuf, FILE *file, int (*out)(uint, FILE *))
{
int last, this;
int copy, bytes;
uint *rect, *rectstart, *temp;
int y;
for (y = 0; y < ibuf->y; y++) {
bytes = ibuf->x - 1;
rectstart = rect = ibuf->rect + (y * ibuf->x);
last = *rect++;
this = *rect++;
copy = last ^ this;
while (bytes > 0) {
if (copy) {
do {
last = this;
this = *rect++;
if (last == this) {
if (this == rect[-3]) { /* three the same? */
bytes--; /* set bytes */
break;
}
}
} while (--bytes != 0);
copy = rect - rectstart;
copy--;
if (bytes) {
copy -= 2;
}
temp = rect;
rect = rectstart;
while (copy) {
last = copy;
if (copy >= 128) {
last = 128;
}
copy -= last;
if (fputc(last - 1, file) == EOF) {
return 0;
}
do {
if (out(*rect++, file) == EOF) {
return 0;
}
} while (--last != 0);
}
rectstart = rect;
rect = temp;
last = this;
copy = 0;
}
else {
while (*rect++ == this) { /* seek for first different byte */
if (--bytes == 0) {
break; /* Or end of line. */
}
}
rect--;
copy = rect - rectstart;
rectstart = rect;
bytes--;
this = *rect++;
while (copy) {
if (copy > 128) {
if (fputc(255, file) == EOF) {
return 0;
}
copy -= 128;
}
else {
if (copy == 1) {
if (fputc(0, file) == EOF) {
return 0;
}
}
else if (fputc(127 + copy, file) == EOF) {
return 0;
}
copy = 0;
}
if (out(last, file) == EOF) {
return 0;
}
}
copy = 1;
}
}
}
return 1;
}
static bool dumptarga(struct ImBuf *ibuf, FILE *file)
{
int size;
uchar *rect;
if (ibuf == NULL) {
return 0;
}
if (ibuf->rect == NULL) {
return 0;
}
size = ibuf->x * ibuf->y;
rect = (uchar *)ibuf->rect;
if (ibuf->planes <= 8) {
while (size > 0) {
if (putc(*rect, file) == EOF) {
return 0;
}
size--;
rect += 4;
}
}
else if (ibuf->planes <= 16) {
while (size > 0) {
putc(rect[0], file);
if (putc(rect[1], file) == EOF) {
return 0;
}
size--;
rect += 4;
}
}
else if (ibuf->planes <= 24) {
while (size > 0) {
putc(rect[2], file);
putc(rect[1], file);
if (putc(rect[0], file) == EOF) {
return 0;
}
size--;
rect += 4;
}
}
else if (ibuf->planes <= 32) {
while (size > 0) {
putc(rect[2], file);
putc(rect[1], file);
putc(rect[0], file);
if (putc(rect[3], file) == EOF) {
return 0;
}
size--;
rect += 4;
}
}
else {
return 0;
}
return 1;
}
bool imb_savetarga(struct ImBuf *ibuf, const char *filepath, int UNUSED(flags))
{
char buf[TARGA_HEADER_SIZE] = {0};
FILE *fildes;
bool ok = false;
buf[16] = (ibuf->planes + 0x7) & ~0x7;
if (ibuf->planes > 8) {
buf[2] = 10;
}
else {
buf[2] = 11;
}
if (ibuf->foptions.flag & RAWTGA) {
buf[2] &= ~8;
}
buf[8] = 0;
buf[9] = 0;
buf[10] = 0;
buf[11] = 0;
buf[12] = ibuf->x & 0xff;
buf[13] = ibuf->x >> 8;
buf[14] = ibuf->y & 0xff;
buf[15] = ibuf->y >> 8;
/* Don't forget to indicate that your 32 bit
* targa uses 8 bits for the alpha channel! */
if (ibuf->planes == 32) {
buf[17] |= 0x08;
}
fildes = BLI_fopen(filepath, "wb");
if (!fildes) {
return 0;
}
if (fwrite(buf, 1, TARGA_HEADER_SIZE, fildes) != TARGA_HEADER_SIZE) {
fclose(fildes);
return 0;
}
if (ibuf->foptions.flag & RAWTGA) {
ok = dumptarga(ibuf, fildes);
}
else {
switch ((ibuf->planes + 7) >> 3) {
case 1:
ok = makebody_tga(ibuf, fildes, tga_out1);
break;
case 2:
ok = makebody_tga(ibuf, fildes, tga_out2);
break;
case 3:
ok = makebody_tga(ibuf, fildes, tga_out3);
break;
case 4:
ok = makebody_tga(ibuf, fildes, tga_out4);
break;
}
}
fclose(fildes);
return ok;
}
static bool checktarga(TARGA *tga, const uchar *mem, const size_t size)
{
if (size < TARGA_HEADER_SIZE) {
return false;
}
tga->numid = mem[0];
tga->maptyp = mem[1];
tga->imgtyp = mem[2];
tga->maporig = GSS(mem + 3);
tga->mapsize = GSS(mem + 5);
tga->mapbits = mem[7];
tga->xorig = GSS(mem + 8);
tga->yorig = GSS(mem + 10);
tga->xsize = GSS(mem + 12);
tga->ysize = GSS(mem + 14);
tga->pixsize = mem[16];
tga->imgdes = mem[17];
if (tga->maptyp > 1) {
return false;
}
switch (tga->imgtyp) {
case 1: /* raw cmap */
case 2: /* raw rgb */
case 3: /* raw b&w */
case 9: /* cmap */
case 10: /* rgb */
case 11: /* b&w */
break;
default:
return false;
}
if (tga->mapsize && tga->mapbits > 32) {
return false;
}
if (tga->xsize <= 0) {
return false;
}
if (tga->ysize <= 0) {
return false;
}
if (tga->pixsize > 32) {
return false;
}
if (tga->pixsize == 0) {
return false;
}
return true;
}
bool imb_is_a_targa(const uchar *buf, size_t size)
{
TARGA tga;
return checktarga(&tga, buf, size);
}
static void complete_partial_load(struct ImBuf *ibuf, uint *rect)
{
int size = (ibuf->x * ibuf->y) - (rect - ibuf->rect);
if (size) {
printf("decodetarga: incomplete file, %.1f%% missing\n",
100 * ((float)size / (ibuf->x * ibuf->y)));
/* Not essential but makes displaying partially rendered TGA's less ugly. */
memset(rect, 0, size);
}
else {
/* shouldn't happen */
printf("decodetarga: incomplete file, all pixels written\n");
}
}
static void decodetarga(struct ImBuf *ibuf, const uchar *mem, size_t mem_size, int psize)
{
const uchar *mem_end = mem + mem_size;
int count, col, size;
uint *rect;
uchar *cp = (uchar *)&col;
if (ibuf == NULL) {
return;
}
if (ibuf->rect == NULL) {
return;
}
size = ibuf->x * ibuf->y;
rect = ibuf->rect;
/* set alpha */
cp[0] = 0xff;
cp[1] = cp[2] = 0;
while (size > 0) {
count = *mem++;
if (mem > mem_end) {
goto partial_load;
}
if (count >= 128) {
// if (count == 128) printf("TARGA: 128 in file !\n");
count -= 127;
if (psize & 2) {
if (psize & 1) {
/* Order = BGRA. */
cp[0] = mem[3];
cp[1] = mem[0];
cp[2] = mem[1];
cp[3] = mem[2];
// col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];
mem += 4;
}
else {
cp[1] = mem[0];
cp[2] = mem[1];
cp[3] = mem[2];
// col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];
mem += 3;
}
}
else {
if (psize & 1) {
cp[0] = mem[0];
cp[1] = mem[1];
mem += 2;
}
else {
col = *mem++;
}
}
size -= count;
if (size >= 0) {
while (count > 0) {
*rect++ = col;
count--;
}
}
}
else {
count++;
size -= count;
if (size >= 0) {
while (count > 0) {
if (psize & 2) {
if (psize & 1) {
/* Order = BGRA. */
cp[0] = mem[3];
cp[1] = mem[0];
cp[2] = mem[1];
cp[3] = mem[2];
// col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];
mem += 4;
}
else {
cp[1] = mem[0];
cp[2] = mem[1];
cp[3] = mem[2];
// col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];
mem += 3;
}
}
else {
if (psize & 1) {
cp[0] = mem[0];
cp[1] = mem[1];
mem += 2;
}
else {
col = *mem++;
}
}
*rect++ = col;
count--;
if (mem > mem_end) {
goto partial_load;
}
}
if (mem > mem_end) {
goto partial_load;
}
}
}
}
if (size) {
printf("decodetarga: count would overwrite %d pixels\n", -size);
}
return;
partial_load:
complete_partial_load(ibuf, rect);
}
static void ldtarga(struct ImBuf *ibuf, const uchar *mem, size_t mem_size, int psize)
{
const uchar *mem_end = mem + mem_size;
int col, size;
uint *rect;
uchar *cp = (uchar *)&col;
if (ibuf == NULL) {
return;
}
if (ibuf->rect == NULL) {
return;
}
size = ibuf->x * ibuf->y;
rect = ibuf->rect;
/* set alpha */
cp[0] = 0xff;
cp[1] = cp[2] = 0;
while (size > 0) {
if (mem > mem_end) {
goto partial_load;
}
if (psize & 2) {
if (psize & 1) {
/* Order = BGRA. */
cp[0] = mem[3];
cp[1] = mem[0];
cp[2] = mem[1];
cp[3] = mem[2];
// col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];
mem += 4;
}
else {
/* set alpha for 24 bits colors */
cp[1] = mem[0];
cp[2] = mem[1];
cp[3] = mem[2];
// col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];
mem += 3;
}
}
else {
if (psize & 1) {
cp[0] = mem[0];
cp[1] = mem[1];
mem += 2;
}
else {
col = *mem++;
}
}
*rect++ = col;
size--;
}
return;
partial_load:
complete_partial_load(ibuf, rect);
}
ImBuf *imb_loadtarga(const uchar *mem, size_t mem_size, int flags, char colorspace[IM_MAX_SPACE])
{
TARGA tga;
struct ImBuf *ibuf;
int count, size;
uint *rect, *cmap = NULL /*, mincol = 0*/, cmap_max = 0;
int32_t cp_data;
uchar *cp = (uchar *)&cp_data;
if (checktarga(&tga, mem, mem_size) == 0) {
return NULL;
}
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
if (flags & IB_test) {
ibuf = IMB_allocImBuf(tga.xsize, tga.ysize, tga.pixsize, 0);
}
else {
ibuf = IMB_allocImBuf(tga.xsize, tga.ysize, (tga.pixsize + 0x7) & ~0x7, IB_rect);
}
if (ibuf == NULL) {
return NULL;
}
ibuf->ftype = IMB_FTYPE_TGA;
if (tga.imgtyp < 4) {
ibuf->foptions.flag |= RAWTGA;
}
mem = mem + TARGA_HEADER_SIZE + tga.numid;
cp[0] = 0xff;
cp[1] = cp[2] = 0;
if (tga.mapsize) {
/* Load color map. */
// mincol = tga.maporig; /* UNUSED */
cmap_max = tga.mapsize;
cmap = MEM_callocN(sizeof(uint) * cmap_max, "targa cmap");
for (count = 0; count < cmap_max; count++) {
switch (tga.mapbits >> 3) {
case 4:
cp[0] = mem[3];
cp[1] = mem[0];
cp[2] = mem[1];
cp[3] = mem[2];
mem += 4;
break;
case 3:
cp[1] = mem[0];
cp[2] = mem[1];
cp[3] = mem[2];
mem += 3;
break;
case 2:
cp[1] = mem[1];
cp[0] = mem[0];
mem += 2;
break;
case 1:
cp_data = *mem++;
break;
}
cmap[count] = cp_data;
}
ibuf->planes = tga.mapbits;
if (tga.mapbits != 32) { /* Set alpha bits. */
cmap[0] &= BIG_LONG(0x00ffffffl);
}
}
if (flags & IB_test) {
if (cmap) {
MEM_freeN(cmap);
}
return ibuf;
}
if (!ELEM(tga.imgtyp, 1, 9)) { /* happens sometimes (ugh) */
if (cmap) {
MEM_freeN(cmap);
cmap = NULL;
}
}
switch (tga.imgtyp) {
case 1:
case 2:
case 3:
if (tga.pixsize <= 8) {
ldtarga(ibuf, mem, mem_size, 0);
}
else if (tga.pixsize <= 16) {
ldtarga(ibuf, mem, mem_size, 1);
}
else if (tga.pixsize <= 24) {
ldtarga(ibuf, mem, mem_size, 2);
}
else if (tga.pixsize <= 32) {
ldtarga(ibuf, mem, mem_size, 3);
}
break;
case 9:
case 10:
case 11:
if (tga.pixsize <= 8) {
decodetarga(ibuf, mem, mem_size, 0);
}
else if (tga.pixsize <= 16) {
decodetarga(ibuf, mem, mem_size, 1);
}
else if (tga.pixsize <= 24) {
decodetarga(ibuf, mem, mem_size, 2);
}
else if (tga.pixsize <= 32) {
decodetarga(ibuf, mem, mem_size, 3);
}
break;
}
if (cmap) {
/* apply color map */
rect = ibuf->rect;
for (size = ibuf->x * ibuf->y; size > 0; size--, rect++) {
int cmap_index = *rect;
if (cmap_index >= 0 && cmap_index < cmap_max) {
*rect = cmap[cmap_index];
}
}
MEM_freeN(cmap);
}
if (tga.pixsize == 16) {
uint col;
rect = ibuf->rect;
for (size = ibuf->x * ibuf->y; size > 0; size--, rect++) {
col = *rect;
cp = (uchar *)rect;
mem = (uchar *)&col;
cp[3] = ((mem[1] << 1) & 0xf8);
cp[2] = ((mem[0] & 0xe0) >> 2) + ((mem[1] & 0x03) << 6);
cp[1] = ((mem[0] << 3) & 0xf8);
cp[1] += cp[1] >> 5;
cp[2] += cp[2] >> 5;
cp[3] += cp[3] >> 5;
cp[0] = 0xff;
}
ibuf->planes = 24;
}
if (ELEM(tga.imgtyp, 3, 11)) {
uchar *crect;
uint *lrect, col;
crect = (uchar *)ibuf->rect;
lrect = (uint *)ibuf->rect;
for (size = ibuf->x * ibuf->y; size > 0; size--) {
col = *lrect++;
crect[0] = 255;
crect[1] = crect[2] = crect[3] = col;
crect += 4;
}
}
if (tga.imgdes & 0x20) {
IMB_flipy(ibuf);
}
if (ibuf->rect) {
IMB_convert_rgba_to_abgr(ibuf);
}
return ibuf;
}

View File

@ -1,832 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbuf
*/
/**
* Provides TIFF file loading and saving for Blender, via libtiff.
*
* The task of loading is complicated somewhat by the fact that Blender has
* already loaded the file into a memory buffer. libtiff is not well
* configured to handle files in memory, so a client wrapper is written to
* surround the memory and turn it into a virtual file. Currently, reading
* of TIFF files is done using libtiff's RGBAImage support. This is a
* high-level routine that loads all images as 32-bit RGBA, handling all the
* required conversions between many different TIFF types internally.
*
* Saving supports RGB, RGBA and BW (gray-scale) images correctly, with
* 8 bits per channel in all cases. The "deflate" compression algorithm is
* used to compress images.
*/
#include <string.h>
#include "imbuf.h"
#include "BLI_endian_defines.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_filetype.h"
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
#include <tiffio.h>
#ifdef WIN32
# include "utfconv.h"
#endif
/* -------------------------------------------------------------------- */
/** \name Local Declarations
* \{ */
/* Reading and writing of an in-memory TIFF file. */
static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n);
static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n);
static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence);
static int imb_tiff_CloseProc(thandle_t handle);
static toff_t imb_tiff_SizeProc(thandle_t handle);
static int imb_tiff_DummyMapProc(thandle_t fd, tdata_t *pbase, toff_t *psize);
static void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size);
/** Structure for in-memory TIFF file. */
typedef struct ImbTIFFMemFile {
/** Location of first byte of TIFF file. */
const uchar *mem;
/** Current offset within the file. */
toff_t offset;
/** Size of the TIFF file. */
tsize_t size;
} ImbTIFFMemFile;
#define IMB_TIFF_GET_MEMFILE(x) ((ImbTIFFMemFile *)(x))
/** \} */
/* -------------------------------------------------------------------- */
/** \name Function Implementations
* \{ */
static void imb_tiff_DummyUnmapProc(
thandle_t fd,
tdata_t base,
/* Cannot be const, because this function implements #TIFFUnmapFileProc.
* NOLINTNEXTLINE: readability-non-const-parameter. */
toff_t size)
{
(void)fd;
(void)base;
(void)size;
}
static int imb_tiff_DummyMapProc(
thandle_t fd,
tdata_t *pbase,
/* Cannot be const, because this function implements #TIFFMapFileProc.
* NOLINTNEXTLINE: readability-non-const-parameter. */
toff_t *psize)
{
(void)fd;
(void)pbase;
(void)psize;
return 0;
}
/**
* Reads data from an in-memory TIFF file.
*
* \param handle: Handle of the TIFF file (pointer to #ImbTIFFMemFile).
* \param data: Buffer to contain data (treat as (void *)).
* \param n: Number of bytes to read.
*
* \return Number of bytes actually read.
* 0 = EOF.
*/
static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n)
{
tsize_t nRemaining, nCopy;
ImbTIFFMemFile *mfile;
void *srcAddr;
/* get the pointer to the in-memory file */
mfile = IMB_TIFF_GET_MEMFILE(handle);
if (!mfile || !mfile->mem) {
fprintf(stderr, "imb_tiff_ReadProc: !mfile || !mfile->mem!\n");
return 0;
}
/* find the actual number of bytes to read (copy) */
nCopy = n;
if ((tsize_t)mfile->offset >= mfile->size) {
nRemaining = 0;
}
else {
nRemaining = mfile->size - mfile->offset;
}
if (nCopy > nRemaining) {
nCopy = nRemaining;
}
/* on EOF, return immediately and read (copy) nothing */
if (nCopy <= 0) {
return 0;
}
/* all set -> do the read (copy) */
srcAddr = (void *)&(mfile->mem[mfile->offset]);
memcpy((void *)data, srcAddr, nCopy);
mfile->offset += nCopy; /* advance file ptr by copied bytes */
return nCopy;
}
/**
* Writes data to an in-memory TIFF file.
*
* NOTE: The current Blender implementation should not need this function.
* It is simply a stub.
*/
static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
{
(void)handle;
(void)data;
(void)n;
printf("imb_tiff_WriteProc: this function should not be called.\n");
return (-1);
}
/**
* Seeks to a new location in an in-memory TIFF file.
*
* \param handle: Handle of the TIFF file (pointer to #ImbTIFFMemFile).
* \param ofs: Offset value (interpreted according to whence below).
* \param whence: This can be one of three values:
* SEEK_SET - The offset is set to ofs bytes.
* SEEK_CUR - The offset is set to its current location plus ofs bytes.
* SEEK_END - (This is unsupported and will return -1, indicating an
* error).
*
* \return Resulting offset location within the file, measured in bytes from
* the beginning of the file. (-1) indicates an error.
*/
static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
{
ImbTIFFMemFile *mfile;
toff_t new_offset;
/* get the pointer to the in-memory file */
mfile = IMB_TIFF_GET_MEMFILE(handle);
if (!mfile || !mfile->mem) {
fprintf(stderr, "imb_tiff_SeekProc: !mfile || !mfile->mem!\n");
return (-1);
}
/* find the location we plan to seek to */
switch (whence) {
case SEEK_SET:
new_offset = ofs;
break;
case SEEK_CUR:
new_offset = mfile->offset + ofs;
break;
default:
/* no other types are supported - return an error */
fprintf(stderr,
"imb_tiff_SeekProc: "
"Unsupported TIFF SEEK type.\n");
return (-1);
}
/* set the new location */
mfile->offset = new_offset;
return mfile->offset;
}
/**
* Closes (virtually) an in-memory TIFF file.
*
* NOTE: All this function actually does is sets the data pointer within the
* TIFF file to NULL. That should trigger assertion errors if attempts
* are made to access the file after that point. However, no such
* attempts should ever be made (in theory).
*
* \param handle: Handle of the TIFF file (pointer to #ImbTIFFMemFile).
*
* \return 0
*/
static int imb_tiff_CloseProc(thandle_t handle)
{
ImbTIFFMemFile *mfile;
/* get the pointer to the in-memory file */
mfile = IMB_TIFF_GET_MEMFILE(handle);
if (!mfile || !mfile->mem) {
fprintf(stderr, "imb_tiff_CloseProc: !mfile || !mfile->mem!\n");
return 0;
}
/* virtually close the file */
mfile->mem = NULL;
mfile->offset = 0;
mfile->size = 0;
return 0;
}
/**
* Returns the size of an in-memory TIFF file in bytes.
*
* \return Size of file (in bytes).
*/
static toff_t imb_tiff_SizeProc(thandle_t handle)
{
ImbTIFFMemFile *mfile;
/* get the pointer to the in-memory file */
mfile = IMB_TIFF_GET_MEMFILE(handle);
if (!mfile || !mfile->mem) {
fprintf(stderr, "imb_tiff_SizeProc: !mfile || !mfile->mem!\n");
return 0;
}
/* return the size */
return (toff_t)(mfile->size);
}
static TIFF *imb_tiff_client_open(ImbTIFFMemFile *memFile, const uchar *mem, size_t size)
{
/* open the TIFF client layer interface to the in-memory file */
memFile->mem = mem;
memFile->offset = 0;
memFile->size = size;
return TIFFClientOpen("(Blender TIFF Interface Layer)",
"r",
(thandle_t)(memFile),
imb_tiff_ReadProc,
imb_tiff_WriteProc,
imb_tiff_SeekProc,
imb_tiff_CloseProc,
imb_tiff_SizeProc,
imb_tiff_DummyMapProc,
imb_tiff_DummyUnmapProc);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Load TIFF
* \{ */
/**
* Checks whether a given memory buffer contains a TIFF file.
*
* This method uses the format identifiers from:
* http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-9.html
* The first four bytes of big-endian and little-endian TIFF files
* respectively are (hex):
* 4d 4d 00 2a
* 49 49 2a 00
* Note that TIFF files on *any* platform can be either big- or little-endian;
* it's not platform-specific.
*
* AFAICT, libtiff doesn't provide a method to do this automatically, and
* hence my manual comparison. - Jonathan Merritt (lancelet) 4th Sept 2005.
*/
#define IMB_TIFF_NCB 4 /* number of comparison bytes used */
bool imb_is_a_tiff(const uchar *buf, size_t size)
{
const char big_endian[IMB_TIFF_NCB] = {0x4d, 0x4d, 0x00, 0x2a};
const char lil_endian[IMB_TIFF_NCB] = {0x49, 0x49, 0x2a, 0x00};
if (size < IMB_TIFF_NCB) {
return false;
}
return ((memcmp(big_endian, buf, IMB_TIFF_NCB) == 0) ||
(memcmp(lil_endian, buf, IMB_TIFF_NCB) == 0));
}
static void scanline_contig_16bit(float *rectf, const ushort *sbuf, int scanline_w, int spp)
{
int i;
for (i = 0; i < scanline_w; i++) {
rectf[i * 4 + 0] = sbuf[i * spp + 0] / 65535.0;
rectf[i * 4 + 1] = (spp >= 3) ? sbuf[i * spp + 1] / 65535.0 : sbuf[i * spp + 0] / 65535.0;
rectf[i * 4 + 2] = (spp >= 3) ? sbuf[i * spp + 2] / 65535.0 : sbuf[i * spp + 0] / 65535.0;
rectf[i * 4 + 3] = (spp == 4) ? (sbuf[i * spp + 3] / 65535.0) : 1.0;
}
}
static void scanline_contig_32bit(float *rectf, const float *fbuf, int scanline_w, int spp)
{
int i;
for (i = 0; i < scanline_w; i++) {
rectf[i * 4 + 0] = fbuf[i * spp + 0];
rectf[i * 4 + 1] = (spp >= 3) ? fbuf[i * spp + 1] : fbuf[i * spp + 0];
rectf[i * 4 + 2] = (spp >= 3) ? fbuf[i * spp + 2] : fbuf[i * spp + 0];
rectf[i * 4 + 3] = (spp == 4) ? fbuf[i * spp + 3] : 1.0f;
}
}
static void scanline_separate_16bit(float *rectf, const ushort *sbuf, int scanline_w, int chan)
{
int i;
for (i = 0; i < scanline_w; i++) {
rectf[i * 4 + chan] = sbuf[i] / 65535.0;
}
}
static void scanline_separate_32bit(float *rectf, const float *fbuf, int scanline_w, int chan)
{
int i;
for (i = 0; i < scanline_w; i++) {
rectf[i * 4 + chan] = fbuf[i];
}
}
static void imb_read_tiff_resolution(ImBuf *ibuf, TIFF *image)
{
uint16_t unit;
float xres;
float yres;
TIFFGetFieldDefaulted(image, TIFFTAG_RESOLUTIONUNIT, &unit);
TIFFGetFieldDefaulted(image, TIFFTAG_XRESOLUTION, &xres);
TIFFGetFieldDefaulted(image, TIFFTAG_YRESOLUTION, &yres);
if (unit == RESUNIT_CENTIMETER) {
ibuf->ppm[0] = (double)xres * 100.0;
ibuf->ppm[1] = (double)yres * 100.0;
}
else {
ibuf->ppm[0] = (double)xres / 0.0254;
ibuf->ppm[1] = (double)yres / 0.0254;
}
}
/*
* Use the libTIFF scanline API to read a TIFF image.
* This method is most flexible and can handle multiple different bit depths
* and RGB channel orderings.
*/
static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
{
ImBuf *tmpibuf = NULL;
int success = 0;
short bitspersample, spp, config;
size_t scanline;
int ib_flag = 0, row, chan;
float *fbuf = NULL;
ushort *sbuf = NULL;
TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &bitspersample);
TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp); /* number of 'channels' */
TIFFGetField(image, TIFFTAG_PLANARCONFIG, &config);
if (spp == 4) {
/* HACK: this is really tricky hack, which is only needed to force libtiff
* do not touch RGB channels when there's alpha channel present
* The thing is: libtiff will premul RGB if alpha mode is set to
* unassociated, which really conflicts with blender's assumptions
*
* Alternative would be to unpremul after load, but it'll be really
* lossy and unwanted behavior
*
* So let's keep this thing here for until proper solution is found (sergey)
*/
ushort extraSampleTypes[1];
extraSampleTypes[0] = EXTRASAMPLE_ASSOCALPHA;
TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, extraSampleTypes);
}
imb_read_tiff_resolution(ibuf, image);
scanline = TIFFScanlineSize(image);
if (bitspersample == 32) {
ib_flag = IB_rectfloat;
fbuf = (float *)_TIFFmalloc(scanline);
if (!fbuf) {
goto cleanup;
}
}
else if (bitspersample == 16) {
ib_flag = IB_rectfloat;
sbuf = (ushort *)_TIFFmalloc(scanline);
if (!sbuf) {
goto cleanup;
}
}
else {
ib_flag = IB_rect;
}
tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ib_flag);
if (!tmpibuf) {
goto cleanup;
}
/* simple RGBA image */
if (!ELEM(bitspersample, 32, 16)) {
success |= TIFFReadRGBAImage(image, ibuf->x, ibuf->y, tmpibuf->rect, 0);
}
/* contiguous channels: RGBRGBRGB */
else if (config == PLANARCONFIG_CONTIG) {
for (row = 0; row < ibuf->y; row++) {
size_t ib_offset = (size_t)ibuf->x * 4 * ((size_t)ibuf->y - ((size_t)row + 1));
if (bitspersample == 32) {
success |= TIFFReadScanline(image, fbuf, row, 0);
scanline_contig_32bit(tmpibuf->rect_float + ib_offset, fbuf, ibuf->x, spp);
}
else if (bitspersample == 16) {
success |= TIFFReadScanline(image, sbuf, row, 0);
scanline_contig_16bit(tmpibuf->rect_float + ib_offset, sbuf, ibuf->x, spp);
}
}
/* Separate channels: RRRGGGBBB. */
}
else if (config == PLANARCONFIG_SEPARATE) {
/* imbufs always have 4 channels of data, so we iterate over all of them
* but only fill in from the TIFF scanline where necessary. */
for (chan = 0; chan < 4; chan++) {
for (row = 0; row < ibuf->y; row++) {
size_t ib_offset = (size_t)ibuf->x * 4 * ((size_t)ibuf->y - ((size_t)row + 1));
if (bitspersample == 32) {
if (chan == 3 && spp == 3) { /* fill alpha if only RGB TIFF */
copy_vn_fl(fbuf, ibuf->x, 1.0f);
}
else if (chan >= spp) { /* For gray-scale, duplicate first channel into G and B. */
success |= TIFFReadScanline(image, fbuf, row, 0);
}
else {
success |= TIFFReadScanline(image, fbuf, row, chan);
}
scanline_separate_32bit(tmpibuf->rect_float + ib_offset, fbuf, ibuf->x, chan);
}
else if (bitspersample == 16) {
if (chan == 3 && spp == 3) { /* fill alpha if only RGB TIFF */
copy_vn_ushort(sbuf, ibuf->x, 65535);
}
else if (chan >= spp) { /* For gray-scale, duplicate first channel into G and B. */
success |= TIFFReadScanline(image, fbuf, row, 0);
}
else {
success |= TIFFReadScanline(image, sbuf, row, chan);
}
scanline_separate_16bit(tmpibuf->rect_float + ib_offset, sbuf, ibuf->x, chan);
}
}
}
}
if (success) {
/* Code seems to be not needed for 16 bits TIFF, on PPC G5 OSX (ton) */
if (bitspersample < 16) {
if (ENDIAN_ORDER == B_ENDIAN) {
IMB_convert_rgba_to_abgr(tmpibuf);
}
}
/* assign rect last */
if (tmpibuf->rect_float) {
ibuf->rect_float = tmpibuf->rect_float;
}
else {
ibuf->rect = tmpibuf->rect;
}
ibuf->mall |= ib_flag;
ibuf->flags |= ib_flag;
tmpibuf->mall &= ~ib_flag;
}
cleanup:
if (bitspersample == 32) {
_TIFFfree(fbuf);
}
else if (bitspersample == 16) {
_TIFFfree(sbuf);
}
IMB_freeImBuf(tmpibuf);
return success;
}
void imb_inittiff(void)
{
if (!(G.debug & G_DEBUG)) {
TIFFSetErrorHandler(NULL);
}
}
ImBuf *imb_loadtiff(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
TIFF *image = NULL;
ImBuf *ibuf = NULL;
ImbTIFFMemFile memFile;
uint32_t width, height;
short spp;
int ib_depth;
/* Check whether or not we have a TIFF file. */
if (imb_is_a_tiff(mem, size) == 0) {
return NULL;
}
/* both 8 and 16 bit PNGs are default to standard byte colorspace */
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
image = imb_tiff_client_open(&memFile, mem, size);
if (image == NULL) {
printf("imb_loadtiff: could not open TIFF IO layer.\n");
return NULL;
}
/* allocate the image buffer */
TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height);
TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp);
ib_depth = spp * 8;
ibuf = IMB_allocImBuf(width, height, ib_depth, 0);
if (ibuf) {
ibuf->ftype = IMB_FTYPE_TIF;
}
else {
fprintf(stderr,
"imb_loadtiff: could not allocate memory for TIFF "
"image.\n");
TIFFClose(image);
return NULL;
}
/* get alpha mode from file header */
if (flags & IB_alphamode_detect) {
if (spp == 4) {
ushort extra, *extraSampleTypes;
const int found = TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extra, &extraSampleTypes);
if (found && (extraSampleTypes[0] == EXTRASAMPLE_ASSOCALPHA)) {
ibuf->flags |= IB_alphamode_premul;
}
}
}
/* if testing, we're done */
if (flags & IB_test) {
TIFFClose(image);
return ibuf;
}
/* read pixels */
if (!imb_read_tiff_pixels(ibuf, image)) {
fprintf(stderr, "imb_loadtiff: Failed to read tiff image.\n");
TIFFClose(image);
return NULL;
}
/* close the client layer interface to the in-memory file */
TIFFClose(image);
/* return successfully */
return ibuf;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Save TIFF
* \{ */
bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
{
TIFF *image = NULL;
uint16_t samplesperpixel, bitspersample;
size_t npixels;
uchar *pixels = NULL;
uchar *from = NULL, *to = NULL;
ushort *pixels16 = NULL, *to16 = NULL;
float *fromf = NULL;
float xres, yres;
int x, y, from_i, to_i, i;
int compress_mode = COMPRESSION_NONE;
/* check for a valid number of bytes per pixel. Like the PNG writer,
* the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
* to gray, RGB, RGBA respectively. */
samplesperpixel = (uint16_t)((ibuf->planes + 7) >> 3);
if ((samplesperpixel > 4) || (samplesperpixel == 2)) {
fprintf(stderr,
"imb_savetiff: unsupported number of bytes per "
"pixel: %d\n",
samplesperpixel);
return 0;
}
if ((ibuf->foptions.flag & TIF_16BIT) && ibuf->rect_float) {
bitspersample = 16;
}
else {
bitspersample = 8;
}
if (ibuf->foptions.flag & TIF_COMPRESS_DEFLATE) {
compress_mode = COMPRESSION_DEFLATE;
}
else if (ibuf->foptions.flag & TIF_COMPRESS_LZW) {
compress_mode = COMPRESSION_LZW;
}
else if (ibuf->foptions.flag & TIF_COMPRESS_PACKBITS) {
compress_mode = COMPRESSION_PACKBITS;
}
/* open TIFF file for writing */
if (flags & IB_mem) {
/* Failed to allocate TIFF in memory. */
fprintf(stderr,
"imb_savetiff: creation of in-memory TIFF files is "
"not yet supported.\n");
return 0;
}
/* create image as a file */
#ifdef WIN32
wchar_t *wname = alloc_utf16_from_8(filepath, 0);
image = TIFFOpenW(wname, "w");
free(wname);
#else
image = TIFFOpen(filepath, "w");
#endif
if (image == NULL) {
fprintf(stderr, "imb_savetiff: could not open TIFF for writing.\n");
return 0;
}
/* allocate array for pixel data */
npixels = ibuf->x * ibuf->y;
if (bitspersample == 16) {
pixels16 = (ushort *)_TIFFmalloc(npixels * samplesperpixel * sizeof(ushort));
}
else {
pixels = (uchar *)_TIFFmalloc(npixels * samplesperpixel * sizeof(uchar));
}
if (pixels == NULL && pixels16 == NULL) {
fprintf(stderr, "imb_savetiff: could not allocate pixels array.\n");
TIFFClose(image);
return 0;
}
/* setup pointers */
if (bitspersample == 16) {
fromf = ibuf->rect_float;
to16 = pixels16;
}
else {
from = (uchar *)ibuf->rect;
to = pixels;
}
/* setup samples per pixel */
TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, bitspersample);
TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
if (samplesperpixel == 4) {
ushort extraSampleTypes[1];
if (bitspersample == 16) {
extraSampleTypes[0] = EXTRASAMPLE_ASSOCALPHA;
}
else {
extraSampleTypes[0] = EXTRASAMPLE_UNASSALPHA;
}
/* RGBA images */
TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, extraSampleTypes);
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
}
else if (samplesperpixel == 3) {
/* RGB images */
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
}
else if (samplesperpixel == 1) {
/* Gray-scale images, 1 channel */
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
/* copy pixel data. While copying, we flip the image vertically. */
const int channels_in_float = ibuf->channels ? ibuf->channels : 4;
for (x = 0; x < ibuf->x; x++) {
for (y = 0; y < ibuf->y; y++) {
from_i = ((size_t)channels_in_float) * (y * ibuf->x + x);
to_i = samplesperpixel * ((ibuf->y - y - 1) * ibuf->x + x);
if (pixels16) {
/* convert from float source */
float rgb[4];
if (ELEM(channels_in_float, 3, 4)) {
if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) {
/* Float buffer was managed already, no need in color
* space conversion.
*/
copy_v3_v3(rgb, &fromf[from_i]);
}
else {
/* Standard linear-to-SRGB conversion if float buffer wasn't managed. */
linearrgb_to_srgb_v3_v3(rgb, &fromf[from_i]);
}
if (channels_in_float == 4) {
rgb[3] = fromf[from_i + 3];
}
else {
rgb[3] = 1.0f;
}
}
else {
if (ibuf->float_colorspace || (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA)) {
rgb[0] = fromf[from_i];
}
else {
rgb[0] = linearrgb_to_srgb(fromf[from_i]);
}
rgb[1] = rgb[2] = rgb[0];
rgb[3] = 1.0f;
}
for (i = 0; i < samplesperpixel; i++, to_i++) {
to16[to_i] = unit_float_to_ushort_clamp(rgb[i]);
}
}
else {
for (i = 0; i < samplesperpixel; i++, to_i++, from_i++) {
to[to_i] = from[from_i];
}
}
}
}
/* write the actual TIFF file */
TIFFSetField(image, TIFFTAG_IMAGEWIDTH, ibuf->x);
TIFFSetField(image, TIFFTAG_IMAGELENGTH, ibuf->y);
TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, ibuf->y);
TIFFSetField(image, TIFFTAG_COMPRESSION, compress_mode);
TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
if (ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) {
xres = (float)(ibuf->ppm[0] * 0.0254);
yres = (float)(ibuf->ppm[1] * 0.0254);
}
else {
xres = yres = IMB_DPI_DEFAULT;
}
TIFFSetField(image, TIFFTAG_XRESOLUTION, xres);
TIFFSetField(image, TIFFTAG_YRESOLUTION, yres);
TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
if (TIFFWriteEncodedStrip(image,
0,
(bitspersample == 16) ? (uchar *)pixels16 : pixels,
(size_t)ibuf->x * ibuf->y * samplesperpixel * bitspersample / 8) ==
-1) {
fprintf(stderr, "imb_savetiff: Could not write encoded TIFF.\n");
TIFFClose(image);
if (pixels) {
_TIFFfree(pixels);
}
if (pixels16) {
_TIFFfree(pixels16);
}
return 1;
}
/* close the TIFF file */
TIFFClose(image);
if (pixels) {
_TIFFfree(pixels);
}
if (pixels16) {
_TIFFfree(pixels16);
}
return 1;
}
/** \} */

View File

@ -41,26 +41,18 @@
#define UTIL_DEBUG 0
const char *imb_ext_image[] = {
".png", ".tga", ".bmp", ".jpg", ".jpeg", ".sgi", ".rgb", ".rgba",
#ifdef WITH_TIFF
".tif", ".tiff", ".tx",
#endif
".png", ".tga", ".bmp", ".jpg", ".jpeg", ".sgi", ".rgb", ".rgba", ".tif", ".tiff", ".tx",
#ifdef WITH_OPENJPEG
".jp2", ".j2c",
#endif
#ifdef WITH_HDR
".hdr",
#endif
#ifdef WITH_DDS
".dds",
#endif
".hdr", ".dds",
#ifdef WITH_CINEON
".dpx", ".cin",
#endif
#ifdef WITH_OPENEXR
".exr",
#endif
".psd", ".pdd", ".psb",
".psd", ".pdd", ".psb",
#ifdef WITH_WEBP
".webp",
#endif

View File

@ -80,7 +80,6 @@ static const char *imb_gpu_get_swizzle(const ImBuf *ibuf)
}
/* Return false if no suitable format was found. */
#ifdef WITH_DDS
static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *r_texture_format)
{
/* For DDS we only support data, scene linear and sRGB. Converting to
@ -102,7 +101,6 @@ static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *
}
return true;
}
#endif
/**
* Apply colormanagement and scale buffer if needed.
@ -326,7 +324,6 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
}
}
#ifdef WITH_DDS
if (ibuf->ftype == IMB_FTYPE_DDS) {
eGPUTextureFormat compressed_format;
if (!IMB_gpu_get_compressed_format(ibuf, &compressed_format)) {
@ -356,7 +353,6 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
/* Fallback to uncompressed texture. */
fprintf(stderr, " falling back to uncompressed.\n");
}
#endif
eGPUDataFormat data_format;
eGPUTextureFormat tex_format;

View File

@ -70,6 +70,11 @@ if(WITH_HARU)
)
list(APPEND LIB
${HARU_LIBRARIES}
# Haru needs `TIFFFaxBlackCodes` & `TIFFFaxWhiteCodes` symbols from TIFF.
# Can be removed with Haru 2.4.0. They should be shipping with their own
# Fax codes defined by default from that version onwards.
${TIFF_LIBRARY}
)
add_definitions(-DWITH_HARU)
endif()

View File

@ -245,26 +245,14 @@ if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
if(WITH_IMAGE_TIFF)
add_definitions(-DWITH_TIFF)
endif()
if(WITH_IMAGE_OPENJPEG)
add_definitions(-DWITH_OPENJPEG)
endif()
if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
endif()
if(WITH_IMAGE_CINEON)
add_definitions(-DWITH_CINEON)
endif()
if(WITH_IMAGE_HDR)
add_definitions(-DWITH_HDR)
endif()
if(WITH_IMAGE_WEBP)
add_definitions(-DWITH_WEBP)
endif()

View File

@ -98,9 +98,13 @@ static void rna_generate_static_parameter_prototypes(FILE *f,
} \
(void)0
/**
* \return 1 when the file was renamed, 0 when no action was taken, -1 on error.
*/
static int replace_if_different(const char *tmpfile, const char *dep_files[])
{
/* return 0; */ /* use for testing had edited rna */
/* Use for testing hand edited `rna_*_gen.c` files. */
// return 0;
#define REN_IF_DIFF \
{ \
@ -124,9 +128,9 @@ static int replace_if_different(const char *tmpfile, const char *dep_files[])
return -1; \
} \
remove(tmpfile); \
return 1
/* end REN_IF_DIFF */
return 1; \
((void)0)
/* End `REN_IF_DIFF`. */
FILE *fp_new = NULL, *fp_org = NULL;
int len_new, len_org;
@ -136,7 +140,7 @@ static int replace_if_different(const char *tmpfile, const char *dep_files[])
char orgfile[4096];
strcpy(orgfile, tmpfile);
orgfile[strlen(orgfile) - strlen(TMP_EXT)] = '\0'; /* strip '.tmp' */
orgfile[strlen(orgfile) - strlen(TMP_EXT)] = '\0'; /* Strip `.tmp`. */
fp_org = fopen(orgfile, "rb");
@ -144,12 +148,17 @@ static int replace_if_different(const char *tmpfile, const char *dep_files[])
REN_IF_DIFF;
}
/* XXX, trick to work around dependency problem
* assumes dep_files is in the same dir as makesrna.c, which is true for now. */
/* NOTE(@ideasman42): trick to work around dependency problem.
* The issue is as follows: When `makesrna.c` or any of the `rna_*.c` files being newer than
* their generated output, the build-system detects that the `rna_*_gen.c` file is out-dated and
* requests the `rna_*_gen.c` files are re-generated (even if this function always returns 0).
* It happens *every* rebuild, slowing incremental builds which isn't practical for development.
*
* This is only an issue for `Unix Makefiles`, `Ninja` generator doesn't have this problem. */
if (1) {
/* first check if makesrna.c is newer than generated files
* for development on makesrna.c you may want to disable this */
/* First check if `makesrna.c` is newer than generated files.
* For development on `makesrna.c` you may want to disable this. */
if (file_older(orgfile, __FILE__)) {
REN_IF_DIFF;
}
@ -158,18 +167,18 @@ static int replace_if_different(const char *tmpfile, const char *dep_files[])
REN_IF_DIFF;
}
/* now check if any files we depend on are newer than any generated files */
/* Now check if any files we depend on are newer than any generated files. */
if (dep_files) {
int pass;
for (pass = 0; dep_files[pass]; pass++) {
const char from_path[4096] = __FILE__;
char *p1, *p2;
/* dir only */
/* Only the directory (base-name). */
p1 = strrchr(from_path, '/');
p2 = strrchr(from_path, '\\');
strcpy((p1 > p2 ? p1 : p2) + 1, dep_files[pass]);
/* account for build deps, if makesrna.c (this file) is newer */
/* Account for build dependencies, if `makesrna.c` (this file) is newer. */
if (file_older(orgfile, from_path)) {
REN_IF_DIFF;
}
@ -181,7 +190,7 @@ static int replace_if_different(const char *tmpfile, const char *dep_files[])
fp_new = fopen(tmpfile, "rb");
if (fp_new == NULL) {
/* shouldn't happen, just to be safe */
/* Shouldn't happen, just to be safe. */
CLOG_ERROR(&LOG, "open error: \"%s\"", tmpfile);
fclose(fp_org);
return -1;
@ -202,7 +211,7 @@ static int replace_if_different(const char *tmpfile, const char *dep_files[])
REN_IF_DIFF;
}
/* now compare the files... */
/* Now compare the files: */
arr_new = MEM_mallocN(sizeof(char) * len_new, "rna_cmp_file_new");
arr_org = MEM_mallocN(sizeof(char) * len_org, "rna_cmp_file_org");
@ -232,7 +241,7 @@ static int replace_if_different(const char *tmpfile, const char *dep_files[])
#undef REN_IF_DIFF
}
/* Helper to solve keyword problems with C/C++ */
/* Helper to solve keyword problems with C/C++. */
static const char *rna_safe_id(const char *id)
{

View File

@ -5014,7 +5014,7 @@ static void def_vector_math(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_vec_math_items);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_ID_NODETREE);
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_NODETREE);
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}

View File

@ -280,12 +280,8 @@ const EnumPropertyItem rna_enum_curve_fit_method_items[] = {
"Output image in uncompressed Targa format"},
#if 0 /* UNUSED (so far) */
# ifdef WITH_DDS
# define R_IMF_ENUM_DDS \
{R_IMF_IMTYPE_DDS, "DDS", ICON_FILE_IMAGE, "DDS", "Output image in DDS format"},
# else
# define R_IMF_ENUM_DDS
# endif
# define R_IMF_ENUM_DDS \
{R_IMF_IMTYPE_DDS, "DDS", ICON_FILE_IMAGE, "DDS", "Output image in DDS format"},
#endif
#ifdef WITH_OPENJPEG
@ -327,23 +323,15 @@ const EnumPropertyItem rna_enum_curve_fit_method_items[] = {
# define R_IMF_ENUM_EXR
#endif
#ifdef WITH_HDR
# define R_IMF_ENUM_HDR \
{R_IMF_IMTYPE_RADHDR, \
"HDR", \
ICON_FILE_IMAGE, \
"Radiance HDR", \
"Output image in Radiance HDR format"},
#else
# define R_IMF_ENUM_HDR
#endif
#define R_IMF_ENUM_HDR \
{R_IMF_IMTYPE_RADHDR, \
"HDR", \
ICON_FILE_IMAGE, \
"Radiance HDR", \
"Output image in Radiance HDR format"},
#ifdef WITH_TIFF
# define R_IMF_ENUM_TIFF \
{R_IMF_IMTYPE_TIFF, "TIFF", ICON_FILE_IMAGE, "TIFF", "Output image in TIFF format"},
#else
# define R_IMF_ENUM_TIFF
#endif
#define R_IMF_ENUM_TIFF \
{R_IMF_IMTYPE_TIFF, "TIFF", ICON_FILE_IMAGE, "TIFF", "Output image in TIFF format"},
#ifdef WITH_WEBP
# define R_IMF_ENUM_WEBP \
@ -5726,7 +5714,6 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
};
# endif
# ifdef WITH_TIFF
static const EnumPropertyItem tiff_codec_items[] = {
{R_IMF_TIFF_CODEC_NONE, "NONE", 0, "None", ""},
{R_IMF_TIFF_CODEC_DEFLATE, "DEFLATE", 0, "Deflate", ""},
@ -5734,7 +5721,6 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
{R_IMF_TIFF_CODEC_PACKBITS, "PACKBITS", 0, "Pack Bits", ""},
{0, NULL, 0, NULL, NULL},
};
# endif
static const EnumPropertyItem color_management_items[] = {
{R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE, "FOLLOW_SCENE", 0, "Follow Scene", ""},
@ -5851,14 +5837,12 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
# endif
# ifdef WITH_TIFF
/* TIFF */
prop = RNA_def_property(srna, "tiff_codec", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "tiff_codec");
RNA_def_property_enum_items(prop, tiff_codec_items);
RNA_def_property_ui_text(prop, "Compression", "Compression mode for TIFF");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
# endif
/* Cineon and DPX */

View File

@ -62,7 +62,7 @@ typedef struct EffectInfo {
} EffectInfo;
const EnumPropertyItem rna_enum_sequence_modifier_type_items[] = {
{seqModifierType_BrightContrast, "BRIGHT_CONTRAST", ICON_NONE, "Bright/Contrast", ""},
{seqModifierType_BrightContrast, "BRIGHT_CONTRAST", ICON_NONE, "Brightness/Contrast", ""},
{seqModifierType_ColorBalance, "COLOR_BALANCE", ICON_NONE, "Color Balance", ""},
{seqModifierType_Curves, "CURVES", ICON_NONE, "Curves", ""},
{seqModifierType_HueCorrect, "HUE_CORRECT", ICON_NONE, "Hue Correct", ""},

View File

@ -580,6 +580,8 @@ static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char
BLI_strncpy(se->name, filename, sizeof(se->name));
seq->len++;
seq->flag &= ~SEQ_SINGLE_FRAME_CONTENT;
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
return se;
@ -608,6 +610,10 @@ static void rna_SequenceElements_pop(ID *id, Sequence *seq, ReportList *reports,
new_seq = MEM_callocN(sizeof(StripElem) * (seq->len - 1), "SequenceElements_pop");
seq->len--;
if (seq->len == 1) {
seq->flag |= SEQ_SINGLE_FRAME_CONTENT;
}
se = seq->strip->stripdata;
if (index > 0) {
memcpy(new_seq, se, sizeof(StripElem) * index);

View File

@ -215,6 +215,7 @@ static void rna_def_text(BlenderRNA *brna)
prop = RNA_def_property(srna, "is_modified", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Text_modified_get", NULL);
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_TEXT);
RNA_def_property_ui_text(
prop, "Modified", "Text file on disk is different than the one in memory");

View File

@ -2340,6 +2340,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "empty", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Empty", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "light", PROP_FLOAT, PROP_COLOR_GAMMA);

View File

@ -169,7 +169,7 @@ static void panel_draw(const bContext * /*C*/, Panel *panel)
uiItemR(col, ptr, "mirror_object", 0, nullptr, ICON_NONE);
uiItemR(col, ptr, "use_clip", 0, IFACE_("Clipping"), ICON_NONE);
uiItemR(col, ptr, "use_clip", 0, CTX_IFACE_(BLT_I18NCONTEXT_ID_MESH, "Clipping"), ICON_NONE);
row = uiLayoutRowWithHeading(col, true, IFACE_("Merge"));
uiItemR(row, ptr, "use_mirror_merge", 0, "", ICON_NONE);

View File

@ -31,7 +31,7 @@ DefNode(ShaderNode, SH_NODE_RGBTOBW, 0, "RGBTOB
DefNode(ShaderNode, SH_NODE_SHADERTORGB, 0, "SHADERTORGB", ShaderToRGB, "Shader to RGB", "Convert rendering effect (such as light and shadow) to color. Typically used for non-photorealistic rendering, to apply additional effects on the output of BSDFs.\nNote: only supported for Eevee")
DefNode(ShaderNode, SH_NODE_NORMAL, 0, "NORMAL", Normal, "Normal", "Generate a normal vector and a dot product")
DefNode(ShaderNode, SH_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "Apply a gamma correction")
DefNode(ShaderNode, SH_NODE_BRIGHTCONTRAST, 0, "BRIGHTCONTRAST", BrightContrast, "Bright Contrast", "Control the brightness and contrast of the input color")
DefNode(ShaderNode, SH_NODE_BRIGHTCONTRAST, 0, "BRIGHTCONTRAST", BrightContrast, "Brightness/Contrast","Control the brightness and contrast of the input color")
DefNode(ShaderNode, SH_NODE_MAPPING, def_sh_mapping, "MAPPING", Mapping, "Mapping", "Transform the input vector by applying translation, rotation, and scale")
DefNode(ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", VectorCurve, "Vector Curves", "Map an input vectors to curves, used to fine-tune the interpolation of the input")
DefNode(ShaderNode, SH_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", RGBCurve, "RGB Curves", "Apply color corrections for each color channel")
@ -44,7 +44,7 @@ DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZ
DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "Invert a color, producing a negative")
DefNode(ShaderNode, SH_NODE_SEPRGB_LEGACY, 0, "SEPRGB", SeparateRGB, "Separate RGB", "Split a color into its red, green, and blue channels (Deprecated)")
DefNode(ShaderNode, SH_NODE_COMBRGB_LEGACY, 0, "COMBRGB", CombineRGB, "Combine RGB", "Generate a color from its red, green, and blue channels (Deprecated)")
DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue Saturation Value","Apply a color transformation in the HSV color model")
DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation/Value","Apply a color transformation in the HSV color model")
DefNode(ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "Output surface material information for use in rendering")
DefNode(ShaderNode, SH_NODE_EEVEE_SPECULAR, 0, "EEVEE_SPECULAR", EeveeSpecular, "Specular BSDF", "Similar to the Principled BSDF node but uses the specular workflow instead of metallic, which functions by specifying the facing (along normal) reflection color. Energy is not conserved, so the result may not be physically accurate")
@ -143,7 +143,7 @@ DefNode(CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBLU
DefNode(CompositorNode, CMP_NODE_SEPRGBA_LEGACY, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
DefNode(CompositorNode, CMP_NODE_SEPHSVA_LEGACY, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
DefNode(CompositorNode, CMP_NODE_SETALPHA, def_cmp_set_alpha, "SETALPHA", SetAlpha, "Set Alpha", "" )
DefNode(CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue Saturation Value","" )
DefNode(CompositorNode, CMP_NODE_HUE_SAT, 0, "HUE_SAT", HueSat, "Hue/Saturation/Value","" )
DefNode(CompositorNode, CMP_NODE_IMAGE, def_cmp_image, "IMAGE", Image, "Image", "" )
DefNode(CompositorNode, CMP_NODE_R_LAYERS, def_cmp_render_layers, "R_LAYERS", RLayers, "Render Layers", "" )
DefNode(CompositorNode, CMP_NODE_COMPOSITE, def_cmp_composite, "COMPOSITE", Composite, "Composite", "" )
@ -176,7 +176,7 @@ DefNode(CompositorNode, CMP_NODE_DISPLACE, 0, "DISPLA
DefNode(CompositorNode, CMP_NODE_COMBHSVA_LEGACY,0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
DefNode(CompositorNode, CMP_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode(CompositorNode, CMP_NODE_LUMA_MATTE, def_cmp_luma_matte, "LUMA_MATTE", LumaMatte, "Luminance Key", "" )
DefNode(CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast, "Bright/Contrast", "" )
DefNode(CompositorNode, CMP_NODE_BRIGHTCONTRAST, def_cmp_brightcontrast, "BRIGHTCONTRAST", BrightContrast, "Brightness/Contrast","" )
DefNode(CompositorNode, CMP_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "" )
DefNode(CompositorNode, CMP_NODE_INVERT, def_cmp_invert, "INVERT", Invert, "Invert", "" )
DefNode(CompositorNode, CMP_NODE_NORMALIZE, 0, "NORMALIZE", Normalize, "Normalize", "" )
@ -235,7 +235,7 @@ DefNode(TextureNode, TEX_NODE_VALTORGB, def_colorramp, "VALTOR
DefNode(TextureNode, TEX_NODE_IMAGE, def_tex_image, "IMAGE", Image, "Image", "" )
DefNode(TextureNode, TEX_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", CurveRGB, "RGB Curves", "" )
DefNode(TextureNode, TEX_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
DefNode(TextureNode, TEX_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue Saturation Value", "" )
DefNode(TextureNode, TEX_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue/Saturation/Value", "" )
DefNode(TextureNode, TEX_NODE_CURVE_TIME, def_time, "CURVE_TIME", CurveTime, "Curve Time", "" )
DefNode(TextureNode, TEX_NODE_ROTATE, 0, "ROTATE", Rotate, "Rotate", "" )
DefNode(TextureNode, TEX_NODE_VIEWER, 0, "VIEWER", Viewer, "Viewer", "" )

Some files were not shown because too many files have changed in this diff Show More