Merge branch 'master' into asset-browser-grid-view
This commit is contained in:
commit
91853d95a9
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
|
|
|
@ -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.
|
||||
#
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ¶ms, 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 ¶ms)
|
||||
{
|
||||
/* 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 ¶ms)
|
||||
{
|
||||
/* 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
|
|
@ -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 ¶ms, 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 ¶ms) 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 ¶ms);
|
||||
|
||||
/* 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
# ifdef WITH_HIP_DYNLOAD
|
||||
# include "hipew.h"
|
||||
# else
|
||||
# include "util/opengl.h"
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
|
@ -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__*/
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct BoundBox;
|
||||
struct Curves;
|
||||
struct CustomDataLayer;
|
||||
struct Depsgraph;
|
||||
struct Curves;
|
||||
struct Main;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include "DNA_image_types.h"
|
||||
|
||||
extern "C" {
|
||||
struct PartialUpdateUser;
|
||||
struct PartialUpdateRegister;
|
||||
struct PartialUpdateUser;
|
||||
}
|
||||
|
||||
namespace blender::bke::image {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
*/
|
||||
|
||||
struct ID;
|
||||
struct ImageUser;
|
||||
struct Main;
|
||||
struct bNode;
|
||||
struct bNodeLink;
|
||||
struct bNodeSocket;
|
||||
struct bNodeTree;
|
||||
struct ImageUser;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
|
@ -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(
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "BKE_tracking.h"
|
||||
#include "BLI_math_vec_types.hh"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
namespace blender {
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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
|
|
@ -6,7 +6,7 @@
|
|||
* \ingroup bli
|
||||
*/
|
||||
|
||||
#include "BLI_math_vec_types.hh"
|
||||
#include "BLI_math_vector.hh"
|
||||
|
||||
#ifdef WITH_GMP
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/** \file
|
||||
* \ingroup bli
|
||||
* Windows-posix compatibility layer, windows-specific functions.
|
||||
* WIN32-POSIX compatibility layer, MS-Windows-specific functions.
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
/** \file
|
||||
* \ingroup blenloader
|
||||
* External writefile function prototypes.
|
||||
* External write-file function prototypes.
|
||||
*/
|
||||
|
||||
#include "BLI_filereader.h"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}")
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "DNA_object_enums.h"
|
||||
#include "DNA_userdef_enums.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -15,9 +15,9 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct GPUBatch;
|
||||
struct IDRemapper;
|
||||
struct Main;
|
||||
struct bContext;
|
||||
struct IDRemapper;
|
||||
|
||||
/* ed_util.c */
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ¶ms, const Span<float> values) const
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue