WIP: Rewrite asset browser as separate editor #104978

Closed
Julian Eisel wants to merge 68 commits from asset-browser-grid-view into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
137 changed files with 2533 additions and 1222 deletions
Showing only changes of commit 91853d95a9 - Show all commits

View File

@ -360,8 +360,9 @@ USE_CXX11=true
# XXX_VERSION_SHORT is used for various things, like preferred version (when distribution provides several of them),
# and to name shortcuts to built libraries' installation directories...
CLANG_FORMAT_VERSION="10.0"
CLANG_FORMAT_VERSION_MIN="6.0"
CLANG_FORMAT_VERSION_MEX="10.0"
CLANG_FORMAT_VERSION_MEX="14.0"
PYTHON_VERSION="3.10.2"
PYTHON_VERSION_SHORT="3.10"

View File

@ -1,33 +1,8 @@
# Ceres Solver - A fast non-linear least squares minimizer
# SPDX-License-Identifier: BSD-3-Clause
# Copyright 2015 Google Inc. All rights reserved.
# http://ceres-solver.org/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Google Inc. nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Author: alexs.mac@gmail.com (Alex Stewart)
#
# Ceres Solver - A fast non-linear least squares minimizer http://ceres-solver.org/
# Author: Alex Stewart <alexs.mac@gmail.com>
# FindGflags.cmake - Find Google gflags logging library.
#

View File

@ -1,33 +1,8 @@
# Ceres Solver - A fast non-linear least squares minimizer
# SPDX-License-Identifier: BSD-3-Clause
# Copyright 2015 Google Inc. All rights reserved.
# http://ceres-solver.org/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Google Inc. nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Author: alexs.mac@gmail.com (Alex Stewart)
#
# Ceres Solver - A fast non-linear least squares minimizer http://ceres-solver.org/
# Author: Alex Stewart <alexs.mac@gmail.com>
# FindGlog.cmake - Find Google glog logging library.
#

View File

@ -71,7 +71,7 @@ void WASAPIDevice::runMixingThread()
IAudioRenderClient* render_client = nullptr;
std::chrono::milliseconds sleep_duration;
std::chrono::milliseconds sleep_duration(0);
bool run_init = true;

View File

@ -33,15 +33,13 @@ else()
endif()
if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
list(APPEND LIBRARIES ${GLUT_LIBRARIES})
add_definitions(${GL_DEFINITIONS})
list(APPEND INC_SYS ${GLEW_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS})
list(APPEND LIBRARIES ${CYCLES_GL_LIBRARIES} ${SDL2_LIBRARIES})
endif()
list(APPEND LIBRARIES ${CYCLES_GL_LIBRARIES})
# Common configuration.
add_definitions(${GL_DEFINITIONS})
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
@ -55,6 +53,18 @@ if(WITH_CYCLES_STANDALONE)
oiio_output_driver.cpp
oiio_output_driver.h
)
if(WITH_CYCLES_STANDALONE_GUI)
list(APPEND SRC
opengl/display_driver.cpp
opengl/display_driver.h
opengl/shader.cpp
opengl/shader.h
opengl/window.cpp
opengl/window.h
)
endif()
add_executable(cycles ${SRC} ${INC} ${INC_SYS})
unset(SRC)
@ -69,6 +79,10 @@ if(WITH_CYCLES_STANDALONE)
# OpenImageDenoise uses BNNS from the Accelerate framework.
set_property(TARGET cycles APPEND_STRING PROPERTY LINK_FLAGS " -framework Accelerate")
endif()
if(WITH_CYCLES_STANDALONE_GUI)
set_property(TARGET cycles APPEND_STRING PROPERTY LINK_FLAGS
" -framework Cocoa -framework CoreAudio -framework AudioUnit -framework AudioToolbox -framework ForceFeedback -framework CoreVideo")
endif()
endif()
if(UNIX AND NOT APPLE)

View File

@ -27,11 +27,10 @@
#include "app/oiio_output_driver.h"
#ifdef WITH_CYCLES_STANDALONE_GUI
# include "util/view.h"
# include "opengl/display_driver.h"
# include "opengl/window.h"
#endif
#include "app/cycles_xml.h"
CCL_NAMESPACE_BEGIN
struct Options {
@ -117,7 +116,14 @@ static void session_init()
options.output_pass = "combined";
options.session = new Session(options.session_params, options.scene_params);
if (!options.output_filepath.empty()) {
#ifdef WITH_CYCLES_STANDALONE_GUI
if (!options.session_params.background) {
options.session->set_display_driver(make_unique<OpenGLDisplayDriver>(
window_opengl_context_enable, window_opengl_context_disable));
}
else
#endif
if (!options.output_filepath.empty()) {
options.session->set_output_driver(make_unique<OIIOOutputDriver>(
options.output_filepath, options.output_pass, session_print));
}
@ -126,7 +132,7 @@ static void session_init()
options.session->progress.set_update_callback(function_bind(&session_print_status));
#ifdef WITH_CYCLES_STANDALONE_GUI
else
options.session->progress.set_update_callback(function_bind(&view_redraw));
options.session->progress.set_update_callback(function_bind(&window_redraw));
#endif
/* load scene */
@ -191,10 +197,10 @@ static void display_info(Progress &progress)
sample_time,
interactive.c_str());
view_display_info(str.c_str());
window_display_info(str.c_str());
if (options.show_help)
view_display_help();
window_display_help();
}
static void display()
@ -525,15 +531,15 @@ int main(int argc, const char **argv)
string title = "Cycles: " + path_filename(options.filepath);
/* init/exit are callback so they run while GL is initialized */
view_main_loop(title.c_str(),
options.width,
options.height,
session_init,
session_exit,
resize,
display,
keyboard,
motion);
window_main_loop(title.c_str(),
options.width,
options.height,
session_init,
session_exit,
resize,
display,
keyboard,
motion);
}
#endif

View File

@ -0,0 +1,385 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "app/opengl/display_driver.h"
#include "app/opengl/shader.h"
#include "util/log.h"
#include "util/string.h"
#include <GL/glew.h>
#include <SDL.h>
CCL_NAMESPACE_BEGIN
/* --------------------------------------------------------------------
* OpenGLDisplayDriver.
*/
OpenGLDisplayDriver::OpenGLDisplayDriver(const function<bool()> &gl_context_enable,
const function<void()> &gl_context_disable)
: gl_context_enable_(gl_context_enable), gl_context_disable_(gl_context_disable)
{
}
OpenGLDisplayDriver::~OpenGLDisplayDriver()
{
}
/* --------------------------------------------------------------------
* Update procedure.
*/
void OpenGLDisplayDriver::next_tile_begin()
{
/* Assuming no tiles used in interactive display. */
}
bool OpenGLDisplayDriver::update_begin(const Params &params, int texture_width, int texture_height)
{
/* Note that it's the responsibility of OpenGLDisplayDriver to ensure updating and drawing
* the texture does not happen at the same time. This is achieved indirectly.
*
* When enabling the OpenGL context, it uses an internal mutex lock DST.gl_context_lock.
* This same lock is also held when do_draw() is called, which together ensure mutual
* exclusion.
*
* This locking is not performed on the Cycles side, because that would cause lock inversion. */
if (!gl_context_enable_()) {
return false;
}
if (gl_render_sync_) {
glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
}
if (!gl_texture_resources_ensure()) {
gl_context_disable_();
return false;
}
/* Update texture dimensions if needed. */
if (texture_.width != texture_width || texture_.height != texture_height) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA16F, texture_width, texture_height, 0, GL_RGBA, GL_HALF_FLOAT, 0);
texture_.width = texture_width;
texture_.height = texture_height;
glBindTexture(GL_TEXTURE_2D, 0);
/* Texture did change, and no pixel storage was provided. Tag for an explicit zeroing out to
* avoid undefined content. */
texture_.need_clear = true;
}
/* Update PBO dimensions if needed.
*
* NOTE: Allocate the PBO for the the size which will fit the final render resolution (as in,
* at a resolution divider 1. This was we don't need to recreate graphics interoperability
* objects which are costly and which are tied to the specific underlying buffer size.
* The downside of this approach is that when graphics interoperability is not used we are
* sending too much data to GPU when resolution divider is not 1. */
const int buffer_width = params.full_size.x;
const int buffer_height = params.full_size.y;
if (texture_.buffer_width != buffer_width || texture_.buffer_height != buffer_height) {
const size_t size_in_bytes = sizeof(half4) * buffer_width * buffer_height;
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
glBufferData(GL_PIXEL_UNPACK_BUFFER, size_in_bytes, 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
texture_.buffer_width = buffer_width;
texture_.buffer_height = buffer_height;
}
/* New content will be provided to the texture in one way or another, so mark this in a
* centralized place. */
texture_.need_update = true;
return true;
}
void OpenGLDisplayDriver::update_end()
{
gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
gl_context_disable_();
}
/* --------------------------------------------------------------------
* Texture buffer mapping.
*/
half4 *OpenGLDisplayDriver::map_texture_buffer()
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
half4 *mapped_rgba_pixels = reinterpret_cast<half4 *>(
glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
if (!mapped_rgba_pixels) {
LOG(ERROR) << "Error mapping OpenGLDisplayDriver pixel buffer object.";
}
if (texture_.need_clear) {
const int64_t texture_width = texture_.width;
const int64_t texture_height = texture_.height;
memset(reinterpret_cast<void *>(mapped_rgba_pixels),
0,
texture_width * texture_height * sizeof(half4));
texture_.need_clear = false;
}
return mapped_rgba_pixels;
}
void OpenGLDisplayDriver::unmap_texture_buffer()
{
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
/* --------------------------------------------------------------------
* Graphics interoperability.
*/
OpenGLDisplayDriver::GraphicsInterop OpenGLDisplayDriver::graphics_interop_get()
{
GraphicsInterop interop_dst;
interop_dst.buffer_width = texture_.buffer_width;
interop_dst.buffer_height = texture_.buffer_height;
interop_dst.opengl_pbo_id = texture_.gl_pbo_id;
interop_dst.need_clear = texture_.need_clear;
texture_.need_clear = false;
return interop_dst;
}
void OpenGLDisplayDriver::graphics_interop_activate()
{
gl_context_enable_();
}
void OpenGLDisplayDriver::graphics_interop_deactivate()
{
gl_context_disable_();
}
/* --------------------------------------------------------------------
* Drawing.
*/
void OpenGLDisplayDriver::clear()
{
texture_.need_clear = true;
}
void OpenGLDisplayDriver::draw(const Params &params)
{
/* See do_update_begin() for why no locking is required here. */
if (texture_.need_clear) {
/* Texture is requested to be cleared and was not yet cleared.
* Do early return which should be equivalent of drawing all-zero texture. */
return;
}
if (!gl_draw_resources_ensure()) {
return;
}
if (gl_upload_sync_) {
glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
}
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
display_shader_.bind(params.full_size.x, params.full_size.y);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
if (texture_.width != params.size.x || texture_.height != params.size.y) {
/* Resolution divider is different from 1, force nearest interpolation. */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
texture_update_if_needed();
vertex_buffer_update(params);
GLuint vertex_array_object;
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
const int texcoord_attribute = display_shader_.get_tex_coord_attrib_location();
const int position_attribute = display_shader_.get_position_attrib_location();
glEnableVertexAttribArray(texcoord_attribute);
glEnableVertexAttribArray(position_attribute);
glVertexAttribPointer(
texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0);
glVertexAttribPointer(position_attribute,
2,
GL_FLOAT,
GL_FALSE,
4 * sizeof(float),
(const GLvoid *)(sizeof(float) * 2));
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteVertexArrays(1, &vertex_array_object);
display_shader_.unbind();
glDisable(GL_BLEND);
gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
}
bool OpenGLDisplayDriver::gl_draw_resources_ensure()
{
if (!texture_.gl_id) {
/* If there is no texture allocated, there is nothing to draw. Inform the draw call that it can
* can not continue. Note that this is not an unrecoverable error, so once the texture is known
* we will come back here and create all the GPU resources needed for draw. */
return false;
}
if (gl_draw_resource_creation_attempted_) {
return gl_draw_resources_created_;
}
gl_draw_resource_creation_attempted_ = true;
if (!vertex_buffer_) {
glGenBuffers(1, &vertex_buffer_);
if (!vertex_buffer_) {
LOG(ERROR) << "Error creating vertex buffer.";
return false;
}
}
gl_draw_resources_created_ = true;
return true;
}
void OpenGLDisplayDriver::gl_resources_destroy()
{
gl_context_enable_();
if (vertex_buffer_ != 0) {
glDeleteBuffers(1, &vertex_buffer_);
}
if (texture_.gl_pbo_id) {
glDeleteBuffers(1, &texture_.gl_pbo_id);
texture_.gl_pbo_id = 0;
}
if (texture_.gl_id) {
glDeleteTextures(1, &texture_.gl_id);
texture_.gl_id = 0;
}
gl_context_disable_();
}
bool OpenGLDisplayDriver::gl_texture_resources_ensure()
{
if (texture_.creation_attempted) {
return texture_.is_created;
}
texture_.creation_attempted = true;
DCHECK(!texture_.gl_id);
DCHECK(!texture_.gl_pbo_id);
/* Create texture. */
glGenTextures(1, &texture_.gl_id);
if (!texture_.gl_id) {
LOG(ERROR) << "Error creating texture.";
return false;
}
/* Configure the texture. */
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
/* Create PBO for the texture. */
glGenBuffers(1, &texture_.gl_pbo_id);
if (!texture_.gl_pbo_id) {
LOG(ERROR) << "Error creating texture pixel buffer object.";
return false;
}
/* Creation finished with a success. */
texture_.is_created = true;
return true;
}
void OpenGLDisplayDriver::texture_update_if_needed()
{
if (!texture_.need_update) {
return;
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
glTexSubImage2D(
GL_TEXTURE_2D, 0, 0, 0, texture_.width, texture_.height, GL_RGBA, GL_HALF_FLOAT, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
texture_.need_update = false;
}
void OpenGLDisplayDriver::vertex_buffer_update(const Params &params)
{
/* Invalidate old contents - avoids stalling if the buffer is still waiting in queue to be
* rendered. */
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
float *vpointer = reinterpret_cast<float *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
if (!vpointer) {
return;
}
vpointer[0] = 0.0f;
vpointer[1] = 0.0f;
vpointer[2] = params.full_offset.x;
vpointer[3] = params.full_offset.y;
vpointer[4] = 1.0f;
vpointer[5] = 0.0f;
vpointer[6] = (float)params.size.x + params.full_offset.x;
vpointer[7] = params.full_offset.y;
vpointer[8] = 1.0f;
vpointer[9] = 1.0f;
vpointer[10] = (float)params.size.x + params.full_offset.x;
vpointer[11] = (float)params.size.y + params.full_offset.y;
vpointer[12] = 0.0f;
vpointer[13] = 1.0f;
vpointer[14] = params.full_offset.x;
vpointer[15] = (float)params.size.y + params.full_offset.y;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
CCL_NAMESPACE_END

View File

@ -0,0 +1,117 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#pragma once
#include <atomic>
#include "app/opengl/shader.h"
#include "session/display_driver.h"
#include "util/function.h"
#include "util/unique_ptr.h"
CCL_NAMESPACE_BEGIN
class OpenGLDisplayDriver : public DisplayDriver {
public:
/* Callbacks for enabling and disabling the OpenGL context. Must be provided to support enabling
* the context on the Cycles render thread independent of the main thread. */
OpenGLDisplayDriver(const function<bool()> &gl_context_enable,
const function<void()> &gl_context_disable);
~OpenGLDisplayDriver();
virtual void graphics_interop_activate() override;
virtual void graphics_interop_deactivate() override;
virtual void clear() override;
void set_zoom(float zoom_x, float zoom_y);
protected:
virtual void next_tile_begin() override;
virtual bool update_begin(const Params &params, int texture_width, int texture_height) override;
virtual void update_end() override;
virtual half4 *map_texture_buffer() override;
virtual void unmap_texture_buffer() override;
virtual GraphicsInterop graphics_interop_get() override;
virtual void draw(const Params &params) override;
/* Make sure texture is allocated and its initial configuration is performed. */
bool gl_texture_resources_ensure();
/* Ensure all runtime GPU resources needed for drawing are allocated.
* Returns true if all resources needed for drawing are available. */
bool gl_draw_resources_ensure();
/* Destroy all GPU resources which are being used by this object. */
void gl_resources_destroy();
/* Update GPU texture dimensions and content if needed (new pixel data was provided).
*
* NOTE: The texture needs to be bound. */
void texture_update_if_needed();
/* Update vertex buffer with new coordinates of vertex positions and texture coordinates.
* This buffer is used to render texture in the viewport.
*
* NOTE: The buffer needs to be bound. */
void vertex_buffer_update(const Params &params);
/* Texture which contains pixels of the render result. */
struct {
/* Indicates whether texture creation was attempted and succeeded.
* Used to avoid multiple attempts of texture creation on GPU issues or GPU context
* misconfiguration. */
bool creation_attempted = false;
bool is_created = false;
/* OpenGL resource IDs of the texture itself and Pixel Buffer Object (PBO) used to write
* pixels to it.
*
* NOTE: Allocated on the engine's context. */
uint gl_id = 0;
uint gl_pbo_id = 0;
/* Is true when new data was written to the PBO, meaning, the texture might need to be resized
* and new data is to be uploaded to the GPU. */
bool need_update = false;
/* Content of the texture is to be filled with zeroes. */
std::atomic<bool> need_clear = true;
/* Dimensions of the texture in pixels. */
int width = 0;
int height = 0;
/* Dimensions of the underlying PBO. */
int buffer_width = 0;
int buffer_height = 0;
} texture_;
OpenGLShader display_shader_;
/* Special track of whether GPU resources were attempted to be created, to avoid attempts of
* their re-creation on failure on every redraw. */
bool gl_draw_resource_creation_attempted_ = false;
bool gl_draw_resources_created_ = false;
/* Vertex buffer which hold vertices of a triangle fan which is textures with the texture
* holding the render result. */
uint vertex_buffer_ = 0;
void *gl_render_sync_ = nullptr;
void *gl_upload_sync_ = nullptr;
float2 zoom_ = make_float2(1.0f, 1.0f);
function<bool()> gl_context_enable_ = nullptr;
function<void()> gl_context_disable_ = nullptr;
};
CCL_NAMESPACE_END

View File

@ -0,0 +1,197 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "app/opengl/shader.h"
#include "util/log.h"
#include "util/string.h"
#include <GL/glew.h>
CCL_NAMESPACE_BEGIN
/* --------------------------------------------------------------------
* OpenGLShader.
*/
static const char *VERTEX_SHADER =
"#version 330\n"
"uniform vec2 fullscreen;\n"
"in vec2 texCoord;\n"
"in vec2 pos;\n"
"out vec2 texCoord_interp;\n"
"\n"
"vec2 normalize_coordinates()\n"
"{\n"
" return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n"
" texCoord_interp = texCoord;\n"
"}\n\0";
static const char *FRAGMENT_SHADER =
"#version 330\n"
"uniform sampler2D image_texture;\n"
"in vec2 texCoord_interp;\n"
"out vec4 fragColor;\n"
"\n"
"void main()\n"
"{\n"
" vec4 rgba = texture(image_texture, texCoord_interp);\n"
/* Harcoded Rec.709 gamma, should use OpenColorIO eventually. */
" fragColor = pow(rgba, vec4(0.45, 0.45, 0.45, 1.0));\n"
"}\n\0";
static void shader_print_errors(const char *task, const char *log, const char *code)
{
LOG(ERROR) << "Shader: " << task << " error:";
LOG(ERROR) << "===== shader string ====";
stringstream stream(code);
string partial;
int line = 1;
while (getline(stream, partial, '\n')) {
if (line < 10) {
LOG(ERROR) << " " << line << " " << partial;
}
else {
LOG(ERROR) << line << " " << partial;
}
line++;
}
LOG(ERROR) << log;
}
static int compile_shader_program(void)
{
const struct Shader {
const char *source;
const GLenum type;
} shaders[2] = {{VERTEX_SHADER, GL_VERTEX_SHADER}, {FRAGMENT_SHADER, GL_FRAGMENT_SHADER}};
const GLuint program = glCreateProgram();
for (int i = 0; i < 2; i++) {
const GLuint shader = glCreateShader(shaders[i].type);
string source_str = shaders[i].source;
const char *c_str = source_str.c_str();
glShaderSource(shader, 1, &c_str, NULL);
glCompileShader(shader);
GLint compile_status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
if (!compile_status) {
GLchar log[5000];
GLsizei length = 0;
glGetShaderInfoLog(shader, sizeof(log), &length, log);
shader_print_errors("compile", log, c_str);
return 0;
}
glAttachShader(program, shader);
}
/* Link output. */
glBindFragDataLocation(program, 0, "fragColor");
/* Link and error check. */
glLinkProgram(program);
GLint link_status;
glGetProgramiv(program, GL_LINK_STATUS, &link_status);
if (!link_status) {
GLchar log[5000];
GLsizei length = 0;
glGetShaderInfoLog(program, sizeof(log), &length, log);
shader_print_errors("linking", log, VERTEX_SHADER);
shader_print_errors("linking", log, FRAGMENT_SHADER);
return 0;
}
return program;
}
int OpenGLShader::get_position_attrib_location()
{
if (position_attribute_location_ == -1) {
const uint shader_program = get_shader_program();
position_attribute_location_ = glGetAttribLocation(shader_program, position_attribute_name);
}
return position_attribute_location_;
}
int OpenGLShader::get_tex_coord_attrib_location()
{
if (tex_coord_attribute_location_ == -1) {
const uint shader_program = get_shader_program();
tex_coord_attribute_location_ = glGetAttribLocation(shader_program, tex_coord_attribute_name);
}
return tex_coord_attribute_location_;
}
void OpenGLShader::bind(int width, int height)
{
create_shader_if_needed();
if (!shader_program_) {
return;
}
glUseProgram(shader_program_);
glUniform1i(image_texture_location_, 0);
glUniform2f(fullscreen_location_, width, height);
}
void OpenGLShader::unbind()
{
}
uint OpenGLShader::get_shader_program()
{
return shader_program_;
}
void OpenGLShader::create_shader_if_needed()
{
if (shader_program_ || shader_compile_attempted_) {
return;
}
shader_compile_attempted_ = true;
shader_program_ = compile_shader_program();
if (!shader_program_) {
return;
}
glUseProgram(shader_program_);
image_texture_location_ = glGetUniformLocation(shader_program_, "image_texture");
if (image_texture_location_ < 0) {
LOG(ERROR) << "Shader doesn't contain the 'image_texture' uniform.";
destroy_shader();
return;
}
fullscreen_location_ = glGetUniformLocation(shader_program_, "fullscreen");
if (fullscreen_location_ < 0) {
LOG(ERROR) << "Shader doesn't contain the 'fullscreen' uniform.";
destroy_shader();
return;
}
}
void OpenGLShader::destroy_shader()
{
glDeleteProgram(shader_program_);
shader_program_ = 0;
}
CCL_NAMESPACE_END

View File

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 OpenGL Foundation */
#pragma once
#include "util/types.h"
CCL_NAMESPACE_BEGIN
class OpenGLShader {
public:
static constexpr const char *position_attribute_name = "pos";
static constexpr const char *tex_coord_attribute_name = "texCoord";
OpenGLShader() = default;
virtual ~OpenGLShader() = default;
/* Get attribute location for position and texture coordinate respectively.
* NOTE: The shader needs to be bound to have access to those. */
int get_position_attrib_location();
int get_tex_coord_attrib_location();
void bind(int width, int height);
void unbind();
protected:
uint get_shader_program();
void create_shader_if_needed();
void destroy_shader();
/* Cached values of various OpenGL resources. */
int position_attribute_location_ = -1;
int tex_coord_attribute_location_ = -1;
uint shader_program_ = 0;
int image_texture_location_ = -1;
int fullscreen_location_ = -1;
/* Shader compilation attempted. Which means, that if the shader program is 0 then compilation or
* linking has failed. Do not attempt to re-compile the shader. */
bool shader_compile_attempted_ = false;
};
CCL_NAMESPACE_END

View File

@ -0,0 +1,352 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <stdio.h>
#include <stdlib.h>
#include "app/opengl/window.h"
#include "util/string.h"
#include "util/thread.h"
#include "util/time.h"
#include "util/version.h"
#include <GL/glew.h>
#include <SDL.h>
CCL_NAMESPACE_BEGIN
/* structs */
struct Window {
WindowInitFunc initf = nullptr;
WindowExitFunc exitf = nullptr;
WindowResizeFunc resize = nullptr;
WindowDisplayFunc display = nullptr;
WindowKeyboardFunc keyboard = nullptr;
WindowMotionFunc motion = nullptr;
bool first_display = true;
bool redraw = false;
int mouseX = 0, mouseY = 0;
int mouseBut0 = 0, mouseBut2 = 0;
int width = 0, height = 0;
SDL_Window *window = nullptr;
SDL_GLContext gl_context = nullptr;
thread_mutex gl_context_mutex;
} V;
/* public */
static void window_display_text(int x, int y, const char *text)
{
/* Not currently supported, need to add text rendering support. */
#if 0
const char *c;
glRasterPos3f(x, y, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
printf("display %s\n", text);
for (c = text; *c != '\0'; c++) {
const uint8_t *bitmap = helvetica10_character_map[*c];
glBitmap(bitmap[0],
helvetica10_height,
helvetica10_x_offset,
helvetica10_y_offset,
bitmap[0],
0.0f,
bitmap + 1);
}
#else
static string last_text = "";
if (text != last_text) {
printf("%s\n", text);
last_text = text;
}
#endif
}
void window_display_info(const char *info)
{
const int height = 20;
#if 0
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.1f, 0.1f, 0.1f, 0.8f);
glRectf(0.0f, V.height - height, V.width, V.height);
glDisable(GL_BLEND);
glColor3f(0.5f, 0.5f, 0.5f);
#endif
window_display_text(10, 7 + V.height - height, info);
#if 0
glColor3f(1.0f, 1.0f, 1.0f);
#endif
}
void window_display_help()
{
const int w = (int)((float)V.width / 1.15f);
const int h = (int)((float)V.height / 1.15f);
const int x1 = (V.width - w) / 2;
#if 0
const int x2 = x1 + w;
#endif
const int y1 = (V.height - h) / 2;
const int y2 = y1 + h;
#if 0
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.5f, 0.5f, 0.5f, 0.8f);
glRectf(x1, y1, x2, y2);
glDisable(GL_BLEND);
glColor3f(0.8f, 0.8f, 0.8f);
#endif
string info = string("Cycles Renderer ") + CYCLES_VERSION_STRING;
window_display_text(x1 + 20, y2 - 20, info.c_str());
window_display_text(x1 + 20, y2 - 40, "(C) 2011-2016 Blender Foundation");
window_display_text(x1 + 20, y2 - 80, "Controls:");
window_display_text(x1 + 20, y2 - 100, "h: Info/Help");
window_display_text(x1 + 20, y2 - 120, "r: Reset");
window_display_text(x1 + 20, y2 - 140, "p: Pause");
window_display_text(x1 + 20, y2 - 160, "esc: Cancel");
window_display_text(x1 + 20, y2 - 180, "q: Quit program");
window_display_text(x1 + 20, y2 - 210, "i: Interactive mode");
window_display_text(x1 + 20, y2 - 230, "Left mouse: Move camera");
window_display_text(x1 + 20, y2 - 250, "Right mouse: Rotate camera");
window_display_text(x1 + 20, y2 - 270, "W/A/S/D: Move camera");
window_display_text(x1 + 20, y2 - 290, "0/1/2/3: Set max bounces");
#if 0
glColor3f(1.0f, 1.0f, 1.0f);
#endif
}
static void window_display()
{
if (V.first_display) {
if (V.initf) {
V.initf();
}
if (V.exitf) {
atexit(V.exitf);
}
V.first_display = false;
}
window_opengl_context_enable();
glViewport(0, 0, V.width, V.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.05f, 0.05f, 0.05f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, V.width, 0, V.height, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRasterPos3f(0, 0, 0);
if (V.display)
V.display();
SDL_GL_SwapWindow(V.window);
window_opengl_context_disable();
}
static void window_reshape(int width, int height)
{
if (V.width != width || V.height != height) {
if (V.resize) {
V.resize(width, height);
}
}
V.width = width;
V.height = height;
}
static bool window_keyboard(unsigned char key)
{
if (V.keyboard)
V.keyboard(key);
if (key == 'q') {
if (V.exitf)
V.exitf();
return true;
}
return false;
}
static void window_mouse(int button, int state, int x, int y)
{
if (button == SDL_BUTTON_LEFT) {
if (state == SDL_MOUSEBUTTONDOWN) {
V.mouseX = x;
V.mouseY = y;
V.mouseBut0 = 1;
}
else if (state == SDL_MOUSEBUTTONUP) {
V.mouseBut0 = 0;
}
}
else if (button == SDL_BUTTON_RIGHT) {
if (state == SDL_MOUSEBUTTONDOWN) {
V.mouseX = x;
V.mouseY = y;
V.mouseBut2 = 1;
}
else if (state == SDL_MOUSEBUTTONUP) {
V.mouseBut2 = 0;
}
}
}
static void window_motion(int x, int y)
{
const int but = V.mouseBut0 ? 0 : 2;
const int distX = x - V.mouseX;
const int distY = y - V.mouseY;
if (V.motion)
V.motion(distX, distY, but);
V.mouseX = x;
V.mouseY = y;
}
bool window_opengl_context_enable()
{
V.gl_context_mutex.lock();
SDL_GL_MakeCurrent(V.window, V.gl_context);
return true;
}
void window_opengl_context_disable()
{
SDL_GL_MakeCurrent(V.window, nullptr);
V.gl_context_mutex.unlock();
}
void window_main_loop(const char *title,
int width,
int height,
WindowInitFunc initf,
WindowExitFunc exitf,
WindowResizeFunc resize,
WindowDisplayFunc display,
WindowKeyboardFunc keyboard,
WindowMotionFunc motion)
{
V.width = width;
V.height = height;
V.first_display = true;
V.redraw = false;
V.initf = initf;
V.exitf = exitf;
V.resize = resize;
V.display = display;
V.keyboard = keyboard;
V.motion = motion;
SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
V.window = SDL_CreateWindow(title,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width,
height,
SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
if (V.window == nullptr) {
fprintf(stderr, "Failed to create window: %s\n", SDL_GetError());
return;
}
SDL_RaiseWindow(V.window);
V.gl_context = SDL_GL_CreateContext(V.window);
glewInit();
SDL_GL_MakeCurrent(V.window, nullptr);
window_reshape(width, height);
window_display();
while (true) {
bool quit = false;
SDL_Event event;
while (!quit && SDL_PollEvent(&event)) {
if (event.type == SDL_TEXTINPUT) {
quit = window_keyboard(event.text.text[0]);
}
else if (event.type == SDL_MOUSEMOTION) {
window_motion(event.motion.x, event.motion.y);
}
else if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) {
window_mouse(event.button.button, event.button.state, event.button.x, event.button.y);
}
else if (event.type == SDL_WINDOWEVENT) {
if (event.window.event == SDL_WINDOWEVENT_RESIZED ||
event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
window_reshape(event.window.data1, event.window.data2);
}
}
else if (event.type == SDL_QUIT) {
if (V.exitf) {
V.exitf();
}
quit = true;
}
}
if (quit) {
break;
}
if (V.redraw) {
V.redraw = false;
window_display();
}
SDL_WaitEventTimeout(NULL, 100);
}
SDL_GL_DeleteContext(V.gl_context);
SDL_DestroyWindow(V.window);
SDL_Quit();
}
void window_redraw()
{
V.redraw = true;
}
CCL_NAMESPACE_END

View File

@ -0,0 +1,35 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#pragma once
/* Functions to display a simple OpenGL window using SDL, simplified to the
* bare minimum we need to reduce boilerplate code in tests apps. */
CCL_NAMESPACE_BEGIN
typedef void (*WindowInitFunc)();
typedef void (*WindowExitFunc)();
typedef void (*WindowResizeFunc)(int width, int height);
typedef void (*WindowDisplayFunc)();
typedef void (*WindowKeyboardFunc)(unsigned char key);
typedef void (*WindowMotionFunc)(int x, int y, int button);
void window_main_loop(const char *title,
int width,
int height,
WindowInitFunc initf,
WindowExitFunc exitf,
WindowResizeFunc resize,
WindowDisplayFunc display,
WindowKeyboardFunc keyboard,
WindowMotionFunc motion);
void window_display_info(const char *info);
void window_display_help();
void window_redraw();
bool window_opengl_context_enable();
void window_opengl_context_disable();
CCL_NAMESPACE_END

View File

@ -479,26 +479,22 @@ else()
endif()
###########################################################################
# GLUT
# SDL
###########################################################################
if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
if(MSVC AND EXISTS ${_cycles_lib_dir})
add_definitions(-DFREEGLUT_STATIC -DFREEGLUT_LIB_PRAGMAS=0)
set(GLUT_LIBRARIES "${_cycles_lib_dir}/opengl/lib/freeglut_static.lib")
set(GLUT_INCLUDE_DIR "${_cycles_lib_dir}/opengl/include")
else()
find_package(GLUT)
# We can't use the version from the Blender precompiled libraries because
# it does not include the video subsystem.
find_package(SDL2)
if(NOT GLUT_FOUND)
set(WITH_CYCLES_STANDALONE_GUI OFF)
message(STATUS "GLUT not found, disabling Cycles standalone GUI")
endif()
if(NOT SDL2_FOUND)
set(WITH_CYCLES_STANDALONE_GUI OFF)
message(STATUS "SDL not found, disabling Cycles standalone GUI")
endif()
include_directories(
SYSTEM
${GLUT_INCLUDE_DIR}
${SDL2_INCLUDE_DIRS}
)
endif()

View File

@ -12,8 +12,6 @@
# ifdef WITH_HIP_DYNLOAD
# include "hipew.h"
# else
# include "util/opengl.h"
# endif
CCL_NAMESPACE_BEGIN

View File

@ -283,7 +283,10 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
ccl_gpu_kernel_lambda_pass.kernel_index = kernel_index;
gpu_parallel_active_index_array(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE,
num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass);
num_states,
indices,
num_indices,
ccl_gpu_kernel_lambda_pass);
}
ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
@ -298,7 +301,10 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
ccl_gpu_kernel_lambda_pass.kernel_index = kernel_index;
gpu_parallel_active_index_array(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE,
num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass);
num_states,
indices,
num_indices,
ccl_gpu_kernel_lambda_pass);
}
ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
@ -310,7 +316,10 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, path, queued_kernel) != 0);
gpu_parallel_active_index_array(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE,
num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass);
num_states,
indices,
num_indices,
ccl_gpu_kernel_lambda_pass);
}
ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
@ -323,7 +332,10 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, path, queued_kernel) == 0);
gpu_parallel_active_index_array(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE,
num_states, indices + indices_offset, num_indices, ccl_gpu_kernel_lambda_pass);
num_states,
indices + indices_offset,
num_indices,
ccl_gpu_kernel_lambda_pass);
}
ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
@ -336,7 +348,10 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, shadow_path, queued_kernel) == 0);
gpu_parallel_active_index_array(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE,
num_states, indices + indices_offset, num_indices, ccl_gpu_kernel_lambda_pass);
num_states,
indices + indices_offset,
num_indices,
ccl_gpu_kernel_lambda_pass);
}
ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
@ -379,7 +394,10 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
ccl_gpu_kernel_lambda_pass.num_active_paths = num_active_paths;
gpu_parallel_active_index_array(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE,
num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass);
num_states,
indices,
num_indices,
ccl_gpu_kernel_lambda_pass);
}
ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)
@ -412,7 +430,10 @@ ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE)
ccl_gpu_kernel_lambda_pass.num_active_paths = num_active_paths;
gpu_parallel_active_index_array(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE,
num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass);
num_states,
indices,
num_indices,
ccl_gpu_kernel_lambda_pass);
}
ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE)

View File

@ -22,19 +22,20 @@ CCL_NAMESPACE_BEGIN
template<uint blocksize, typename IsActiveOp>
__device__
#endif
void gpu_parallel_active_index_array_impl(const uint num_states,
ccl_global int *indices,
ccl_global int *num_indices,
void
gpu_parallel_active_index_array_impl(const uint num_states,
ccl_global int *indices,
ccl_global int *num_indices,
#ifdef __KERNEL_METAL__
const uint is_active,
const uint blocksize,
const int thread_index,
const uint state_index,
const int ccl_gpu_warp_size,
const int thread_warp,
const int warp_index,
const int num_warps,
threadgroup int *warp_offset)
const uint is_active,
const uint blocksize,
const int thread_index,
const uint state_index,
const int ccl_gpu_warp_size,
const int thread_warp,
const int warp_index,
const int num_warps,
threadgroup int *warp_offset)
{
#else
IsActiveOp is_active_op)
@ -65,7 +66,7 @@ void gpu_parallel_active_index_array_impl(const uint num_states,
ccl_gpu_syncthreads();
/* Last thread in block converts per-warp sizes to offsets, increments global size of
* index array and gets offset to write to. */
* index array and gets offset to write to. */
if (thread_index == blocksize - 1) {
/* TODO: parallelize this. */
int offset = 0;
@ -91,15 +92,27 @@ void gpu_parallel_active_index_array_impl(const uint num_states,
#ifdef __KERNEL_METAL__
# define gpu_parallel_active_index_array(dummy, num_states, indices, num_indices, is_active_op) \
const uint is_active = (ccl_gpu_global_id_x() < num_states) ? is_active_op(ccl_gpu_global_id_x()) : 0; \
gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active, \
metal_local_size, metal_local_id, metal_global_id, simdgroup_size, simd_lane_index, \
simd_group_index, num_simd_groups, simdgroup_offset)
const uint is_active = (ccl_gpu_global_id_x() < num_states) ? \
is_active_op(ccl_gpu_global_id_x()) : \
0; \
gpu_parallel_active_index_array_impl(num_states, \
indices, \
num_indices, \
is_active, \
metal_local_size, \
metal_local_id, \
metal_global_id, \
simdgroup_size, \
simd_lane_index, \
simd_group_index, \
num_simd_groups, \
simdgroup_offset)
#else
# define gpu_parallel_active_index_array(blocksize, num_states, indices, num_indices, is_active_op) \
gpu_parallel_active_index_array_impl<blocksize>(num_states, indices, num_indices, is_active_op)
# define gpu_parallel_active_index_array( \
blocksize, num_states, indices, num_indices, is_active_op) \
gpu_parallel_active_index_array_impl<blocksize>(num_states, indices, num_indices, is_active_op)
#endif

View File

@ -1,27 +1,8 @@
/*
* Based on code from OpenSubdiv released under this license:
*
* Copyright 2013 Pixar
*
* Licensed under the Apache License, Version 2.0 (the "Apache License")
* with the following modification; you may not use this file except in
* compliance with the Apache License and the following modification to it:
* Section 6. Trademarks. is deleted and replaced with:
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor
* and its affiliates, except as required to comply with Section 4(c) of
* the License and to reproduce the content of the NOTICE file.
*
* You may obtain a copy of the Apache License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Apache License with the above modification is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the Apache License for the specific
* language governing permissions and limitations under the Apache License.
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2013 Pixar. */
/** \file
* Based on code from OpenSubdiv.
*/
#pragma once

View File

@ -1,27 +1,8 @@
/*
* Based on code from OpenSubdiv released under this license:
*
* Copyright 2014 DreamWorks Animation LLC.
*
* Licensed under the Apache License, Version 2.0 (the "Apache License")
* with the following modification; you may not use this file except in
* compliance with the Apache License and the following modification to it:
* Section 6. Trademarks. is deleted and replaced with:
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor
* and its affiliates, except as required to comply with Section 4(c) of
* the License and to reproduce the content of the NOTICE file.
*
* You may obtain a copy of the Apache License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Apache License with the above modification is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the Apache License for the specific
* language governing permissions and limitations under the Apache License.
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2014 DreamWorks Animation LLC. */
/** \file
* Based on code from OpenSubdiv.
*/
#include "subd/patch_table.h"

View File

@ -7,7 +7,6 @@ set(INC
)
set(INC_SYS
${GLEW_INCLUDE_DIR}
)
set(SRC
@ -34,14 +33,6 @@ set(LIB
${TBB_LIBRARIES}
)
if(WITH_CYCLES_STANDALONE)
if(WITH_CYCLES_STANDALONE_GUI)
list(APPEND SRC
view.cpp
)
endif()
endif()
set(SRC_HEADERS
algorithm.h
aligned_malloc.h
@ -142,7 +133,6 @@ set(SRC_HEADERS
unique_ptr.h
vector.h
version.h
view.h
windows.h
xml.h
)

View File

@ -1,269 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <stdio.h>
#include <stdlib.h>
#include "util/opengl.h"
#include "util/string.h"
#include "util/time.h"
#include "util/version.h"
#include "util/view.h"
#ifdef __APPLE__
# include <GLUT/glut.h>
#else
# include <GL/glut.h>
#endif
CCL_NAMESPACE_BEGIN
/* structs */
struct View {
ViewInitFunc initf;
ViewExitFunc exitf;
ViewResizeFunc resize;
ViewDisplayFunc display;
ViewKeyboardFunc keyboard;
ViewMotionFunc motion;
bool first_display;
bool redraw;
int mouseX, mouseY;
int mouseBut0, mouseBut2;
int width, height;
} V;
/* public */
static void view_display_text(int x, int y, const char *text)
{
const char *c;
glRasterPos3f(x, y, 0);
for (c = text; *c != '\0'; c++)
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, *c);
}
void view_display_info(const char *info)
{
const int height = 20;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.1f, 0.1f, 0.1f, 0.8f);
glRectf(0.0f, V.height - height, V.width, V.height);
glDisable(GL_BLEND);
glColor3f(0.5f, 0.5f, 0.5f);
view_display_text(10, 7 + V.height - height, info);
glColor3f(1.0f, 1.0f, 1.0f);
}
void view_display_help()
{
const int w = (int)((float)V.width / 1.15f);
const int h = (int)((float)V.height / 1.15f);
const int x1 = (V.width - w) / 2;
const int x2 = x1 + w;
const int y1 = (V.height - h) / 2;
const int y2 = y1 + h;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.5f, 0.5f, 0.5f, 0.8f);
glRectf(x1, y1, x2, y2);
glDisable(GL_BLEND);
glColor3f(0.8f, 0.8f, 0.8f);
string info = string("Cycles Renderer ") + CYCLES_VERSION_STRING;
view_display_text(x1 + 20, y2 - 20, info.c_str());
view_display_text(x1 + 20, y2 - 40, "(C) 2011-2022 Blender Foundation");
view_display_text(x1 + 20, y2 - 80, "Controls:");
view_display_text(x1 + 20, y2 - 100, "h: Info/Help");
view_display_text(x1 + 20, y2 - 120, "r: Reset");
view_display_text(x1 + 20, y2 - 140, "p: Pause");
view_display_text(x1 + 20, y2 - 160, "esc: Cancel");
view_display_text(x1 + 20, y2 - 180, "q: Quit program");
view_display_text(x1 + 20, y2 - 210, "i: Interactive mode");
view_display_text(x1 + 20, y2 - 230, "Left mouse: Move camera");
view_display_text(x1 + 20, y2 - 250, "Right mouse: Rotate camera");
view_display_text(x1 + 20, y2 - 270, "W/A/S/D: Move camera");
view_display_text(x1 + 20, y2 - 290, "0/1/2/3: Set max bounces");
glColor3f(1.0f, 1.0f, 1.0f);
}
static void view_display()
{
if (V.first_display) {
if (V.initf)
V.initf();
if (V.exitf)
atexit(V.exitf);
V.first_display = false;
}
glClearColor(0.05f, 0.05f, 0.05f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, V.width, 0, V.height, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRasterPos3f(0, 0, 0);
if (V.display)
V.display();
glutSwapBuffers();
}
static void view_reshape(int width, int height)
{
if (width <= 0 || height <= 0)
return;
V.width = width;
V.height = height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (V.resize)
V.resize(width, height);
}
static void view_keyboard(unsigned char key, int x, int y)
{
if (V.keyboard)
V.keyboard(key);
if (key == 'm')
printf("mouse %d %d\n", x, y);
if (key == 'q') {
if (V.exitf)
V.exitf();
exit(0);
}
}
static void view_mouse(int button, int state, int x, int y)
{
if (button == 0) {
if (state == GLUT_DOWN) {
V.mouseX = x;
V.mouseY = y;
V.mouseBut0 = 1;
}
else if (state == GLUT_UP) {
V.mouseBut0 = 0;
}
}
else if (button == 2) {
if (state == GLUT_DOWN) {
V.mouseX = x;
V.mouseY = y;
V.mouseBut2 = 1;
}
else if (state == GLUT_UP) {
V.mouseBut2 = 0;
}
}
}
static void view_motion(int x, int y)
{
const int but = V.mouseBut0 ? 0 : 2;
const int distX = x - V.mouseX;
const int distY = y - V.mouseY;
if (V.motion)
V.motion(distX, distY, but);
V.mouseX = x;
V.mouseY = y;
}
static void view_idle()
{
if (V.redraw) {
V.redraw = false;
glutPostRedisplay();
}
time_sleep(0.1);
}
void view_main_loop(const char *title,
int width,
int height,
ViewInitFunc initf,
ViewExitFunc exitf,
ViewResizeFunc resize,
ViewDisplayFunc display,
ViewKeyboardFunc keyboard,
ViewMotionFunc motion)
{
const char *name = "app";
char *argv = (char *)name;
int argc = 1;
memset(&V, 0, sizeof(V));
V.width = width;
V.height = height;
V.first_display = true;
V.redraw = false;
V.initf = initf;
V.exitf = exitf;
V.resize = resize;
V.display = display;
V.keyboard = keyboard;
V.motion = motion;
glutInit(&argc, &argv);
glutInitWindowSize(width, height);
glutInitWindowPosition(0, 0);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow(title);
glewInit();
view_reshape(width, height);
glutDisplayFunc(view_display);
glutIdleFunc(view_idle);
glutReshapeFunc(view_reshape);
glutKeyboardFunc(view_keyboard);
glutMouseFunc(view_mouse);
glutMotionFunc(view_motion);
glutMainLoop();
}
void view_redraw()
{
V.redraw = true;
}
CCL_NAMESPACE_END

View File

@ -1,35 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#ifndef __UTIL_VIEW_H__
#define __UTIL_VIEW_H__
/* Functions to display a simple OpenGL window using GLUT, simplified to the
* bare minimum we need to reduce boilerplate code in tests apps. */
CCL_NAMESPACE_BEGIN
typedef void (*ViewInitFunc)();
typedef void (*ViewExitFunc)();
typedef void (*ViewResizeFunc)(int width, int height);
typedef void (*ViewDisplayFunc)();
typedef void (*ViewKeyboardFunc)(unsigned char key);
typedef void (*ViewMotionFunc)(int x, int y, int button);
void view_main_loop(const char *title,
int width,
int height,
ViewInitFunc initf,
ViewExitFunc exitf,
ViewResizeFunc resize,
ViewDisplayFunc display,
ViewKeyboardFunc keyboard,
ViewMotionFunc motion);
void view_display_info(const char *info);
void view_display_help();
void view_redraw();
CCL_NAMESPACE_END
#endif /*__UTIL_VIEW_H__*/

View File

@ -2013,8 +2013,10 @@ def km_node_editor(params):
("node.link_make", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("replace", True)]}),
op_menu("NODE_MT_add", {"type": 'A', "value": 'PRESS', "shift": True}),
("node.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
("node.duplicate_move_keep_inputs", {"type": 'D', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("node.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True},
{"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}),
("node.duplicate_move_keep_inputs", {"type": 'D', "value": 'PRESS', "shift": True, "ctrl": True},
{"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}),
("node.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None),
("node.detach", {"type": 'P', "value": 'PRESS', "alt": True}, None),
("node.join", {"type": 'J', "value": 'PRESS', "ctrl": True}, None),

View File

@ -1109,7 +1109,8 @@ def km_node_editor(params):
{"properties": [("replace", False)]}),
("node.link_make", {"type": 'L', "value": 'PRESS', "shift": True},
{"properties": [("replace", True)]}),
("node.duplicate_move", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("node.duplicate_move", {"type": 'D', "value": 'PRESS', "ctrl": True},
{"properties": [("NODE_OT_translate_attach", [("TRANSFORM_OT_translate", [("view2d_edge_pan", True)])])]}),
("node.parent_set", {"type": 'P', "value": 'PRESS'}, None),
("node.join", {"type": 'J', "value": 'PRESS', "ctrl": True}, None),
("node.hide_toggle", {"type": 'H', "value": 'PRESS', "ctrl": True}, None),

View File

@ -44,6 +44,26 @@ class PlayRenderedAnim(Operator):
bl_label = "Play Rendered Animation"
bl_options = {'REGISTER'}
@staticmethod
def _frame_path_with_number_char(rd, ch, **kwargs):
# Replace the number with `ch`.
# NOTE: make an api call for this would be nice, however this isn't needed in many places.
file_a = rd.frame_path(frame=0, **kwargs)
file_b = rd.frame_path(frame=-1, **kwargs)
assert len(file_b) == len(file_a) + 1
for number_beg in range(len(file_a)):
if file_a[number_beg] != file_b[number_beg]:
break
for number_end in range(-1, -(len(file_a) + 1), -1):
if file_a[number_end] != file_b[number_end]:
break
number_end += len(file_a) + 1
return file_a[:number_beg] + (ch * (number_end - number_beg)) + file_a[number_end:]
def execute(self, context):
import os
import subprocess
@ -71,21 +91,7 @@ class PlayRenderedAnim(Operator):
player_path = guess_player_path(preset)
if is_movie is False and preset in {'FRAMECYCLER', 'RV', 'MPLAYER'}:
# replace the number with '#'
file_a = rd.frame_path(frame=0, view=view_suffix)
# TODO, make an api call for this
frame_tmp = 9
file_b = rd.frame_path(frame=frame_tmp, view=view_suffix)
while len(file_a) == len(file_b):
frame_tmp = (frame_tmp * 10) + 9
file_b = rd.frame_path(frame=frame_tmp, view=view_suffix)
file_b = rd.frame_path(frame=int(frame_tmp / 10), view=view_suffix)
file = ("".join((c if file_b[i] == c else "#")
for i, c in enumerate(file_a)))
del file_a, file_b, frame_tmp
file = PlayRenderedAnim._frame_path_with_number_char(rd, "#", view=view_suffix)
file = bpy.path.abspath(file) # expand '//'
else:
path_valid = True

View File

@ -780,7 +780,7 @@ class IMAGE_HT_header(Header):
layout.template_edit_mode_selection()
else:
layout.prop(tool_settings, "uv_select_mode", text="", expand=True)
layout.prop(uvedit, "sticky_select_mode", icon_only=True)
layout.prop(tool_settings, "uv_sticky_select_mode", icon_only=True)
IMAGE_MT_editor_menus.draw_collapsible(context, layout)

View File

@ -823,7 +823,7 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_select_paint_mask")
elif mesh.use_paint_mask_vertex and mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX'}:
layout.menu("VIEW3D_MT_select_paint_mask_vertex")
elif mode_string != 'SCULPT':
elif mode_string not in {'SCULPT', 'SCULPT_CURVES'}:
layout.menu("VIEW3D_MT_select_%s" % mode_string.lower())
if gp_edit:
@ -866,7 +866,7 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_edit_curve_segments")
elif obj:
if mode_string != 'PAINT_TEXTURE':
if mode_string not in {'PAINT_TEXTURE', 'SCULPT_CURVES'}:
layout.menu("VIEW3D_MT_%s" % mode_string.lower())
if mode_string == 'SCULPT':
layout.menu("VIEW3D_MT_mask")

View File

@ -18,7 +18,7 @@
</style>
</head>
<body>
<p class="p1"><b>Blender BLENDER_VERSION</b></p>
<p class="p1"><b>Blender @BLENDER_VERSION@</b></p>
<p class="p2"><br></p>
<p class="p3"><b>About</b></p>
<p class="p4">
@ -33,13 +33,13 @@ It's free and open-source software, released under the GNU GPL licence.
The entire source code is available on our website.
</p>
<p class="p4">
For more information, visit <a href="http://www.blender.org/"><span class="s1">blender.org</span></a>.
For more information, visit <a href="https://www.blender.org/"><span class="s1">blender.org</span></a>.
</p>
<p class="p2"><br></p>
<p class="p3"><b>BLENDER_VERSION</b></p>
<p class="p3"><b>@BLENDER_VERSION@</b></p>
<p class="p4">
The Blender Foundation and online developer community is proud to present Blender BLENDER_VERSION.
<a href="https://wiki.blender.org/wiki/Reference/Release_Notes/BLENDER_VERSION">
The Blender Foundation and online developer community is proud to present Blender @BLENDER_VERSION@.
<a href="https://wiki.blender.org/wiki/Reference/Release_Notes/@BLENDER_VERSION@">
<span class="s1">More information about this release</span></a>.
</p>
<p class="p2"><br></p>
@ -79,27 +79,27 @@ download an addon as a .py or .zip file, then press the "Install Addon" button a
<p class="p3"><b>Links</b></p>
<p class="p4">Users:</p>
<p class="p5">
<span class="s3">General information <a href="http://www.blender.org/">
<span class="s3">General information <a href="https://www.blender.org/">
<span class="s4">www.blender.org</span></a> <br>
Release Notes <a href="https://wiki.blender.org/wiki/Reference/Release_Notes/BLENDER_VERSION">
<span class="s4">wiki.blender.org/wiki/Reference/Release_Notes/BLENDER_VERSION</span></a><br>
Tutorials <a href="http://www.blender.org/support/tutorials/">
Release Notes <a href="https://wiki.blender.org/wiki/Reference/Release_Notes/@BLENDER_VERSION@">
<span class="s4">wiki.blender.org/wiki/Reference/Release_Notes/@BLENDER_VERSION@</span></a><br>
Tutorials <a href="https://www.blender.org/support/tutorials/">
<span class="s4">www.blender.org/support/tutorials/</span></a> <br>
Manual <a href="https://docs.blender.org/manual/en/latest/"><span class="s4">https://docs.blender.org/manual/en/latest/</span></a><br>
User Forum <a href="http://www.blenderartists.org/">
User Forum <a href="https://www.blenderartists.org/">
<span class="s4">www.blenderartists.org</span></a><br>
IRC <a href="irc://irc.freenode.net/#blenderchat">
<span class="s4">#blenderchat</span></a> or <a href="irc://irc.freenode.net/#blender">
<span class="s4">#blender</span></a> on irc.freenode.net</span>
Chat <a href="https://blender.chat/channel/today">
<span class="s4">#today</span></a> or <a href="https://blender.chat/channel/support">
<span class="s4">#support</span></a> on blender.chat</span>
</p>
<p class="p4">Developers:</p>
<p class="p5">
<span class="s3">Development <a href="http://www.blender.org/get-involved/developers/">
<span class="s3">Development <a href="https://www.blender.org/get-involved/developers/">
<span class="s4">www.blender.org/get-involved/developers/</span></a><br>
GIT and Bug Tracker <a href="http://developer.blender.org/">
<span class="s4">www.blender.org/get-involved/</span></a><br>
IRC <a href="irc://irc.freenode.net/#blendercoders">
<span class="s4">#blendercoders</span></a> on irc.freenode.net</span>
GIT and Bug Tracker <a href="https://developer.blender.org/">
<span class="s4">developer.blender.org</span></a><br>
Chat <a href="https://blender.chat/channel/blender-coders">
<span class="s4">#blender-coders</span></a> on blender.chat</span>
</p>
<p class="p2"><br></p>
<p class="p2"><br></p>

View File

@ -74,6 +74,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_text_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_texture_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_tracking_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_userdef_enums.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_userdef_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_uuid_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_vec_types.h

View File

@ -299,22 +299,22 @@ void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], int t
* Same as above but won't use render settings.
*/
struct Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *,
const struct Scene *scene,
struct Object *obedit,
struct BMEditMesh *em,
const struct CustomData_MeshMasks *dataMask);
struct Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *obedit,
const struct CustomData_MeshMasks *dataMask);
float (*editbmesh_vert_coords_alloc(struct BMEditMesh *em, int *r_vert_len))[3];
bool editbmesh_modifier_is_enabled(struct Scene *scene,
bool editbmesh_modifier_is_enabled(const struct Scene *scene,
const struct Object *ob,
struct ModifierData *md,
bool has_prev_mesh);
void makeDerivedMesh(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *ob,
const struct CustomData_MeshMasks *dataMask);

View File

@ -88,7 +88,8 @@ struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks,
void BKE_keyingsets_copy(struct ListBase *newlist, const struct ListBase *list);
/** Process the ID pointers inside a scene's keyingsets, in see `BKE_lib_query.h` for details. */
void BKE_keyingsets_foreach_id(struct LibraryForeachIDData *data, const struct ListBase *keyingsets);
void BKE_keyingsets_foreach_id(struct LibraryForeachIDData *data,
const struct ListBase *keyingsets);
/* Free the given Keying Set path */
void BKE_keyingset_free_path(struct KeyingSet *ks, struct KS_Path *ksp);

View File

@ -4,7 +4,8 @@
#include "BLI_array.hh"
#include "BLI_color.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "DNA_customdata_types.h"

View File

@ -118,8 +118,9 @@ typedef enum eContextObjectMode {
CTX_MODE_SCULPT_GPENCIL,
CTX_MODE_WEIGHT_GPENCIL,
CTX_MODE_VERTEX_GPENCIL,
CTX_MODE_SCULPT_CURVES,
} eContextObjectMode;
#define CTX_MODE_NUM (CTX_MODE_VERTEX_GPENCIL + 1)
#define CTX_MODE_NUM (CTX_MODE_SCULPT_CURVES + 1)
/* Context */

View File

@ -12,9 +12,9 @@ extern "C" {
#endif
struct BoundBox;
struct Curves;
struct CustomDataLayer;
struct Depsgraph;
struct Curves;
struct Main;
struct Object;
struct Scene;

View File

@ -16,6 +16,7 @@ struct Brush;
struct CurveMapping;
struct Depsgraph;
struct GHash;
struct GPencilUpdateCache;
struct ListBase;
struct MDeformVert;
struct Main;
@ -32,7 +33,6 @@ struct bGPDlayer;
struct bGPDlayer_Mask;
struct bGPDstroke;
struct bGPdata;
struct GPencilUpdateCache;
#define GPENCIL_SIMPLIFY(scene) (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE)
#define GPENCIL_SIMPLIFY_ONPLAY(playing) \

View File

@ -14,11 +14,11 @@ extern "C" {
#include "BLI_sys_types.h" /* for bool */
struct DLRBT_Tree;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
struct GPencilUpdateCache;
struct bGPDframe;
struct bGPDlayer;
struct bGPDstroke;
struct bGPdata;
/* GPencilUpdateCache.flag */
typedef enum eGPUpdateCacheNodeFlag {

View File

@ -21,8 +21,8 @@
#include "DNA_image_types.h"
extern "C" {
struct PartialUpdateUser;
struct PartialUpdateRegister;
struct PartialUpdateUser;
}
namespace blender::bke::image {

View File

@ -72,26 +72,26 @@ void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri,
* For now keep the names similar to avoid confusion. */
struct Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *ob,
const struct CustomData_MeshMasks *dataMask);
struct Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *ob,
const struct CustomData_MeshMasks *dataMask);
struct Mesh *mesh_create_eval_final(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *ob,
const struct CustomData_MeshMasks *dataMask);
struct Mesh *mesh_create_eval_no_deform(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *ob,
const struct CustomData_MeshMasks *dataMask);
struct Mesh *mesh_create_eval_no_deform_render(struct Depsgraph *depsgraph,
struct Scene *scene,
const struct Scene *scene,
struct Object *ob,
const struct CustomData_MeshMasks *dataMask);

View File

@ -409,14 +409,18 @@ void BKE_modifier_session_uuid_generate(struct ModifierData *md);
bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
struct ModifierData *BKE_modifier_copy_ex(const struct ModifierData *md, int flag);
/**
* Callback's can use this to avoid copying every member.
*/
void BKE_modifier_copydata_generic(const struct ModifierData *md,
struct ModifierData *md_dst,
int flag);
void BKE_modifier_copydata(struct ModifierData *md, struct ModifierData *target);
void BKE_modifier_copydata_ex(struct ModifierData *md, struct ModifierData *target, int flag);
void BKE_modifier_copydata(const struct ModifierData *md, struct ModifierData *target);
void BKE_modifier_copydata_ex(const struct ModifierData *md,
struct ModifierData *target,
int flag);
bool BKE_modifier_depends_ontime(struct Scene *scene, struct ModifierData *md, int dag_eval_mode);
bool BKE_modifier_supports_mapping(struct ModifierData *md);
bool BKE_modifier_supports_cage(struct Scene *scene, struct ModifierData *md);

View File

@ -7,12 +7,12 @@
*/
struct ID;
struct ImageUser;
struct Main;
struct bNode;
struct bNodeLink;
struct bNodeSocket;
struct bNodeTree;
struct ImageUser;
#ifdef __cplusplus
extern "C" {

View File

@ -661,7 +661,8 @@ void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Obj
* Sculpt mode handles multi-res differently from regular meshes, but only if
* it's the last modifier on the stack and it is not on the first level.
*/
struct MultiresModifierData *BKE_sculpt_multires_active(struct Scene *scene, struct Object *ob);
struct MultiresModifierData *BKE_sculpt_multires_active(const struct Scene *scene,
struct Object *ob);
int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd);
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);

View File

@ -183,6 +183,7 @@ set(SRC
intern/mball_tessellate.c
intern/mesh.cc
intern/mesh_boolean_convert.cc
intern/mesh_calc_edges.cc
intern/mesh_convert.cc
intern/mesh_debug.cc
intern/mesh_evaluate.cc
@ -199,7 +200,6 @@ set(SRC
intern/mesh_tangent.c
intern/mesh_tessellate.c
intern/mesh_validate.c
intern/mesh_validate.cc
intern/mesh_wrapper.c
intern/modifier.c
intern/movieclip.c

View File

@ -722,7 +722,7 @@ static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
}
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
const bool use_deform,
const bool need_mapping,
@ -1240,7 +1240,7 @@ float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3]
return cos;
}
bool editbmesh_modifier_is_enabled(Scene *scene,
bool editbmesh_modifier_is_enabled(const Scene *scene,
const Object *ob,
ModifierData *md,
bool has_prev_mesh)
@ -1301,7 +1301,7 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
}
static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
BMEditMesh *em_input,
const CustomData_MeshMasks *dataMask,
@ -1595,7 +1595,7 @@ static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob, Mesh
}
static void mesh_build_data(struct Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask,
const bool need_mapping)
@ -1661,7 +1661,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
}
static void editbmesh_build_data(struct Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *obedit,
BMEditMesh *em,
CustomData_MeshMasks *dataMask)
@ -1754,7 +1754,7 @@ static void object_get_datamask(const Depsgraph *depsgraph,
}
void makeDerivedMesh(struct Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
@ -1790,7 +1790,7 @@ void makeDerivedMesh(struct Depsgraph *depsgraph,
/***/
Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
@ -1826,7 +1826,7 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
}
Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
@ -1866,7 +1866,7 @@ Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
}
Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
@ -1877,7 +1877,7 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
}
Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
@ -1888,7 +1888,7 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
}
Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
@ -1901,7 +1901,7 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
/***/
Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *obedit,
BMEditMesh *em,
const CustomData_MeshMasks *dataMask)
@ -1922,12 +1922,12 @@ Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
}
Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph,
Scene *scene,
const Scene *scene,
Object *obedit,
const CustomData_MeshMasks *dataMask)
{
BLI_assert((obedit->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
const Scene *scene_eval = (const Scene *)DEG_get_evaluated_id(depsgraph, (ID *)&scene->id);
Object *obedit_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obedit->id);
BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
return editbmesh_get_eval_cage(depsgraph, scene_eval, obedit_eval, em_eval, dataMask);

View File

@ -1207,6 +1207,9 @@ enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit,
if (object_mode & OB_MODE_VERTEX_GPENCIL) {
return CTX_MODE_VERTEX_GPENCIL;
}
if (object_mode & OB_MODE_SCULPT_CURVES) {
return CTX_MODE_SCULPT_CURVES;
}
}
}
@ -1226,11 +1229,27 @@ enum eContextObjectMode CTX_data_mode_enum(const bContext *C)
* \note Must be aligned with above enum.
*/
static const char *data_mode_strings[] = {
"mesh_edit", "curve_edit", "surface_edit", "text_edit",
"armature_edit", "mball_edit", "lattice_edit", "posemode",
"sculpt_mode", "weightpaint", "vertexpaint", "imagepaint",
"particlemode", "objectmode", "greasepencil_paint", "greasepencil_edit",
"greasepencil_sculpt", "greasepencil_weight", "greasepencil_vertex", NULL,
"mesh_edit",
"curve_edit",
"surface_edit",
"text_edit",
"armature_edit",
"mball_edit",
"lattice_edit",
"posemode",
"sculpt_mode",
"weightpaint",
"vertexpaint",
"imagepaint",
"particlemode",
"objectmode",
"greasepencil_paint",
"greasepencil_edit",
"greasepencil_sculpt",
"greasepencil_weight",
"greasepencil_vertex",
"curves_sculpt",
NULL,
};
BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1,
"Must have a string for each context mode")

View File

@ -17,7 +17,7 @@
#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_base.h"
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.hh"
#include "BLI_rand.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"

View File

@ -2823,7 +2823,7 @@ void BKE_gpencil_frame_selected_hash(bGPdata *gpd, struct GHash *r_list)
bool BKE_gpencil_can_avoid_full_copy_on_write(const Depsgraph *depsgraph, bGPdata *gpd)
{
/* For now, we only use the update cache in the active depsgraph. Othwerwise we might access the
/* For now, we only use the update cache in the active depsgraph. Otherwise we might access the
* cache while another depsgraph frees it. */
if (!DEG_is_active(depsgraph)) {
return false;

View File

@ -99,7 +99,7 @@ static void update_cache_node_create_ex(GPencilUpdateCache *root_cache,
bool full_copy)
{
if (root_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
/* Entire data-block has to be recaculated, e.g. nothing else needs to be added to the cache.
/* Entire data-block has to be recalculated, e.g. nothing else needs to be added to the cache.
*/
return;
}
@ -110,14 +110,14 @@ static void update_cache_node_create_ex(GPencilUpdateCache *root_cache,
root_cache->data = (bGPdata *)data;
root_cache->flag = node_flag;
if (full_copy) {
/* Entire data-block has to be recaculated, remove all caches of "lower" elements. */
/* Entire data-block has to be recalculated, remove all caches of "lower" elements. */
BLI_dlrbTree_free(root_cache->children, cache_node_free);
}
return;
}
const bool is_layer_update_node = (gpf_index == -1);
/* If the data pointer in GPencilUpdateCache is NULL, this element is not actually cached
/* If the data pointer in #GPencilUpdateCache is NULL, this element is not actually cached
* and does not need to be updated, but we do need the index to find elements that are in
* levels below. E.g. if a stroke needs to be updated, the frame it is in would not hold a
* pointer to it's data. */
@ -174,7 +174,7 @@ static void update_cache_node_create(
}
if (root_cache->flag == GP_UPDATE_NODE_FULL_COPY) {
/* Entire data-block has to be recaculated, e.g. nothing else needs to be added to the cache.
/* Entire data-block has to be recalculated, e.g. nothing else needs to be added to the cache.
*/
return;
}

View File

@ -431,7 +431,8 @@ static GPUTexture *image_get_gpu_texture(Image *ima,
if (ibuf_intern == nullptr) {
ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, nullptr);
if (ibuf_intern == nullptr) {
return image_gpu_texture_error_create(textarget);
*tex = image_gpu_texture_error_create(textarget);
return *tex;
}
}

View File

@ -90,8 +90,8 @@ static int chunk_number_for_pixel(int pixel_offset)
return chunk_offset;
}
struct PartialUpdateUserImpl;
struct PartialUpdateRegisterImpl;
struct PartialUpdateUserImpl;
/**
* Wrap PartialUpdateUserImpl to its C-struct (PartialUpdateUser).

View File

@ -26,7 +26,7 @@
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.hh"
#include "BLI_memarena.h"
#include "BLI_string.h"
#include "BLI_task.hh"

View File

@ -8,9 +8,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_edgehash.h"
#include "BLI_map.hh"
#include "BLI_math_base.h"
#include "BLI_task.hh"
#include "BLI_threads.h"
#include "BLI_timeit.hh"

View File

@ -1041,7 +1041,7 @@ static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh)
BKE_mesh_wrapper_ensure_mdata(mesh);
}
else {
BKE_mesh_wrapper_ensure_subdivision(object, mesh);
mesh = BKE_mesh_wrapper_ensure_subdivision(object, mesh);
}
Mesh *mesh_result = (Mesh *)BKE_id_copy_ex(
@ -1079,8 +1079,7 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph,
mask.pmask |= CD_MASK_ORIGINDEX;
}
Mesh *result = mesh_create_eval_final(depsgraph, scene, &object_for_eval, &mask);
BKE_mesh_wrapper_ensure_subdivision(object, result);
return result;
return BKE_mesh_wrapper_ensure_subdivision(object, result);
}
static Mesh *mesh_new_from_mesh_object(Depsgraph *depsgraph,
@ -1223,6 +1222,9 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain,
BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, nullptr, &CD_MASK_MESH, true);
/* Anonymous attributes shouldn't exist on original data. */
BKE_mesh_anonymous_attributes_remove(mesh_in_bmain);
/* User-count is required because so far mesh was in a limbo, where library management does
* not perform any user management (i.e. copy of a mesh will not increase users of materials). */
BKE_library_foreach_ID_link(

View File

@ -17,6 +17,7 @@
#include "BLI_array.hh"
#include "BLI_index_range.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
#include "BLI_span.hh"
#include "DNA_mesh_types.h"

View File

@ -131,7 +131,7 @@ void BKE_modifier_panel_expand(ModifierData *md)
/***/
ModifierData *BKE_modifier_new(int type)
static ModifierData *modifier_allocate_and_init(int type)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
ModifierData *md = MEM_callocN(mti->structSize, mti->structName);
@ -152,6 +152,13 @@ ModifierData *BKE_modifier_new(int type)
mti->initData(md);
}
return md;
}
ModifierData *BKE_modifier_new(int type)
{
ModifierData *md = modifier_allocate_and_init(type);
BKE_modifier_session_uuid_generate(md);
return md;
@ -315,6 +322,16 @@ void BKE_modifiers_foreach_tex_link(Object *ob, TexWalkFunc walk, void *userData
}
}
ModifierData *BKE_modifier_copy_ex(const ModifierData *md, int flag)
{
ModifierData *md_dst = modifier_allocate_and_init(md->type);
BLI_strncpy(md_dst->name, md->name, sizeof(md_dst->name));
BKE_modifier_copydata_ex(md, md_dst, flag);
return md_dst;
}
void BKE_modifier_copydata_generic(const ModifierData *md_src,
ModifierData *md_dst,
const int UNUSED(flag))
@ -348,7 +365,7 @@ static void modifier_copy_data_id_us_cb(void *UNUSED(userData),
}
}
void BKE_modifier_copydata_ex(ModifierData *md, ModifierData *target, const int flag)
void BKE_modifier_copydata_ex(const ModifierData *md, ModifierData *target, const int flag)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
@ -374,11 +391,11 @@ void BKE_modifier_copydata_ex(ModifierData *md, ModifierData *target, const int
}
else {
/* In the case copyData made full byte copy force UUID to be re-generated. */
BKE_modifier_session_uuid_generate(md);
BKE_modifier_session_uuid_generate(target);
}
}
void BKE_modifier_copydata(ModifierData *md, ModifierData *target)
void BKE_modifier_copydata(const ModifierData *md, ModifierData *target)
{
BKE_modifier_copydata_ex(md, target, 0);
}

View File

@ -1599,9 +1599,7 @@ bool BKE_object_modifier_stack_copy(Object *ob_dst,
continue;
}
ModifierData *md_dst = BKE_modifier_new(md_src->type);
BLI_strncpy(md_dst->name, md_src->name, sizeof(md_dst->name));
BKE_modifier_copydata_ex(md_src, md_dst, flag_subdata);
ModifierData *md_dst = BKE_modifier_copy_ex(md_src, flag_subdata);
BLI_addtail(&ob_dst->modifiers, md_dst);
}

View File

@ -1488,7 +1488,7 @@ void BKE_sculptsession_free(Object *ob)
}
}
MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob)
{
Mesh *me = (Mesh *)ob->data;
ModifierData *md;

View File

@ -11,6 +11,7 @@
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
#include "BLI_bounds.hh"
#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_vec_types.hh"
@ -254,68 +255,28 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
return pointcloud;
}
struct MinMaxResult {
float3 min;
float3 max;
};
static MinMaxResult min_max_no_radii(Span<float3> positions)
static std::optional<blender::bounds::MinMaxResult<float3>> point_cloud_bounds(
const PointCloud &pointcloud)
{
using namespace blender::math;
return blender::threading::parallel_reduce(
positions.index_range(),
1024,
MinMaxResult{float3(FLT_MAX), float3(-FLT_MAX)},
[&](IndexRange range, const MinMaxResult &init) {
MinMaxResult result = init;
for (const int i : range) {
min_max(positions[i], result.min, result.max);
}
return result;
},
[](const MinMaxResult &a, const MinMaxResult &b) {
return MinMaxResult{min(a.min, b.min), max(a.max, b.max)};
});
}
static MinMaxResult min_max_with_radii(Span<float3> positions, Span<float> radii)
{
using namespace blender::math;
return blender::threading::parallel_reduce(
positions.index_range(),
1024,
MinMaxResult{float3(FLT_MAX), float3(-FLT_MAX)},
[&](IndexRange range, const MinMaxResult &init) {
MinMaxResult result = init;
for (const int i : range) {
result.min = min(positions[i] - radii[i], result.min);
result.max = max(positions[i] + radii[i], result.max);
}
return result;
},
[](const MinMaxResult &a, const MinMaxResult &b) {
return MinMaxResult{min(a.min, b.min), max(a.max, b.max)};
});
Span<float3> positions{reinterpret_cast<float3 *>(pointcloud.co), pointcloud.totpoint};
if (pointcloud.radius) {
Span<float> radii{pointcloud.radius, pointcloud.totpoint};
return blender::bounds::min_max_with_radii(positions, radii);
}
return blender::bounds::min_max(positions);
}
bool BKE_pointcloud_minmax(const PointCloud *pointcloud, float r_min[3], float r_max[3])
{
using namespace blender::math;
using namespace blender;
if (!pointcloud->totpoint) {
const std::optional<bounds::MinMaxResult<float3>> min_max = point_cloud_bounds(*pointcloud);
if (!min_max) {
return false;
}
Span<float3> positions{reinterpret_cast<float3 *>(pointcloud->co), pointcloud->totpoint};
const MinMaxResult min_max = (pointcloud->radius) ?
min_max_with_radii(positions,
{pointcloud->radius, pointcloud->totpoint}) :
min_max_no_radii(positions);
copy_v3_v3(r_min, min(min_max.min, float3(r_min)));
copy_v3_v3(r_max, max(min_max.max, float3(r_max)));
copy_v3_v3(r_min, math::min(min_max->min, float3(r_min)));
copy_v3_v3(r_max, math::max(min_max->max, float3(r_max)));
return true;
}

View File

@ -6,6 +6,7 @@
#include "BKE_tracking.h"
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
namespace blender {

View File

@ -5,7 +5,7 @@
#include "FN_multi_function_builder.hh"
#include "BLI_color.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.hh"
namespace blender::bke {
@ -72,7 +72,7 @@ static int float2_to_int(const float2 &a)
}
static bool float2_to_bool(const float2 &a)
{
return !is_zero_v2(a);
return !math::is_zero(a);
}
static int8_t float2_to_int8(const float2 &a)
{
@ -85,7 +85,7 @@ static ColorGeometry4f float2_to_color(const float2 &a)
static bool float3_to_bool(const float3 &a)
{
return !is_zero_v3(a);
return !math::is_zero(a);
}
static int8_t float3_to_int8(const float3 &a)
{

View File

@ -0,0 +1,89 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
/** \file
* \ingroup bli
*
* Generic algorithms for finding the largest and smallest elements in a span.
*/
#include <optional>
#include "BLI_math_vector.hh"
#include "BLI_task.hh"
namespace blender::bounds {
template<typename T> struct MinMaxResult {
T min;
T max;
};
/**
* Find the smallest and largest values element-wise in the span.
*/
template<typename T> static std::optional<MinMaxResult<T>> min_max(Span<T> values)
{
if (values.is_empty()) {
return std::nullopt;
}
return threading::parallel_reduce(
values.index_range(),
1024,
MinMaxResult<T>(),
[&](IndexRange range, const MinMaxResult<T> &init) {
MinMaxResult<T> result = init;
for (const int i : range) {
math::min_max(values[i], result.min, result.max);
}
return result;
},
[](const MinMaxResult<T> &a, const MinMaxResult<T> &b) {
return MinMaxResult<T>{math::min(a.min, b.min), math::max(a.max, b.max)};
});
}
/**
* Find the smallest and largest values element-wise in the span, adding the radius to each element
* first. The template type T is expected to have an addition operator implemented with RadiusT.
*/
template<typename T, typename RadiusT>
static std::optional<MinMaxResult<T>> min_max_with_radii(Span<T> values, Span<RadiusT> radii)
{
BLI_assert(values.size() == radii.size());
if (values.is_empty()) {
return std::nullopt;
}
return threading::parallel_reduce(
values.index_range(),
1024,
MinMaxResult<T>(),
[&](IndexRange range, const MinMaxResult<T> &init) {
MinMaxResult<T> result = init;
for (const int i : range) {
result.min = math::min(values[i] - radii[i], result.min);
result.max = math::max(values[i] + radii[i], result.max);
}
return result;
},
[](const MinMaxResult<T> &a, const MinMaxResult<T> &b) {
return MinMaxResult<T>{math::min(a.min, b.min), math::max(a.max, b.max)};
});
}
} // namespace blender::bounds

View File

@ -5,6 +5,7 @@
#include "BLI_math_matrix.h"
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
namespace blender {

View File

@ -0,0 +1,104 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2022 Blender Foundation. */
#pragma once
/** \file
* \ingroup bli
*/
#include <algorithm>
#include <cmath>
#include <type_traits>
#include "BLI_math_base_safe.h"
#include "BLI_math_vec_types.hh"
#include "BLI_utildefines.h"
#ifdef WITH_GMP
# include "BLI_math_mpq.hh"
#endif
namespace blender::math {
template<typename T> inline bool is_zero(const T &a)
{
return a == T(0);
}
template<typename T> inline bool is_any_zero(const T &a)
{
return is_zero(a);
}
template<typename T> inline T abs(const T &a)
{
return std::abs(a);
}
template<typename T> inline T min(const T &a, const T &b)
{
return std::min(a, b);
}
template<typename T> inline T max(const T &a, const T &b)
{
return std::max(a, b);
}
template<typename T> inline T clamp(const T &a, const T &min, const T &max)
{
return std::clamp(a, min, max);
}
template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T mod(const T &a, const T &b)
{
return std::fmod(a, b);
}
template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T safe_mod(const T &a, const T &b)
{
return (b != 0) ? std::fmod(a, b) : 0;
}
template<typename T> inline void min_max(const T &value, T &min, T &max)
{
min = math::min(value, min);
max = math::max(value, max);
}
template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T safe_divide(const T &a, const T &b)
{
return (b != 0) ? a / b : T(0.0f);
}
template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T floor(const T &a)
{
return std::floor(a);
}
template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T ceil(const T &a)
{
return std::ceil(a);
}
template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))> inline T fract(const T &a)
{
return a - std::floor(a);
}
template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T interpolate(const T &a, const T &b, const T &t)
{
return a * (1 - t) + b * t;
}
template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T midpoint(const T &a, const T &b)
{
return (a + b) * T(0.5);
}
} // namespace blender::math

View File

@ -6,7 +6,7 @@
* \ingroup bli
*/
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.hh"
#ifdef WITH_GMP

View File

@ -12,9 +12,12 @@
#include <iostream>
#include <type_traits>
#include "BLI_math_vector.hh"
#include "BLI_utildefines.h"
#ifdef WITH_GMP
# include "BLI_math_mpq.hh"
#endif
namespace blender {
/* clang-format off */
@ -41,6 +44,38 @@ template<typename T> struct vec_struct_base<T, 4> {
T x, y, z, w;
};
namespace math {
template<typename T> uint64_t vector_hash(const T &vec)
{
BLI_STATIC_ASSERT(T::type_length <= 4, "Longer types need to implement vector_hash themself.");
const typename T::uint_type &uvec = *reinterpret_cast<const typename T::uint_type *>(&vec);
uint64_t result;
result = uvec[0] * uint64_t(435109);
if constexpr (T::type_length > 1) {
result ^= uvec[1] * uint64_t(380867);
}
if constexpr (T::type_length > 2) {
result ^= uvec[2] * uint64_t(1059217);
}
if constexpr (T::type_length > 3) {
result ^= uvec[3] * uint64_t(2002613);
}
return result;
}
template<typename T, int Size> inline bool is_any_zero(const vec_struct_base<T, Size> &a)
{
for (int i = 0; i < Size; i++) {
if (a[i] == T(0)) {
return true;
}
}
return false;
}
} // namespace math
template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> {
static constexpr int type_length = Size;
@ -342,7 +377,7 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size>
vec_base &operator/=(const vec_base &b)
{
BLI_assert(!math::is_any_zero(b));
BLI_assert(b != T(0));
BLI_VEC_OP_IMPL_SELF(i, (*this)[i] /= b[i]);
}
@ -486,7 +521,7 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size>
BLI_INT_OP(T) friend vec_base operator%(T a, const vec_base &b)
{
BLI_assert(!math::is_any_zero(b));
BLI_assert(b != T(0));
BLI_VEC_OP_IMPL(ret, i, ret[i] = a % b[i]);
}
@ -548,4 +583,13 @@ using double2 = vec_base<double, 2>;
using double3 = vec_base<double, 3>;
using double4 = vec_base<double, 4>;
template<typename T>
inline constexpr bool is_math_float_type = (std::is_floating_point_v<T>
#ifdef WITH_GMP
|| std::is_same_v<T, mpq_class>
#endif
);
template<typename T> inline constexpr bool is_math_integral_type = std::is_integral_v<T>;
} // namespace blender

View File

@ -11,14 +11,10 @@
#include <type_traits>
#include "BLI_math_base_safe.h"
#include "BLI_math_vector.h"
#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
#ifdef WITH_GMP
# include "BLI_math_mpq.hh"
#endif
namespace blender::math {
#ifndef NDEBUG
@ -33,305 +29,293 @@ namespace blender::math {
# define BLI_ASSERT_UNIT(v) (void)(v)
#endif
#define bT typename T::base_type
#ifdef WITH_GMP
# define BLI_ENABLE_IF_FLT_VEC(T) \
BLI_ENABLE_IF((std::is_floating_point_v<typename T::base_type> || \
std::is_same_v<typename T::base_type, mpq_class>))
#else
# define BLI_ENABLE_IF_FLT_VEC(T) BLI_ENABLE_IF((std::is_floating_point_v<typename T::base_type>))
#endif
#define BLI_ENABLE_IF_INT_VEC(T) BLI_ENABLE_IF((std::is_integral_v<typename T::base_type>))
template<typename T> inline bool is_zero(const T &a)
template<typename T, int Size> inline bool is_zero(const vec_base<T, Size> &a)
{
for (int i = 0; i < T::type_length; i++) {
if (a[i] != bT(0)) {
for (int i = 0; i < Size; i++) {
if (a[i] != T(0)) {
return false;
}
}
return true;
}
template<typename T> inline bool is_any_zero(const T &a)
template<typename T, int Size> inline vec_base<T, Size> abs(const vec_base<T, Size> &a)
{
for (int i = 0; i < T::type_length; i++) {
if (a[i] == bT(0)) {
return true;
}
}
return false;
}
template<typename T> inline T abs(const T &a)
{
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = a[i] >= 0 ? a[i] : -a[i];
}
return result;
}
template<typename T> inline T min(const T &a, const T &b)
template<typename T, int Size>
inline vec_base<T, Size> min(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
{
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = a[i] < b[i] ? a[i] : b[i];
}
return result;
}
template<typename T> inline T max(const T &a, const T &b)
template<typename T, int Size>
inline vec_base<T, Size> max(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
{
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = a[i] > b[i] ? a[i] : b[i];
}
return result;
}
template<typename T> inline T clamp(const T &a, const T &min_v, const T &max_v)
template<typename T, int Size>
inline T clamp(const vec_base<T, Size> &a,
const vec_base<T, Size> &min,
const vec_base<T, Size> &max)
{
T result = a;
for (int i = 0; i < T::type_length; i++) {
CLAMP(result[i], min_v[i], max_v[i]);
vec_base<T, Size> result = a;
for (int i = 0; i < Size; i++) {
std::clamp(result[i], min[i], max[i]);
}
return result;
}
template<typename T> inline T clamp(const T &a, const bT &min_v, const bT &max_v)
template<typename T, int Size>
inline vec_base<T, Size> clamp(const vec_base<T, Size> &a, const T &min, const T &max)
{
T result = a;
for (int i = 0; i < T::type_length; i++) {
CLAMP(result[i], min_v, max_v);
vec_base<T, Size> result = a;
for (int i = 0; i < Size; i++) {
std::clamp(result[i], min, max);
}
return result;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T mod(const T &a, const T &b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> mod(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
{
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
BLI_assert(b[i] != 0);
result[i] = std::fmod(a[i], b[i]);
}
return result;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T mod(const T &a, bT b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> mod(const vec_base<T, Size> &a, const T &b)
{
BLI_assert(b != 0);
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::fmod(a[i], b);
}
return result;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_mod(const T &a, const T &b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T safe_mod(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
{
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = (b[i] != 0) ? std::fmod(a[i], b[i]) : 0;
}
return result;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_mod(const T &a, bT b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T safe_mod(const vec_base<T, Size> &a, const T &b)
{
if (b == 0) {
return T(0.0f);
return vec_base<T, Size>(0);
}
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::fmod(a[i], b);
}
return result;
}
template<typename T> inline void min_max(const T &vector, T &min_vec, T &max_vec)
template<typename T, int Size>
inline void min_max(const vec_base<T, Size> &vector,
vec_base<T, Size> &min,
vec_base<T, Size> &max)
{
min_vec = min(vector, min_vec);
max_vec = max(vector, max_vec);
min = math::min(vector, min);
max = math::max(vector, max);
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_divide(const T &a, const T &b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> safe_divide(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
{
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = (b[i] == 0) ? 0 : a[i] / b[i];
}
return result;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_divide(const T &a, const bT b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> safe_divide(const vec_base<T, Size> &a, const T &b)
{
return (b != 0) ? a / b : T(0.0f);
return (b != 0) ? a / b : vec_base<T, Size>(0.0f);
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T floor(const T &a)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> floor(const vec_base<T, Size> &a)
{
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::floor(a[i]);
}
return result;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T ceil(const T &a)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> ceil(const vec_base<T, Size> &a)
{
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = std::ceil(a[i]);
}
return result;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T fract(const T &a)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> fract(const vec_base<T, Size> &a)
{
T result;
for (int i = 0; i < T::type_length; i++) {
vec_base<T, Size> result;
for (int i = 0; i < Size; i++) {
result[i] = a[i] - std::floor(a[i]);
}
return result;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT dot(const T &a, const T &b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T dot(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
{
bT result = a[0] * b[0];
for (int i = 1; i < T::type_length; i++) {
T result = a[0] * b[0];
for (int i = 1; i < Size; i++) {
result += a[i] * b[i];
}
return result;
}
template<typename T> inline bT length_manhattan(const T &a)
template<typename T, int Size> inline T length_manhattan(const vec_base<T, Size> &a)
{
bT result = std::abs(a[0]);
for (int i = 1; i < T::type_length; i++) {
T result = std::abs(a[0]);
for (int i = 1; i < Size; i++) {
result += std::abs(a[i]);
}
return result;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT length_squared(const T &a)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T length_squared(const vec_base<T, Size> &a)
{
return dot(a, a);
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT length(const T &a)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T length(const vec_base<T, Size> &a)
{
return std::sqrt(length_squared(a));
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT distance_manhattan(const T &a, const T &b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T distance_manhattan(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
{
return length_manhattan(a - b);
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT distance_squared(const T &a, const T &b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T distance_squared(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
{
return length_squared(a - b);
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT distance(const T &a, const T &b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline T distance(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
{
return length(a - b);
}
template<typename T> uint64_t vector_hash(const T &vec)
{
BLI_STATIC_ASSERT(T::type_length <= 4, "Longer types need to implement vector_hash themself.");
const typename T::uint_type &uvec = *reinterpret_cast<const typename T::uint_type *>(&vec);
uint64_t result;
result = uvec[0] * uint64_t(435109);
if constexpr (T::type_length > 1) {
result ^= uvec[1] * uint64_t(380867);
}
if constexpr (T::type_length > 2) {
result ^= uvec[2] * uint64_t(1059217);
}
if constexpr (T::type_length > 3) {
result ^= uvec[3] * uint64_t(2002613);
}
return result;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T reflect(const T &incident, const T &normal)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> reflect(const vec_base<T, Size> &incident,
const vec_base<T, Size> &normal)
{
BLI_ASSERT_UNIT(normal);
return incident - 2.0 * dot(normal, incident) * normal;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
inline T refract(const T &incident, const T &normal, const bT eta)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> refract(const vec_base<T, Size> &incident,
const vec_base<T, Size> &normal,
const T &eta)
{
float dot_ni = dot(normal, incident);
float k = 1.0f - eta * eta * (1.0f - dot_ni * dot_ni);
if (k < 0.0f) {
return T(0.0f);
return vec_base<T, Size>(0.0f);
}
return eta * incident - (eta * dot_ni + sqrt(k)) * normal;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T project(const T &p, const T &v_proj)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> project(const vec_base<T, Size> &p, const vec_base<T, Size> &v_proj)
{
if (UNLIKELY(is_zero(v_proj))) {
return T(0.0f);
return vec_base<T, Size>(0.0f);
}
return v_proj * (dot(p, v_proj) / dot(v_proj, v_proj));
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
inline T normalize_and_get_length(const T &v, bT &out_length)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> normalize_and_get_length(const vec_base<T, Size> &v, T &out_length)
{
out_length = length_squared(v);
/* A larger value causes normalize errors in a scaled down models with camera extreme close. */
constexpr bT threshold = std::is_same_v<bT, double> ? 1.0e-70 : 1.0e-35f;
constexpr T threshold = std::is_same_v<T, double> ? 1.0e-70 : 1.0e-35f;
if (out_length > threshold) {
out_length = sqrt(out_length);
return v / out_length;
}
/* Either the vector is small or one of it's values contained `nan`. */
out_length = 0.0;
return T(0.0);
return vec_base<T, Size>(0.0);
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T normalize(const T &v)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> normalize(const vec_base<T, Size> &v)
{
bT len;
T len;
return normalize_and_get_length(v, len);
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T), BLI_ENABLE_IF((T::type_length == 3))>
inline T cross(const T &a, const T &b)
template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, 3> cross(const vec_base<T, 3> &a, const vec_base<T, 3> &b)
{
return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
template<typename T,
BLI_ENABLE_IF((std::is_same_v<bT, float>)),
BLI_ENABLE_IF((T::type_length == 3))>
inline T cross_high_precision(const T &a, const T &b)
inline vec_base<float, 3> cross_high_precision(const vec_base<float, 3> &a,
const vec_base<float, 3> &b)
{
return {(float)((double)a.y * b.z - (double)a.z * b.y),
(float)((double)a.z * b.x - (double)a.x * b.z),
(float)((double)a.x * b.y - (double)a.y * b.x)};
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T), BLI_ENABLE_IF((T::type_length == 3))>
inline T cross_poly(Span<T> poly)
template<typename T, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, 3> cross_poly(Span<vec_base<T, 3>> poly)
{
/* Newell's Method. */
int nv = static_cast<int>(poly.size());
if (nv < 3) {
return T(0, 0, 0);
return vec_base<T, 3>(0, 0, 0);
}
const T *v_prev = &poly[nv - 1];
const T *v_curr = &poly[0];
T n(0, 0, 0);
const vec_base<T, 3> *v_prev = &poly[nv - 1];
const vec_base<T, 3> *v_curr = &poly[0];
vec_base<T, 3> n(0, 0, 0);
for (int i = 0; i < nv;) {
n[0] = n[0] + ((*v_prev)[1] - (*v_curr)[1]) * ((*v_prev)[2] + (*v_curr)[2]);
n[1] = n[1] + ((*v_prev)[2] - (*v_curr)[2]) * ((*v_prev)[0] + (*v_curr)[0]);
@ -345,25 +329,31 @@ inline T cross_poly(Span<T> poly)
return n;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T interpolate(const T &a, const T &b, bT t)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> interpolate(const vec_base<T, Size> &a,
const vec_base<T, Size> &b,
const T &t)
{
return a * (1 - t) + b * t;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T midpoint(const T &a, const T &b)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> midpoint(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
{
return (a + b) * 0.5;
}
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
inline T faceforward(const T &vector, const T &incident, const T &reference)
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
inline vec_base<T, Size> faceforward(const vec_base<T, Size> &vector,
const vec_base<T, Size> &incident,
const vec_base<T, Size> &reference)
{
return (dot(reference, incident) < 0) ? vector : -vector;
}
template<typename T> inline int dominant_axis(const T &a)
template<typename T> inline int dominant_axis(const vec_base<T, 3> &a)
{
T b = abs(a);
vec_base<T, 3> b = abs(a);
return ((b.x > b.y) ? ((b.x > b.z) ? 0 : 2) : ((b.y > b.z) ? 1 : 2));
}
@ -376,14 +366,13 @@ template<typename T> struct isect_result {
LINE_LINE_EXACT = 1,
LINE_LINE_CROSS = 2,
} kind;
bT lambda;
typename T::base_type lambda;
};
template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
isect_result<T> isect_seg_seg(const T &v1, const T &v2, const T &v3, const T &v4);
#undef BLI_ENABLE_IF_FLT_VEC
#undef BLI_ENABLE_IF_INT_VEC
#undef bT
template<typename T, int Size, BLI_ENABLE_IF((is_math_float_type<T>))>
isect_result<vec_base<T, Size>> isect_seg_seg(const vec_base<T, Size> &v1,
const vec_base<T, Size> &v2,
const vec_base<T, Size> &v3,
const vec_base<T, Size> &v4);
} // namespace blender::math

View File

@ -162,6 +162,7 @@ set(SRC
BLI_bitmap_draw_2d.h
BLI_blenlib.h
BLI_boxpack_2d.h
BLI_bounds.hh
BLI_buffer.h
BLI_color.hh
BLI_compiler_attrs.h
@ -220,6 +221,7 @@ set(SRC
BLI_map.hh
BLI_map_slots.hh
BLI_math.h
BLI_math_base.hh
BLI_math_base.h
BLI_math_base_safe.h
BLI_math_bits.h
@ -394,6 +396,7 @@ if(WITH_GTESTS)
tests/BLI_array_store_test.cc
tests/BLI_array_test.cc
tests/BLI_array_utils_test.cc
tests/BLI_bounds_test.cc
tests/BLI_color_test.cc
tests/BLI_delaunay_2d_test.cc
tests/BLI_disjoint_set_test.cc

View File

@ -1691,7 +1691,7 @@ void fill_crossdata_for_intersect(const FatCo<T> &curco,
BLI_assert(se_vcva->vert == vc && se_vcva->next->vert == va);
BLI_assert(se_vcvb->vert == vc && se_vcvb->next->vert == vb);
UNUSED_VARS_NDEBUG(vc);
auto isect = isect_seg_seg<vec2<T>>(va->co.exact, vb->co.exact, curco.exact, v2->co.exact);
auto isect = isect_seg_seg(va->co.exact, vb->co.exact, curco.exact, v2->co.exact);
T &lambda = isect.lambda;
switch (isect.kind) {
case isect_result<vec2<T>>::LINE_LINE_CROSS: {
@ -2556,7 +2556,7 @@ template<typename T> void detect_holes(CDT_state<T> *cdt_state)
if (e->symedges[0].face->visit_index == e->symedges[1].face->visit_index) {
continue; /* Don't count hits on edges between faces in same region. */
}
auto isect = isect_seg_seg<vec2<T>>(ray_end.exact,
auto isect = isect_seg_seg(ray_end.exact,
mid.exact,
e->symedges[0].vert->co.exact,
e->symedges[1].vert->co.exact);

View File

@ -22,7 +22,7 @@
# include "BLI_math_geom.h"
# include "BLI_math_mpq.hh"
# include "BLI_math_vec_mpq_types.hh"
# include "BLI_math_vec_types.hh"
# include "BLI_math_vector.hh"
# include "BLI_mesh_intersect.hh"
# include "BLI_set.hh"
# include "BLI_span.hh"

View File

@ -23,6 +23,7 @@
# include "BLI_math_mpq.hh"
# include "BLI_math_vec_mpq_types.hh"
# include "BLI_math_vec_types.hh"
# include "BLI_math_vector.h"
# include "BLI_polyfill_2d.h"
# include "BLI_set.hh"
# include "BLI_span.hh"

View File

@ -7,7 +7,7 @@
#include <cstdint>
#include "BLI_math_base_safe.h"
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.hh"
#include "BLI_noise.hh"
#include "BLI_utildefines.h"
@ -581,7 +581,7 @@ float perlin_fractal(float4 position, float octaves, float roughness)
* positions to act as a seed since the noise functions don't have seed values.
* The offset's components are in the range [100, 200], not too high to cause
* bad precision and not too small to be noticeable. We use float seed because
* OSL only support float hashes and we need to maintain compatibility with it.
* OSL only supports float hashes and we need to maintain compatibility with it.
*/
BLI_INLINE float random_float_offset(float seed)
@ -727,7 +727,7 @@ float musgrave_fBm(const float co,
float p = co;
float value = 0.0f;
float pwr = 1.0f;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
for (int i = 0; i < (int)octaves; i++) {
@ -752,7 +752,7 @@ float musgrave_multi_fractal(const float co,
float p = co;
float value = 1.0f;
float pwr = 1.0f;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
for (int i = 0; i < (int)octaves; i++) {
@ -776,11 +776,11 @@ float musgrave_hetero_terrain(const float co,
const float offset)
{
float p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
/* first unscaled octave of function; later octaves are scaled */
/* First unscaled octave of function; later octaves are scaled. */
float value = offset + perlin_signed(p);
p *= lacunarity;
@ -808,7 +808,7 @@ float musgrave_hybrid_multi_fractal(const float co,
const float gain)
{
float p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
float value = perlin_signed(p) + offset;
@ -845,10 +845,10 @@ float musgrave_ridged_multi_fractal(const float co,
const float gain)
{
float p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
float signal = offset - fabsf(perlin_signed(p));
float signal = offset - std::abs(perlin_signed(p));
signal *= signal;
float value = signal;
float weight = 1.0f;
@ -858,7 +858,7 @@ float musgrave_ridged_multi_fractal(const float co,
for (int i = 1; i < (int)octaves; i++) {
p *= lacunarity;
weight = CLAMPIS(signal * gain, 0.0f, 1.0f);
signal = offset - fabsf(perlin_signed(p));
signal = offset - std::abs(perlin_signed(p));
signal *= signal;
signal *= weight;
value += signal * pwr;
@ -878,7 +878,7 @@ float musgrave_fBm(const float2 co,
float2 p = co;
float value = 0.0f;
float pwr = 1.0f;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
for (int i = 0; i < (int)octaves; i++) {
@ -903,7 +903,7 @@ float musgrave_multi_fractal(const float2 co,
float2 p = co;
float value = 1.0f;
float pwr = 1.0f;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
for (int i = 0; i < (int)octaves; i++) {
@ -927,10 +927,10 @@ float musgrave_hetero_terrain(const float2 co,
const float offset)
{
float2 p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
/* first unscaled octave of function; later octaves are scaled */
/* First unscaled octave of function; later octaves are scaled. */
float value = offset + perlin_signed(p);
p *= lacunarity;
@ -960,7 +960,7 @@ float musgrave_hybrid_multi_fractal(const float2 co,
const float gain)
{
float2 p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
float value = perlin_signed(p) + offset;
@ -997,10 +997,10 @@ float musgrave_ridged_multi_fractal(const float2 co,
const float gain)
{
float2 p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
float signal = offset - fabsf(perlin_signed(p));
float signal = offset - std::abs(perlin_signed(p));
signal *= signal;
float value = signal;
float weight = 1.0f;
@ -1010,7 +1010,7 @@ float musgrave_ridged_multi_fractal(const float2 co,
for (int i = 1; i < (int)octaves; i++) {
p *= lacunarity;
weight = CLAMPIS(signal * gain, 0.0f, 1.0f);
signal = offset - fabsf(perlin_signed(p));
signal = offset - std::abs(perlin_signed(p));
signal *= signal;
signal *= weight;
value += signal * pwr;
@ -1030,7 +1030,7 @@ float musgrave_fBm(const float3 co,
float3 p = co;
float value = 0.0f;
float pwr = 1.0f;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
@ -1056,7 +1056,7 @@ float musgrave_multi_fractal(const float3 co,
float3 p = co;
float value = 1.0f;
float pwr = 1.0f;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
@ -1081,7 +1081,7 @@ float musgrave_hetero_terrain(const float3 co,
const float offset)
{
float3 p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
/* first unscaled octave of function; later octaves are scaled */
@ -1114,7 +1114,7 @@ float musgrave_hybrid_multi_fractal(const float3 co,
const float gain)
{
float3 p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
float value = perlin_signed(p) + offset;
@ -1151,10 +1151,10 @@ float musgrave_ridged_multi_fractal(const float3 co,
const float gain)
{
float3 p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
float signal = offset - fabsf(perlin_signed(p));
float signal = offset - std::abs(perlin_signed(p));
signal *= signal;
float value = signal;
float weight = 1.0f;
@ -1164,7 +1164,7 @@ float musgrave_ridged_multi_fractal(const float3 co,
for (int i = 1; i < (int)octaves; i++) {
p *= lacunarity;
weight = CLAMPIS(signal * gain, 0.0f, 1.0f);
signal = offset - fabsf(perlin_signed(p));
signal = offset - std::abs(perlin_signed(p));
signal *= signal;
signal *= weight;
value += signal * pwr;
@ -1184,7 +1184,7 @@ float musgrave_fBm(const float4 co,
float4 p = co;
float value = 0.0f;
float pwr = 1.0f;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
@ -1210,7 +1210,7 @@ float musgrave_multi_fractal(const float4 co,
float4 p = co;
float value = 1.0f;
float pwr = 1.0f;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
const float octaves = CLAMPIS(octaves_unclamped, 0.0f, 15.0f);
@ -1235,7 +1235,7 @@ float musgrave_hetero_terrain(const float4 co,
const float offset)
{
float4 p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
/* first unscaled octave of function; later octaves are scaled */
@ -1268,7 +1268,7 @@ float musgrave_hybrid_multi_fractal(const float4 co,
const float gain)
{
float4 p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
float value = perlin_signed(p) + offset;
@ -1305,10 +1305,10 @@ float musgrave_ridged_multi_fractal(const float4 co,
const float gain)
{
float4 p = co;
const float pwHL = powf(lacunarity, -H);
const float pwHL = std::pow(lacunarity, -H);
float pwr = pwHL;
float signal = offset - fabsf(perlin_signed(p));
float signal = offset - std::abs(perlin_signed(p));
signal *= signal;
float value = signal;
float weight = 1.0f;
@ -1318,7 +1318,7 @@ float musgrave_ridged_multi_fractal(const float4 co,
for (int i = 1; i < (int)octaves; i++) {
p *= lacunarity;
weight = CLAMPIS(signal * gain, 0.0f, 1.0f);
signal = offset - fabsf(perlin_signed(p));
signal = offset - std::abs(perlin_signed(p));
signal *= signal;
signal *= weight;
value += signal * pwr;
@ -1362,7 +1362,7 @@ enum {
BLI_INLINE float voronoi_distance(const float a, const float b)
{
return fabsf(b - a);
return std::abs(b - a);
}
void voronoi_f1(
@ -1491,10 +1491,10 @@ void voronoi_distance_to_edge(const float w, const float randomness, float *r_di
const float midPointPosition = hash_float_to_float(cellPosition) * randomness;
const float leftPointPosition = -1.0f + hash_float_to_float(cellPosition - 1.0f) * randomness;
const float rightPointPosition = 1.0f + hash_float_to_float(cellPosition + 1.0f) * randomness;
const float distanceToMidLeft = fabsf((midPointPosition + leftPointPosition) / 2.0f -
localPosition);
const float distanceToMidRight = fabsf((midPointPosition + rightPointPosition) / 2.0f -
localPosition);
const float distanceToMidLeft = std::abs((midPointPosition + leftPointPosition) / 2.0f -
localPosition);
const float distanceToMidRight = std::abs((midPointPosition + rightPointPosition) / 2.0f -
localPosition);
*r_distance = std::min(distanceToMidLeft, distanceToMidRight);
}
@ -1511,7 +1511,7 @@ void voronoi_n_sphere_radius(const float w, const float randomness, float *r_rad
const float cellOffset = i;
const float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * randomness;
const float distanceToPoint = fabsf(pointPosition - localPosition);
const float distanceToPoint = std::abs(pointPosition - localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
@ -1528,13 +1528,13 @@ void voronoi_n_sphere_radius(const float w, const float randomness, float *r_rad
const float cellOffset = i + closestPointOffset;
const float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * randomness;
const float distanceToPoint = fabsf(closestPoint - pointPosition);
const float distanceToPoint = std::abs(closestPoint - pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
*r_radius = fabsf(closestPointToClosestPoint - closestPoint) / 2.0f;
*r_radius = std::abs(closestPointToClosestPoint - closestPoint) / 2.0f;
}
/* **** 2D Voronoi **** */
@ -1548,12 +1548,13 @@ static float voronoi_distance(const float2 a,
case NOISE_SHD_VORONOI_EUCLIDEAN:
return math::distance(a, b);
case NOISE_SHD_VORONOI_MANHATTAN:
return fabsf(a.x - b.x) + fabsf(a.y - b.y);
return std::abs(a.x - b.x) + std::abs(a.y - b.y);
case NOISE_SHD_VORONOI_CHEBYCHEV:
return std::max(fabsf(a.x - b.x), fabsf(a.y - b.y));
return std::max(std::abs(a.x - b.x), std::abs(a.y - b.y));
case NOISE_SHD_VORONOI_MINKOWSKI:
return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent),
1.0f / exponent);
return std::pow(std::pow(std::abs(a.x - b.x), exponent) +
std::pow(std::abs(a.y - b.y), exponent),
1.0f / exponent);
default:
BLI_assert_unreachable();
break;
@ -1712,7 +1713,7 @@ void voronoi_distance_to_edge(const float2 coord, const float randomness, float
const float2 vectorToPoint = cellOffset +
hash_float_to_float2(cellPosition + cellOffset) * randomness -
localPosition;
const float distanceToPoint = dot_v2v2(vectorToPoint, vectorToPoint);
const float distanceToPoint = math::dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
@ -1728,9 +1729,9 @@ void voronoi_distance_to_edge(const float2 coord, const float randomness, float
hash_float_to_float2(cellPosition + cellOffset) * randomness -
localPosition;
const float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot_v2v2(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
const float distanceToEdge = dot_v2v2((vectorToClosest + vectorToPoint) / 2.0f,
math::normalize(perpendicularToEdge));
if (math::dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
const float distanceToEdge = math::dot((vectorToClosest + vectorToPoint) / 2.0f,
math::normalize(perpendicularToEdge));
minDistance = std::min(minDistance, distanceToEdge);
}
}
@ -1791,13 +1792,14 @@ static float voronoi_distance(const float3 a,
case NOISE_SHD_VORONOI_EUCLIDEAN:
return math::distance(a, b);
case NOISE_SHD_VORONOI_MANHATTAN:
return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z);
return std::abs(a.x - b.x) + std::abs(a.y - b.y) + std::abs(a.z - b.z);
case NOISE_SHD_VORONOI_CHEBYCHEV:
return std::max(fabsf(a.x - b.x), std::max(fabsf(a.y - b.y), fabsf(a.z - b.z)));
return std::max(std::abs(a.x - b.x), std::max(std::abs(a.y - b.y), std::abs(a.z - b.z)));
case NOISE_SHD_VORONOI_MINKOWSKI:
return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
powf(fabsf(a.z - b.z), exponent),
1.0f / exponent);
return std::pow(std::pow(std::abs(a.x - b.x), exponent) +
std::pow(std::abs(a.y - b.y), exponent) +
std::pow(std::abs(a.z - b.z), exponent),
1.0f / exponent);
default:
BLI_assert_unreachable();
break;
@ -1965,7 +1967,7 @@ void voronoi_distance_to_edge(const float3 coord, const float randomness, float
const float3 vectorToPoint = cellOffset +
hash_float_to_float3(cellPosition + cellOffset) * randomness -
localPosition;
const float distanceToPoint = dot_v3v3(vectorToPoint, vectorToPoint);
const float distanceToPoint = math::dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
@ -1983,9 +1985,9 @@ void voronoi_distance_to_edge(const float3 coord, const float randomness, float
hash_float_to_float3(cellPosition + cellOffset) * randomness -
localPosition;
const float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot_v3v3(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
const float distanceToEdge = dot_v3v3((vectorToClosest + vectorToPoint) / 2.0f,
math::normalize(perpendicularToEdge));
if (math::dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
const float distanceToEdge = math::dot((vectorToClosest + vectorToPoint) / 2.0f,
math::normalize(perpendicularToEdge));
minDistance = std::min(minDistance, distanceToEdge);
}
}
@ -2051,14 +2053,16 @@ static float voronoi_distance(const float4 a,
case NOISE_SHD_VORONOI_EUCLIDEAN:
return math::distance(a, b);
case NOISE_SHD_VORONOI_MANHATTAN:
return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z) + fabsf(a.w - b.w);
return std::abs(a.x - b.x) + std::abs(a.y - b.y) + std::abs(a.z - b.z) + std::abs(a.w - b.w);
case NOISE_SHD_VORONOI_CHEBYCHEV:
return std::max(fabsf(a.x - b.x),
std::max(fabsf(a.y - b.y), std::max(fabsf(a.z - b.z), fabsf(a.w - b.w))));
return std::max(
std::abs(a.x - b.x),
std::max(std::abs(a.y - b.y), std::max(std::abs(a.z - b.z), std::abs(a.w - b.w))));
case NOISE_SHD_VORONOI_MINKOWSKI:
return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
powf(fabsf(a.z - b.z), exponent) + powf(fabsf(a.w - b.w), exponent),
1.0f / exponent);
return std::pow(
std::pow(std::abs(a.x - b.x), exponent) + std::pow(std::abs(a.y - b.y), exponent) +
std::pow(std::abs(a.z - b.z), exponent) + std::pow(std::abs(a.w - b.w), exponent),
1.0f / exponent);
default:
BLI_assert_unreachable();
break;
@ -2237,7 +2241,7 @@ void voronoi_distance_to_edge(const float4 coord, const float randomness, float
hash_float_to_float4(cellPosition + cellOffset) *
randomness -
localPosition;
const float distanceToPoint = dot_v4v4(vectorToPoint, vectorToPoint);
const float distanceToPoint = math::dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
@ -2258,9 +2262,9 @@ void voronoi_distance_to_edge(const float4 coord, const float randomness, float
randomness -
localPosition;
const float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot_v4v4(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
const float distanceToEdge = dot_v4v4((vectorToClosest + vectorToPoint) / 2.0f,
math::normalize(perpendicularToEdge));
if (math::dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
const float distanceToEdge = math::dot((vectorToClosest + vectorToPoint) / 2.0f,
math::normalize(perpendicularToEdge));
minDistance = std::min(minDistance, distanceToEdge);
}
}

View File

@ -3,7 +3,7 @@
/** \file
* \ingroup bli
* Windows-posix compatibility layer, windows-specific functions.
* WIN32-POSIX compatibility layer, MS-Windows-specific functions.
*/
#ifdef WIN32

View File

@ -0,0 +1,57 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_math_base.hh"
#include "BLI_array.hh"
#include "BLI_bounds.hh"
namespace blender::tests {
TEST(bounds, Empty)
{
Span<float2> empty_span{};
EXPECT_TRUE(empty_span.is_empty());
auto result = bounds::min_max(empty_span);
EXPECT_EQ(result, std::nullopt);
}
TEST(bounds, MinMax)
{
Array<float2> data = {float2(0, 1), float2(3, -1), float2(0, -2), float2(-1, 1)};
auto result = bounds::min_max(data.as_span());
EXPECT_EQ(result->min, float2(-1, -2));
EXPECT_EQ(result->max, float2(3, 1));
}
TEST(bounds, MinMaxFloat)
{
Array<float> data = {1.0f, 3.0f, 0.0f, -1.0f};
auto result = bounds::min_max(data.as_span());
EXPECT_EQ(result->min, -1.0f);
EXPECT_EQ(result->max, 3.0f);
}
TEST(bounds, MinMaxRadii)
{
Array<int2> data = {int2(0, 1), int2(3, -1), int2(0, -2), int2(-1, 1)};
Array<int> radii = {5, 1, 1, 4};
auto result = bounds::min_max_with_radii(data.as_span(), radii.as_span());
EXPECT_EQ(result->min, int2(-5, -4));
EXPECT_EQ(result->max, int2(5, 6));
}
TEST(bounds, Large)
{
Array<int2> data(10000);
for (const int64_t i : data.index_range()) {
data[i] = int2(i, i);
}
auto result = bounds::min_max(data.as_span());
EXPECT_EQ(result->min, int2(0, 0));
EXPECT_EQ(result->max, int2(9999, 9999));
}
} // namespace blender::tests

View File

@ -3,6 +3,10 @@
#include "testing/testing.h"
#include "BLI_math.h"
#include "BLI_math_base.hh"
#include "BLI_math_vector.hh"
namespace blender::tests {
/* In tests below, when we are using -1.0f as max_diff value, we actually turn the function into a
* pure-ULP one. */
@ -131,3 +135,20 @@ TEST(math_base, FloorPowerOf10)
EXPECT_NEAR(floor_power_of_10(100.1f), 100.0f, 1e-4f);
EXPECT_NEAR(floor_power_of_10(99.9f), 10.0f, 1e-4f);
}
TEST(math_base, MinVectorAndFloat)
{
EXPECT_EQ(math::min(1.0f, 2.0f), 1.0f);
}
TEST(math_base, ClampInt)
{
EXPECT_EQ(math::clamp(111, -50, 101), 101);
}
TEST(math_base, Midpoint)
{
EXPECT_NEAR(math::midpoint(100.0f, 200.0f), 150.0f, 1e-4f);
}
} // namespace blender::tests

View File

@ -5,7 +5,7 @@
/** \file
* \ingroup blenloader
* External writefile function prototypes.
* External write-file function prototypes.
*/
#include "BLI_filereader.h"

View File

@ -102,7 +102,7 @@ struct IMAGE_InstanceData {
short requested_view = image_user ? image_user->multi_index : 0;
/* There is room for 2 multiview textures. When a higher number is requested we should always
* target the first view slot. This is fine as multi view images aren't used together. */
if (requested_view < 2) {
if (requested_view > 1) {
requested_view = 0;
}

View File

@ -254,31 +254,8 @@ void main()
* Morgan McGuire and Kyle Whitson
* http://graphics.cs.williams.edu
*
*
* Copyright (c) Morgan McGuire and Williams College, 2006
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* SPDX-License-Identifier: BSD-2-Clause
* Copyright 2006 Morgan McGuire and Williams College, All rights reserved.
*/
#ifdef BLUR2

View File

@ -1340,8 +1340,9 @@ void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
drw_subdiv_compute_dispatch(cache, shader, 0, dst_offset, cache->num_subdiv_quads);
/* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
/* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. Put
* a barrier on the shader storage as we may use the result in another compute shader. */
GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
/* Cleanup. */
GPU_shader_unbind();
@ -1422,6 +1423,28 @@ void draw_subdiv_finalize_normals(const DRWSubdivCache *cache,
GPU_shader_unbind();
}
void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache,
GPUVertBuf *src_custom_normals,
GPUVertBuf *pos_nor)
{
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_FINALIZE, "#define CUSTOM_NORMALS");
GPU_shader_bind(shader);
GPU_vertbuf_bind_as_ssbo(src_custom_normals, 0);
/* outputPosNor is bound at index 2 in the base shader. */
GPU_vertbuf_bind_as_ssbo(pos_nor, 2);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
/* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array.
* We also need it for subsequent compute shaders, so a barrier on the shader storage is also
* needed. */
GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
/* Cleanup. */
GPU_shader_unbind();
}
void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
GPUIndexBuf *subdiv_tris,
const int material_count)
@ -1762,9 +1785,9 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
const bool use_subsurf_fdots,
const bool UNUSED(use_subsurf_fdots),
const ToolSettings *ts,
const bool use_hide,
const bool UNUSED(use_hide),
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob);
@ -1813,6 +1836,11 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
/* We can only evaluate limit normals if the patches are adaptive. */
draw_cache->do_limit_normals = settings.is_adaptive;
draw_cache->use_custom_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) &&
(mesh_eval->flag & ME_AUTOSMOOTH) &&
CustomData_has_layer(&mesh_eval->ldata,
CD_CUSTOMLOOPNORMAL);
if (DRW_ibo_requested(mbc->buff.ibo.tris)) {
draw_subdiv_cache_ensure_mat_offsets(draw_cache, mesh_eval, batch_cache->mat_len);
}

View File

@ -52,6 +52,7 @@ typedef struct DRWSubdivCache {
struct Subdiv *subdiv;
bool optimal_display;
bool do_limit_normals;
bool use_custom_loop_normals;
/* Coordinates used to evaluate patches for UVs, positions, and normals. */
struct GPUVertBuf *patch_coords;
@ -171,6 +172,10 @@ void draw_subdiv_finalize_normals(const DRWSubdivCache *cache,
struct GPUVertBuf *subdiv_loop_subdiv_vert_index,
struct GPUVertBuf *pos_nor);
void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache,
GPUVertBuf *src_custom_normals,
GPUVertBuf *pos_nor);
void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
struct GPUVertBuf *pos_nor,
bool do_limit_normals);

View File

@ -200,6 +200,16 @@ static GPUVertFormat *get_normals_format()
return &format;
}
static GPUVertFormat *get_custom_normals_format()
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
GPU_vertformat_alias_add(&format, "lnor");
}
return &format;
}
static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
@ -207,7 +217,8 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
void *UNUSED(data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
const bool do_limit_normals = subdiv_cache->do_limit_normals;
const bool do_limit_normals = subdiv_cache->do_limit_normals &&
!subdiv_cache->use_custom_loop_normals;
/* Initialize the vertex buffer, it was already allocated. */
GPU_vertbuf_init_build_on_device(
@ -215,7 +226,31 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
draw_subdiv_extract_pos_nor(subdiv_cache, vbo, do_limit_normals);
if (!do_limit_normals) {
if (subdiv_cache->use_custom_loop_normals) {
Mesh *coarse_mesh = subdiv_cache->mesh;
float(*lnors)[3] = static_cast<float(*)[3]>(
CustomData_get_layer(&coarse_mesh->ldata, CD_NORMAL));
BLI_assert(lnors != NULL);
GPUVertBuf *src_custom_normals = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format(src_custom_normals, get_custom_normals_format());
GPU_vertbuf_data_alloc(src_custom_normals, coarse_mesh->totloop);
memcpy(
GPU_vertbuf_get_data(src_custom_normals), lnors, sizeof(float[3]) * coarse_mesh->totloop);
GPUVertBuf *dst_custom_normals = GPU_vertbuf_calloc();
GPU_vertbuf_init_build_on_device(
dst_custom_normals, get_custom_normals_format(), subdiv_cache->num_subdiv_loops);
draw_subdiv_interp_custom_data(subdiv_cache, src_custom_normals, dst_custom_normals, 3, 0);
draw_subdiv_finalize_custom_normals(subdiv_cache, dst_custom_normals, vbo);
GPU_vertbuf_discard(src_custom_normals);
GPU_vertbuf_discard(dst_custom_normals);
}
else if (!do_limit_normals) {
/* We cannot evaluate vertex normals using the limit surface, so compute them manually. */
GPUVertBuf *subdiv_loop_subdiv_vert_index = draw_subdiv_build_origindex_buffer(
subdiv_cache->subdiv_loop_subdiv_vert_index, subdiv_cache->num_subdiv_loops);

View File

@ -185,7 +185,7 @@ void main()
}
else {
/* Interpolate the src data for the center. */
uint loop_end = loop_start + number_of_vertices - 1;
uint loop_end = loop_start + number_of_vertices;
Vertex center_value;
clear(center_value);
@ -202,7 +202,7 @@ void main()
uint prev_coarse_corner = (current_coarse_corner + number_of_vertices - 1) %
number_of_vertices;
v0 = read_vertex(loop_start);
v0 = read_vertex(loop_start + current_coarse_corner);
v1 = average(v0, read_vertex(loop_start + next_coarse_corner));
v3 = average(v0, read_vertex(loop_start + prev_coarse_corner));

View File

@ -1,6 +1,18 @@
/* To be compile with common_subdiv_lib.glsl */
#ifdef CUSTOM_NORMALS
struct CustomNormal {
float x;
float y;
float z;
};
layout(std430, binding = 0) readonly buffer inputNormals
{
CustomNormal custom_normals[];
};
#else
layout(std430, binding = 0) readonly buffer inputNormals
{
vec3 vertex_normals[];
@ -10,6 +22,7 @@ layout(std430, binding = 1) readonly buffer inputSubdivVertLoopMap
{
uint vert_loop_map[];
};
#endif
layout(std430, binding = 2) buffer outputPosNor
{
@ -26,9 +39,17 @@ void main()
uint start_loop_index = quad_index * 4;
#ifdef CUSTOM_NORMALS
for (int i = 0; i < 4; i++) {
CustomNormal custom_normal = custom_normals[start_loop_index + i];
vec3 nor = vec3(custom_normal.x, custom_normal.y, custom_normal.z);
set_vertex_nor(pos_nor[start_loop_index + i], normalize(nor));
}
#else
for (int i = 0; i < 4; i++) {
uint subdiv_vert_index = vert_loop_map[start_loop_index + i];
vec3 nor = vertex_normals[subdiv_vert_index];
set_vertex_nor(pos_nor[start_loop_index + i], nor);
}
#endif
}

View File

@ -9,6 +9,7 @@ if(WITH_BLENDER)
add_subdirectory(armature)
add_subdirectory(asset)
add_subdirectory(curve)
add_subdirectory(curves)
add_subdirectory(geometry)
add_subdirectory(gizmo_library)
add_subdirectory(gpencil)

View File

@ -574,6 +574,14 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
cdd->vc.scene = CTX_data_scene(C);
cdd->vc.view_layer = CTX_data_view_layer(C);
cdd->vc.obedit = CTX_data_edit_object(C);
/* Using an empty stroke complicates logic later,
* it's simplest to disallow early on (see: T94085). */
if (RNA_collection_is_empty(op->ptr, "stroke")) {
MEM_freeN(cdd);
BKE_report(op->reports, RPT_ERROR, "The \"stroke\" cannot be empty");
return false;
}
}
op->customdata = cdd;

View File

@ -0,0 +1,24 @@
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
../include
../../blenkernel
../../blenlib
../../blentranslation
../../depsgraph
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
)
set(SRC
intern/curves_ops.cc
)
set(LIB
bf_blenkernel
bf_blenlib
)
blender_add_lib(bf_editor_curves "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@ -0,0 +1,70 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edcurves
*/
#include "BLI_utildefines.h"
#include "ED_curves.h"
#include "ED_object.h"
#include "WM_api.h"
#include "WM_types.h"
#include "BKE_context.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_types.h"
static bool curves_sculptmode_toggle_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
if (ob == nullptr) {
return false;
}
if (ob->type != OB_CURVES) {
return false;
}
return true;
}
static int curves_sculptmode_toggle_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
const bool is_mode_set = ob->mode == OB_MODE_SCULPT_CURVES;
if (is_mode_set) {
if (!ED_object_mode_compat_set(C, ob, OB_MODE_SCULPT_CURVES, op->reports)) {
return OPERATOR_CANCELLED;
}
}
if (is_mode_set) {
ob->mode = OB_MODE_OBJECT;
}
else {
ob->mode = OB_MODE_SCULPT_CURVES;
}
WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);
return OPERATOR_CANCELLED;
}
static void CURVES_OT_sculptmode_toggle(wmOperatorType *ot)
{
ot->name = "Curve Sculpt Mode Toggle";
ot->idname = "CURVES_OT_sculptmode_toggle";
ot->description = "Enter/Exit sculpt mode for curves";
ot->exec = curves_sculptmode_toggle_exec;
ot->poll = curves_sculptmode_toggle_poll;
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
void ED_operatortypes_curves()
{
WM_operatortype_append(CURVES_OT_sculptmode_toggle);
}

View File

@ -1811,7 +1811,7 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *
gso->mval[1] = mouse[1] = (int)(mousef[1]);
/* If the mouse/pen has not moved, no reason to continue. This also avoid a small
* drift due precision acumulation errors. */
* drift due precision accumulation errors. */
if ((gso->mval[0] == gso->mval_prev[0]) && (gso->mval[1] == gso->mval_prev[1])) {
return;
}

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup editors
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void ED_operatortypes_curves(void);
#ifdef __cplusplus
}
#endif

View File

@ -9,6 +9,7 @@
#include "BLI_compiler_attrs.h"
#include "DNA_object_enums.h"
#include "DNA_userdef_enums.h"
#ifdef __cplusplus
extern "C" {

View File

@ -15,9 +15,9 @@ extern "C" {
#endif
struct GPUBatch;
struct IDRemapper;
struct Main;
struct bContext;
struct IDRemapper;
/* ed_util.c */

View File

@ -97,8 +97,7 @@ bool uvedit_face_select_test(const struct Scene *scene, struct BMFace *efa, int
bool uvedit_edge_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset);
bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset);
/* uv face */
void uvedit_face_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
void uvedit_face_select_set_with_sticky(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
bool select,
@ -120,8 +119,7 @@ void uvedit_face_select_disable(const struct Scene *scene,
struct BMFace *efa,
int cd_loop_uv_offset);
/* uv edge */
void uvedit_edge_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
void uvedit_edge_select_set_with_sticky(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
bool select,
@ -143,8 +141,7 @@ void uvedit_edge_select_disable(const struct Scene *scene,
struct BMLoop *l,
int cd_loop_uv_offset);
/* uv vert */
void uvedit_uv_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
void uvedit_uv_select_set_with_sticky(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
bool select,

View File

@ -2354,6 +2354,7 @@ int UI_icon_from_object_mode(const int mode)
return ICON_EDITMODE_HLT;
case OB_MODE_SCULPT:
case OB_MODE_SCULPT_GPENCIL:
case OB_MODE_SCULPT_CURVES:
return ICON_SCULPTMODE_HLT;
case OB_MODE_VERTEX_PAINT:
case OB_MODE_VERTEX_GPENCIL:

View File

@ -94,6 +94,9 @@ static const char *object_mode_op_string(eObjectMode mode)
if (mode == OB_MODE_VERTEX_GPENCIL) {
return "GPENCIL_OT_vertexmode_toggle";
}
if (mode == OB_MODE_SCULPT_CURVES) {
return "CURVES_OT_sculptmode_toggle";
}
return NULL;
}
@ -139,6 +142,11 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
return true;
}
break;
case OB_CURVES:
if (mode & (OB_MODE_SCULPT_CURVES)) {
return true;
}
break;
}
return false;

View File

@ -6059,7 +6059,8 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
view_data = IDP_GetPropertyTypeFromGroup(idgroup, PROJ_VIEW_DATA_ID, IDP_ARRAY);
/* type check to make sure its ok */
if (view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT) {
if (view_data != NULL &&
(view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT)) {
BKE_report(op->reports, RPT_ERROR, "Image project data invalid");
return OPERATOR_CANCELLED;
}

View File

@ -28,6 +28,7 @@
#include "ED_asset.h"
#include "ED_clip.h"
#include "ED_curve.h"
#include "ED_curves.h"
#include "ED_fileselect.h"
#include "ED_geometry.h"
#include "ED_gizmo_library.h"
@ -100,6 +101,7 @@ void ED_spacetypes_init(void)
ED_operatortypes_paint();
ED_operatortypes_physics();
ED_operatortypes_curve();
ED_operatortypes_curves();
ED_operatortypes_armature();
ED_operatortypes_marker();
ED_operatortypes_metaball();

View File

@ -186,7 +186,7 @@ static int open_exec(bContext *C, wmOperator *op)
MovieClip *clip = NULL;
char str[FILE_MAX];
if (RNA_collection_length(op->ptr, "files")) {
if (!RNA_collection_is_empty(op->ptr, "files")) {
PointerRNA fileptr;
PropertyRNA *prop;
char dir_only[FILE_MAX], file_only[FILE_MAX];

View File

@ -7,7 +7,8 @@
#pragma once
#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "BLI_vector.hh"
#include "BKE_node.h"

View File

@ -747,7 +747,8 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
RNA_enum_set(op->ptr, "fit_method", SEQ_tool_settings_fit_method_get(scene));
/* This is for drag and drop. */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
if ((RNA_struct_property_is_set(op->ptr, "files") &&
!RNA_collection_is_empty(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath")) {
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_MOVIE);
return sequencer_add_movie_strip_exec(C, op);
@ -901,7 +902,8 @@ static int sequencer_add_sound_strip_invoke(bContext *C,
const wmEvent *UNUSED(event))
{
/* This is for drag and drop. */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
if ((RNA_struct_property_is_set(op->ptr, "files") &&
!RNA_collection_is_empty(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath")) {
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_SOUND_RAM);
return sequencer_add_sound_strip_exec(C, op);
@ -1094,7 +1096,7 @@ static int sequencer_add_image_strip_invoke(bContext *C,
RNA_enum_set(op->ptr, "fit_method", SEQ_tool_settings_fit_method_get(scene));
/* Name set already by drag and drop. */
if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) {
if (RNA_struct_property_is_set(op->ptr, "files") && !RNA_collection_is_empty(op->ptr, "files")) {
sequencer_generic_invoke_xy__internal(
C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE);
return sequencer_add_image_strip_exec(C, op);

View File

@ -255,6 +255,23 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
}
}
}
else if (data.type().is<std::string>()) {
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
ICON_NONE,
data.get<std::string>(real_index).c_str(),
params.xmin,
params.ymin,
params.width,
params.height,
nullptr,
0,
0,
0,
0,
nullptr);
}
}
void draw_float_vector(const CellDrawParams &params, const Span<float> values) const

View File

@ -14,15 +14,15 @@
#define V3D_OP_TRACKBALLSIZE (1.1f)
struct ARegion;
struct bContext;
struct Depsgraph;
struct Dial;
struct Main;
struct rcti;
struct RegionView3D;
struct Scene;
struct ScrArea;
struct View3D;
struct bContext;
struct rcti;
struct wmEvent;
struct wmOperator;

View File

@ -39,6 +39,7 @@ set(SRC
../include/ED_buttons.h
../include/ED_clip.h
../include/ED_curve.h
../include/ED_curves.h
../include/ED_datafiles.h
../include/ED_file_indexer.h
../include/ED_fileselect.h

View File

@ -1572,7 +1572,7 @@ static int uv_reveal_exec(bContext *C, wmOperator *op)
const ToolSettings *ts = scene->toolsettings;
const bool use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
const bool stickymode = sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
const bool stickymode = sima ? (ts->uv_sticky != SI_STICKY_DISABLE) : 1;
const bool select = RNA_boolean_get(op->ptr, "select");
uint objects_len = 0;

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