upgraded to ocio v2
This commit is contained in:
+1
-1
@@ -41,7 +41,7 @@ endif()
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
find_package(OpenColorIO REQUIRED)
|
||||
find_package(OpenColorIO 2.0.0 REQUIRED)
|
||||
|
||||
find_package(OpenImageIO 1.6 REQUIRED)
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ OLIVE_NAMESPACE_ENTER
|
||||
FFmpegDecoder::FFmpegDecoder() :
|
||||
scale_ctx_(nullptr),
|
||||
scale_divider_(0),
|
||||
pool_(QThread::idealThreadCount()),
|
||||
pool_(QThread::idealThreadCount()*2),
|
||||
is_working_(false),
|
||||
cache_at_zero_(false),
|
||||
cache_at_eof_(false)
|
||||
@@ -120,21 +120,20 @@ FramePtr FFmpegDecoder::RetrieveStillImage(const rational &timecode, const int &
|
||||
|
||||
if (ret >= 0) {
|
||||
// Create frame to return
|
||||
FramePtr copy = Frame::Create();
|
||||
copy->set_video_params(VideoParams(frame->width,
|
||||
output_frame = Frame::Create();
|
||||
output_frame->set_video_params(VideoParams(frame->width,
|
||||
frame->height,
|
||||
native_pix_fmt_,
|
||||
std::static_pointer_cast<VideoStream>(stream())->pixel_aspect_ratio(),
|
||||
std::static_pointer_cast<VideoStream>(stream())->interlacing(),
|
||||
divider));
|
||||
copy->set_timestamp(timecode);
|
||||
copy->allocate();
|
||||
output_frame->set_timestamp(timecode);
|
||||
output_frame->allocate();
|
||||
|
||||
uint8_t* copy_data = reinterpret_cast<uint8_t*>(copy->data());
|
||||
int copy_linesize = copy->linesize_bytes();
|
||||
FFmpegFrameToNativeBuffer(frame->data, frame->linesize, ©_data, ©_linesize);
|
||||
uint8_t* copy_data = reinterpret_cast<uint8_t*>(output_frame->data());
|
||||
int copy_linesize = output_frame->linesize_bytes();
|
||||
|
||||
return copy;
|
||||
FFmpegBufferToNativeBuffer(frame->data, frame->linesize, ©_data, ©_linesize);
|
||||
} else {
|
||||
qWarning() << "Failed to retrieve still image from decoder";
|
||||
}
|
||||
@@ -151,6 +150,11 @@ FramePtr FFmpegDecoder::RetrieveVideoInternal(const rational &timecode, const in
|
||||
{
|
||||
VideoStreamPtr vs = std::static_pointer_cast<VideoStream>(stream());
|
||||
|
||||
if (scale_divider_ != divider) {
|
||||
FreeScaler();
|
||||
InitScaler(divider);
|
||||
}
|
||||
|
||||
if (vs->video_type() == VideoStream::kVideoTypeStill
|
||||
|| vs->video_type() == VideoStream::kVideoTypeImageSequence) {
|
||||
|
||||
@@ -158,8 +162,6 @@ FramePtr FFmpegDecoder::RetrieveVideoInternal(const rational &timecode, const in
|
||||
|
||||
} else {
|
||||
|
||||
FFmpegFramePool::ElementPtr return_frame = nullptr;
|
||||
|
||||
int64_t target_ts = vs->get_time_in_timebase_units(timecode);
|
||||
|
||||
int divided_width = VideoParams::GetScaledDimension(vs->width(), divider);
|
||||
@@ -171,12 +173,10 @@ FramePtr FFmpegDecoder::RetrieveVideoInternal(const rational &timecode, const in
|
||||
|
||||
// Set new frame pool parameters
|
||||
pool_.SetParameters(divided_width, divided_height, native_pix_fmt_);
|
||||
} else {
|
||||
return_frame = GetFrameFromCache(target_ts);
|
||||
}
|
||||
|
||||
// Retrieve frame
|
||||
return_frame = RetrieveFrame(target_ts, divider);
|
||||
FFmpegFramePool::ElementPtr return_frame = RetrieveFrame(target_ts, divider);
|
||||
|
||||
// We found the frame, we'll return a copy
|
||||
if (return_frame) {
|
||||
@@ -563,7 +563,7 @@ uint64_t FFmpegDecoder::ValidateChannelLayout(AVStream* stream)
|
||||
return av_get_default_channel_layout(stream->codecpar->channels);
|
||||
}
|
||||
|
||||
void FFmpegDecoder::FFmpegFrameToNativeBuffer(uint8_t **input_data, int *input_linesize, uint8_t** output_buffer, int* output_linesize)
|
||||
void FFmpegDecoder::FFmpegBufferToNativeBuffer(uint8_t **input_data, int *input_linesize, uint8_t** output_buffer, int* output_linesize)
|
||||
{
|
||||
sws_scale(scale_ctx_,
|
||||
input_data,
|
||||
@@ -640,17 +640,12 @@ void FFmpegDecoder::ClearFrameCache()
|
||||
|
||||
FFmpegFramePool::ElementPtr FFmpegDecoder::RetrieveFrame(const int64_t& target_ts, int divider)
|
||||
{
|
||||
if (scale_divider_ != divider) {
|
||||
FreeScaler();
|
||||
InitScaler(divider);
|
||||
}
|
||||
|
||||
int64_t seek_ts = target_ts;
|
||||
bool still_seeking = false;
|
||||
|
||||
// If the frame wasn't in the frame cache, see if this frame cache is too old to use
|
||||
if (cached_frames_.isEmpty()
|
||||
|| (target_ts < cached_frames_.first()->timestamp() && target_ts > cached_frames_.last()->timestamp() + 2*second_ts_)) {
|
||||
|| (target_ts < cached_frames_.first()->timestamp() || target_ts > cached_frames_.last()->timestamp() + 2*second_ts_)) {
|
||||
ClearFrameCache();
|
||||
|
||||
instance_.Seek(seek_ts);
|
||||
@@ -659,6 +654,12 @@ FFmpegFramePool::ElementPtr FFmpegDecoder::RetrieveFrame(const int64_t& target_t
|
||||
}
|
||||
|
||||
still_seeking = true;
|
||||
} else {
|
||||
// Search cache for frame
|
||||
FFmpegFramePool::ElementPtr cached_frame = GetFrameFromCache(target_ts);
|
||||
if (cached_frame) {
|
||||
return cached_frame;
|
||||
}
|
||||
}
|
||||
|
||||
int ret;
|
||||
@@ -727,9 +728,9 @@ FFmpegFramePool::ElementPtr FFmpegDecoder::RetrieveFrame(const int64_t& target_t
|
||||
}
|
||||
|
||||
// Store in queue, converting to native format
|
||||
int destination_linesize = Frame::generate_linesize_bytes(VideoParams::GetScaledDimension(instance_.avstream()->codecpar->width, divider), native_pix_fmt_);
|
||||
uint8_t* destination_data = cached->data();
|
||||
FFmpegFrameToNativeBuffer(working_frame->data, working_frame->linesize, &destination_data, &destination_linesize);
|
||||
int destination_linesize = Frame::generate_linesize_bytes(VideoParams::GetScaledDimension(instance_.avstream()->codecpar->width, divider), native_pix_fmt_);
|
||||
FFmpegBufferToNativeBuffer(working_frame->data, working_frame->linesize, &destination_data, &destination_linesize);
|
||||
|
||||
// Set timestamp so this frame can be identified later
|
||||
cached->set_timestamp(working_frame->pts);
|
||||
|
||||
@@ -130,7 +130,7 @@ private:
|
||||
|
||||
static uint64_t ValidateChannelLayout(AVStream *stream);
|
||||
|
||||
void FFmpegFrameToNativeBuffer(uint8_t** input_data, int* input_linesize, uint8_t **output_buffer, int *output_linesize);
|
||||
void FFmpegBufferToNativeBuffer(uint8_t** input_data, int* input_linesize, uint8_t **output_buffer, int *output_linesize);
|
||||
|
||||
FFmpegFramePool::ElementPtr GetFrameFromCache(const int64_t& t) const;
|
||||
|
||||
|
||||
+7
-5
@@ -45,14 +45,14 @@ void Frame::set_video_params(const VideoParams ¶ms)
|
||||
{
|
||||
params_ = params;
|
||||
|
||||
linesize_ = generate_linesize_bytes(params_.width(), params_.format());
|
||||
linesize_ = generate_linesize_bytes(width(), params_.format());
|
||||
linesize_pixels_ = linesize_ / PixelFormat::BytesPerPixel(params_.format());
|
||||
}
|
||||
|
||||
int Frame::generate_linesize_bytes(int width, PixelFormat::Format format)
|
||||
{
|
||||
// Align to 32 bytes (not sure if this is necessary?)
|
||||
return ((PixelFormat::BytesPerPixel(format) * width) + 31) & ~31;
|
||||
return PixelFormat::BytesPerPixel(format) * ((width + 31) & ~31);
|
||||
}
|
||||
|
||||
Color Frame::get_pixel(int x, int y) const
|
||||
@@ -82,15 +82,17 @@ void Frame::set_pixel(int x, int y, const Color &c)
|
||||
c.toData(data_.data() + byte_offset, video_params().format());
|
||||
}
|
||||
|
||||
void Frame::allocate()
|
||||
bool Frame::allocate()
|
||||
{
|
||||
// Assume this frame is intended to be a video frame
|
||||
if (!params_.is_valid()) {
|
||||
qWarning() << "Tried to allocate a frame with invalid parameters";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
data_.resize(PixelFormat::GetBufferSize(params_.format(), linesize_, params_.height()));
|
||||
data_.resize(PixelFormat::GetBufferSize(params_.format(), linesize_, height()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ public:
|
||||
*
|
||||
* If a memory buffer has been previously allocated without destroying, this function will destroy it.
|
||||
*/
|
||||
void allocate();
|
||||
bool allocate();
|
||||
|
||||
/**
|
||||
* @brief Return whether the frame is allocated or not
|
||||
|
||||
@@ -37,6 +37,7 @@ set(OLIVE_SOURCES
|
||||
common/lerp.h
|
||||
common/memorypool.h
|
||||
common/memorypool.cpp
|
||||
common/ocioutils.h
|
||||
common/qtutils.h
|
||||
common/qtutils.cpp
|
||||
common/range.h
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 Olive Team
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OCIOUTILS_H
|
||||
#define OCIOUTILS_H
|
||||
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OpenColorIO_v2_0dev;
|
||||
|
||||
#endif // OCIOUTILS_H
|
||||
@@ -121,8 +121,6 @@ void Config::SetDefaults()
|
||||
// Online/offline settings
|
||||
SetEntryInternal(QStringLiteral("OnlinePixelFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA32F);
|
||||
SetEntryInternal(QStringLiteral("OfflinePixelFormat"), NodeParam::kInt, PixelFormat::PIX_FMT_RGBA16F);
|
||||
SetEntryInternal(QStringLiteral("OnlineOCIOMethod"), NodeParam::kInt, ColorManager::kOCIOAccurate);
|
||||
SetEntryInternal(QStringLiteral("OfflineOCIOMethod"), NodeParam::kInt, ColorManager::kOCIOFast);
|
||||
}
|
||||
|
||||
void Config::Load()
|
||||
|
||||
@@ -25,9 +25,8 @@
|
||||
#include <QInputDialog>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
|
||||
#include "common/ocioutils.h"
|
||||
#include "core.h"
|
||||
#include "project/item/footage/footage.h"
|
||||
#include "project/project.h"
|
||||
|
||||
@@ -27,10 +27,9 @@
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
|
||||
#include "common/filefunctions.h"
|
||||
#include "common/ocioutils.h"
|
||||
#include "config/config.h"
|
||||
#include "core.h"
|
||||
#include "render/colormanager.h"
|
||||
|
||||
@@ -157,7 +157,7 @@ void AudioPlaybackCache::WriteSilence(const TimeRange &range, qint64 job_time)
|
||||
|
||||
void AudioPlaybackCache::ShiftEvent(const rational &from_in_time, const rational &to_in_time)
|
||||
{
|
||||
if (from_in_time == to_in_time) {
|
||||
if (from_in_time == to_in_time || GetLength().isNull()) {
|
||||
// Nothing to be done
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "openglrenderer.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFloat16>
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
@@ -44,16 +45,6 @@ const QVector<GLfloat> blit_texcoords = {
|
||||
1.0f, 1.0f
|
||||
};
|
||||
|
||||
const QVector<GLfloat> flipped_blit_texcoords = {
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f
|
||||
};
|
||||
|
||||
OpenGLRenderer::OpenGLRenderer(QObject* parent) :
|
||||
Renderer(parent),
|
||||
context_(nullptr)
|
||||
@@ -110,33 +101,11 @@ void OpenGLRenderer::PostInit()
|
||||
|
||||
// Set up framebuffer used for various things
|
||||
functions_->glGenFramebuffers(1, &framebuffer_);
|
||||
|
||||
// Set up vertex array object
|
||||
vao_.create();
|
||||
|
||||
// Set up vertex buffer
|
||||
vert_vbo_.create();
|
||||
vert_vbo_.bind();
|
||||
vert_vbo_.allocate(blit_vertices.constData(), blit_vertices.size() * sizeof(GLfloat));
|
||||
vert_vbo_.release();
|
||||
|
||||
// Set up fragment buffer
|
||||
frag_vbo_.create();
|
||||
frag_vbo_.bind();
|
||||
frag_vbo_.allocate(blit_texcoords.constData(), blit_texcoords.size() * sizeof(GLfloat));
|
||||
frag_vbo_.release();
|
||||
}
|
||||
|
||||
void OpenGLRenderer::Destroy()
|
||||
{
|
||||
if (context_) {
|
||||
// Delete buffers
|
||||
vert_vbo_.destroy();
|
||||
frag_vbo_.destroy();
|
||||
|
||||
// Delete vertex array object
|
||||
vao_.destroy();
|
||||
|
||||
// Delete framebuffer
|
||||
functions_->glDeleteFramebuffers(1, &framebuffer_);
|
||||
|
||||
@@ -181,12 +150,19 @@ QVariant OpenGLRenderer::CreateNativeTexture(VideoParams p, void *data, int line
|
||||
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize);
|
||||
|
||||
GLint current_tex;
|
||||
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex);
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
functions_->glTexImage2D(GL_TEXTURE_2D, 0, GetInternalFormat(p.format()),
|
||||
p.width(), p.height(), 0, GL_RGBA,
|
||||
p.effective_width(), p.effective_height(), 0, GL_RGBA,
|
||||
GetPixelType(p.format()), data);
|
||||
|
||||
functions_->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@@ -215,8 +191,6 @@ QVariant OpenGLRenderer::CreateNativeShader(ShaderCode code)
|
||||
goto error;
|
||||
}
|
||||
|
||||
qDebug() << "Shader created successfully";
|
||||
|
||||
return Node::PtrToValue(program);
|
||||
|
||||
error:
|
||||
@@ -254,13 +228,12 @@ void OpenGLRenderer::UploadToTexture(Texture *texture, void *data, int linesize)
|
||||
|
||||
void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int linesize)
|
||||
{
|
||||
GLuint t = texture->id().value<GLuint>();
|
||||
const VideoParams& p = texture->params();
|
||||
|
||||
GLint current_tex;
|
||||
functions_->glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_tex);
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, t);
|
||||
AttachTextureAsDestination(texture);
|
||||
|
||||
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, linesize);
|
||||
|
||||
@@ -274,6 +247,8 @@ void OpenGLRenderer::DownloadFromTexture(Texture* texture, void *data, int lines
|
||||
|
||||
functions_->glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||
|
||||
DetachTextureAsDestination();
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, current_tex);
|
||||
}
|
||||
|
||||
@@ -315,23 +290,6 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destinat
|
||||
shader->setUniformValue(variable_location, value.data.toFloat());
|
||||
break;
|
||||
case NodeInput::kVec2:
|
||||
/*if (corresponding_input && corresponding_input->IsArray()) {
|
||||
QVector<NodeValue> nv = value.value< QVector<NodeValue> >();
|
||||
QVector<QVector2D> a(nv.size());
|
||||
|
||||
for (int j=0;j<a.size();j++) {
|
||||
a[j] = nv.at(j).data().value<QVector2D>();
|
||||
}
|
||||
|
||||
shader->setUniformValueArray(variable_location, a.constData(), a.size());
|
||||
|
||||
int count_location = shader->uniformLocation(QStringLiteral("%1_count").arg(it.key()));
|
||||
if (count_location > -1) {
|
||||
shader->setUniformValue(count_location, a.size());
|
||||
}
|
||||
} else {
|
||||
|
||||
}*/
|
||||
shader->setUniformValue(variable_location, value.data.value<QVector2D>());
|
||||
break;
|
||||
case NodeInput::kVec3:
|
||||
@@ -349,8 +307,8 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destinat
|
||||
case NodeInput::kColor:
|
||||
{
|
||||
Color color = value.data.value<Color>();
|
||||
|
||||
shader->setUniformValue(variable_location, color.red(), color.green(), color.blue(), color.alpha());
|
||||
shader->setUniformValue(variable_location,
|
||||
color.red(), color.green(), color.blue(), color.alpha());
|
||||
break;
|
||||
}
|
||||
case NodeInput::kBoolean:
|
||||
@@ -423,14 +381,6 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destinat
|
||||
}
|
||||
}
|
||||
|
||||
// Set ove_resolution to the destination to the "logical" resolution of the destination
|
||||
shader->setUniformValue("ove_resolution",
|
||||
static_cast<GLfloat>(destination_params.width()),
|
||||
static_cast<GLfloat>(destination_params.height()));
|
||||
|
||||
// Set the viewport to the "physical" resolution of the destination
|
||||
functions_->glViewport(0, 0, destination_params.effective_width(), destination_params.effective_height());
|
||||
|
||||
// Bind all textures
|
||||
for (int i=0; i<textures_to_bind.size(); i++) {
|
||||
functions_->glActiveTexture(GL_TEXTURE0 + i);
|
||||
@@ -438,10 +388,37 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destinat
|
||||
PrepareInputTexture(job.GetBilinearFiltering());
|
||||
}
|
||||
|
||||
// Set ove_resolution to the destination to the "logical" resolution of the destination
|
||||
shader->setUniformValue("ove_resolution",
|
||||
static_cast<GLfloat>(destination_params.width()),
|
||||
static_cast<GLfloat>(destination_params.height()));
|
||||
|
||||
// Set matrix to identity
|
||||
shader->setUniformValue("ove_mvpmat", job.GetMatrix());
|
||||
|
||||
// Set the viewport to the "physical" resolution of the destination
|
||||
functions_->glViewport(0, 0,
|
||||
destination_params.effective_width(),
|
||||
destination_params.effective_height());
|
||||
|
||||
// Bind vertex array object
|
||||
QOpenGLVertexArrayObject vao_;
|
||||
vao_.create();
|
||||
vao_.bind();
|
||||
|
||||
// Set buffers
|
||||
QOpenGLBuffer vert_vbo_;
|
||||
vert_vbo_.create();
|
||||
vert_vbo_.bind();
|
||||
vert_vbo_.allocate(blit_vertices.constData(), blit_vertices.size() * sizeof(GLfloat));
|
||||
vert_vbo_.release();
|
||||
|
||||
QOpenGLBuffer frag_vbo_;
|
||||
frag_vbo_.create();
|
||||
frag_vbo_.bind();
|
||||
frag_vbo_.allocate(blit_texcoords.constData(), blit_texcoords.size() * sizeof(GLfloat));
|
||||
frag_vbo_.release();
|
||||
|
||||
int vertex_location = shader->attributeLocation("a_position");
|
||||
vert_vbo_.bind();
|
||||
functions_->glEnableVertexAttribArray(vertex_location);
|
||||
@@ -493,8 +470,9 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destinat
|
||||
DetachTextureAsDestination();
|
||||
}
|
||||
} else {
|
||||
// Always draw to output_tex
|
||||
// Always draw to output_tex, which gets swapped with input_tex every iteration
|
||||
AttachTextureAsDestination(output_tex.get());
|
||||
}
|
||||
|
||||
if (iteration > 0) {
|
||||
// If this is not the first iteration, replace the iterative texture with the one we
|
||||
@@ -506,7 +484,6 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destinat
|
||||
|
||||
// Swap so that the next iteration, the texture we draw now will be the input texture next
|
||||
std::swap(output_tex, input_tex);
|
||||
}
|
||||
|
||||
// Blit this texture through this shader
|
||||
functions_->glDrawArrays(GL_TRIANGLES, 0, blit_vertices.size() / 3);
|
||||
@@ -526,41 +503,16 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Renderer::Texture *destinat
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
// Release vertex array object
|
||||
vao_.release();
|
||||
|
||||
// Release shader
|
||||
shader->release();
|
||||
|
||||
// Release vertex array object
|
||||
frag_vbo_.destroy();
|
||||
vert_vbo_.destroy();
|
||||
vao_.release();
|
||||
vao_.destroy();
|
||||
}
|
||||
|
||||
/*void OpenGLRenderer::Blit(Renderer::Texture *source, QVariant shader, Renderer::ShaderUniformMap parameters, Renderer::Texture *destination)
|
||||
{
|
||||
QOpenGLShaderProgram* program = Node::ValueToPtr<QOpenGLShaderProgram>(shader);
|
||||
|
||||
if (!program) {
|
||||
qCritical() << "Attempted to blit with a null shader";
|
||||
return;
|
||||
}
|
||||
|
||||
if (destination) {
|
||||
AttachTextureAsDestination(destination);
|
||||
}
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, source->id().value<GLuint>());
|
||||
|
||||
program->bind();
|
||||
|
||||
qCritical() << "OpenGLRenderer::Blit is a stub!";
|
||||
|
||||
program->release();
|
||||
|
||||
functions_->glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
if (destination) {
|
||||
DetachTextureAsDestination();
|
||||
}
|
||||
}*/
|
||||
|
||||
GLint OpenGLRenderer::GetInternalFormat(PixelFormat::Format format)
|
||||
{
|
||||
switch (format) {
|
||||
|
||||
@@ -86,12 +86,6 @@ private:
|
||||
|
||||
QOffscreenSurface surface_;
|
||||
|
||||
QOpenGLVertexArrayObject vao_;
|
||||
|
||||
QOpenGLBuffer vert_vbo_;
|
||||
|
||||
QOpenGLBuffer frag_vbo_;
|
||||
|
||||
GLuint framebuffer_;
|
||||
|
||||
};
|
||||
|
||||
@@ -20,11 +20,9 @@
|
||||
|
||||
#include "renderer.h"
|
||||
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
|
||||
#include <QFloat16>
|
||||
|
||||
#include "common/ocioutils.h"
|
||||
#include "render/colormanager.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
@@ -54,83 +52,62 @@ const int OCIO_LUT3D_ENTRY_COUNT = 3 * OCIO_LUT3D_PIXEL_COUNT;
|
||||
const int OCIO_LUT3D_ENTRY_COUNT_WITH_ALPHA = 4 * OCIO_LUT3D_PIXEL_COUNT;
|
||||
const int OCIO_LUT2D_EDGE_SIZE = 512;*/
|
||||
|
||||
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture *destination)
|
||||
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture *destination, bool flipped)
|
||||
{
|
||||
qDebug() << "BlitColorManaged is a partial stub";
|
||||
|
||||
QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert")));
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture));
|
||||
|
||||
if (flipped) {
|
||||
QMatrix4x4 mat;
|
||||
mat.scale(1, -1, 1);
|
||||
job.SetMatrix(mat);
|
||||
}
|
||||
|
||||
BlitToTexture(shader, job, destination);
|
||||
|
||||
DestroyNativeShader(shader);
|
||||
}
|
||||
|
||||
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params, bool flipped)
|
||||
{
|
||||
qDebug() << "BlitColorManaged is a partial stub";
|
||||
|
||||
/*ColorContext color_ctx;
|
||||
|
||||
if (color_cache_.contains(color_processor->id())) {
|
||||
color_ctx = color_cache_.value(color_processor->id());
|
||||
} else {
|
||||
// Generate OCIO color context
|
||||
|
||||
// Generate OCIO shader descriptor
|
||||
// Create shader description
|
||||
const char* ocio_func_name = "OCIODisplay";
|
||||
OCIO::GpuShaderDesc shader_desc;
|
||||
shader_desc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
|
||||
shader_desc.setFunctionName(ocio_func_name);
|
||||
shader_desc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE);
|
||||
OCIO::GpuShaderDescRcPtr shader_desc = OCIO::GpuShaderDesc::CreateShaderDesc();
|
||||
shader_desc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_2);
|
||||
shader_desc->setFunctionName(ocio_func_name);
|
||||
shader_desc->setResourcePrefix("ocio_");
|
||||
|
||||
// Generate LUT
|
||||
QVector<float> lut_data(OCIO_LUT3D_ENTRY_COUNT);
|
||||
color_processor->GetProcessor()->getGpuLut3D(lut_data.data(), shader_desc);
|
||||
// Generate shader
|
||||
color_processor->GetProcessor()->getDefaultGPUProcessor()->extractGpuShaderInfo(shader_desc);
|
||||
|
||||
// Convert to half float RGBA
|
||||
QVector<qfloat16> texture_ready_lut_data(OCIO_LUT3D_ENTRY_COUNT_WITH_ALPHA);
|
||||
for (int i=0; i<OCIO_LUT3D_PIXEL_COUNT; i++) {
|
||||
texture_ready_lut_data[i*kRGBAChannels+0] = lut_data[i*kRGBChannels+0];
|
||||
texture_ready_lut_data[i*kRGBAChannels+1] = lut_data[i*kRGBChannels+1];
|
||||
texture_ready_lut_data[i*kRGBAChannels+2] = lut_data[i*kRGBChannels+2];
|
||||
texture_ready_lut_data[i*kRGBAChannels+3] = 1.0f;
|
||||
}
|
||||
|
||||
// Create LUT texture
|
||||
color_ctx.lut = CreateTexture(VideoParams(OCIO_LUT2D_EDGE_SIZE, OCIO_LUT2D_EDGE_SIZE, PixelFormat::PIX_FMT_RGBA32F),
|
||||
texture_ready_lut_data.data());
|
||||
|
||||
// Create shader
|
||||
QString frag_code;
|
||||
|
||||
frag_code.append(QStringLiteral("sampler2D texture;\n"
|
||||
"sampler2D lut;\n"
|
||||
"\n"
|
||||
"vec3 LUTLookup(sampler2D lut3d, vec3 in_coord)\n"
|
||||
"{\n"
|
||||
" return texture2D(lut3d, vec2());\n"
|
||||
"}\n"
|
||||
"\n"));
|
||||
|
||||
// Correct code for our GLSL set up
|
||||
QString ocio_code = color_processor->GetProcessor()->getGpuShaderText(shader_desc);
|
||||
ocio_code.replace(QStringLiteral("texture3D"), QStringLiteral("texture2D"));
|
||||
ocio_code.replace(QStringLiteral("sampler3D"), QStringLiteral("sampler2D"));
|
||||
|
||||
|
||||
|
||||
qDebug() << frag_code;
|
||||
|
||||
//qDebug() << "FIXME: GPU doesn't handle associated alpha yet";
|
||||
qDebug() << "Shader:" << shader_desc->getShaderText();
|
||||
}*/
|
||||
|
||||
qDebug() << "BlitColorManaged is a partial stub";
|
||||
|
||||
QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert")));
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture));
|
||||
|
||||
BlitToTexture(shader, job, destination);
|
||||
if (flipped) {
|
||||
QMatrix4x4 mat;
|
||||
mat.scale(1, -1, 1);
|
||||
job.SetMatrix(mat);
|
||||
}
|
||||
|
||||
void Renderer::BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params)
|
||||
{
|
||||
qDebug() << "BlitColorManaged is a partial stub";
|
||||
|
||||
QVariant shader = CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(":/shaders/default.frag"), FileFunctions::ReadFileAsString(":/shaders/default.vert")));
|
||||
|
||||
ShaderJob job;
|
||||
job.InsertValue(QStringLiteral("ove_maintex"), ShaderValue(QVariant::fromValue(source), NodeParam::kTexture));
|
||||
|
||||
Blit(shader, job, params);
|
||||
|
||||
DestroyNativeShader(shader);
|
||||
}
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
@@ -135,8 +135,8 @@ public:
|
||||
Blit(shader, job, nullptr, params);
|
||||
}
|
||||
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture* destination);
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params);
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, Texture* destination, bool flipped = false);
|
||||
void BlitColorManaged(ColorProcessorPtr color_processor, TexturePtr source, VideoParams params, bool flipped = false);
|
||||
|
||||
public slots:
|
||||
virtual void PostInit() = 0;
|
||||
|
||||
+47
-47
@@ -24,41 +24,41 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
Color Color::fromHsv(const float &h, const float &s, const float &v)
|
||||
Color Color::fromHsv(const double &h, const double &s, const double &v)
|
||||
{
|
||||
float C = s * v;
|
||||
float X = C * (1.0f - abs(fmod(h / 60.0f, 2.0f) - 1.0f));
|
||||
float m = v - C;
|
||||
float Rs, Gs, Bs;
|
||||
double C = s * v;
|
||||
double X = C * (1.0 - abs(fmod(h / 60.0, 2.0) - 1.0));
|
||||
double m = v - C;
|
||||
double Rs, Gs, Bs;
|
||||
|
||||
if(h >= 0.0f && h < 60.0f) {
|
||||
if(h >= 0.0 && h < 60.0) {
|
||||
Rs = C;
|
||||
Gs = X;
|
||||
Bs = 0.0f;
|
||||
Bs = 0.0;
|
||||
}
|
||||
else if(h >= 60.0f && h < 120.0f) {
|
||||
else if(h >= 60.0 && h < 120.0) {
|
||||
Rs = X;
|
||||
Gs = C;
|
||||
Bs = 0.0f;
|
||||
Bs = 0.0;
|
||||
}
|
||||
else if(h >= 120.0f && h < 180.0f) {
|
||||
Rs = 0.0f;
|
||||
else if(h >= 120.0 && h < 180.0) {
|
||||
Rs = 0.0;
|
||||
Gs = C;
|
||||
Bs = X;
|
||||
}
|
||||
else if(h >= 180.0f && h < 240.0f) {
|
||||
Rs = 0.0f;
|
||||
else if(h >= 180.0 && h < 240.0) {
|
||||
Rs = 0.0;
|
||||
Gs = X;
|
||||
Bs = C;
|
||||
}
|
||||
else if(h >= 240.0f && h < 300.0f) {
|
||||
else if(h >= 240.0 && h < 300.0) {
|
||||
Rs = X;
|
||||
Gs = 0.0f;
|
||||
Gs = 0.0;
|
||||
Bs = C;
|
||||
}
|
||||
else {
|
||||
Rs = C;
|
||||
Gs = 0.0f;
|
||||
Gs = 0.0;
|
||||
Bs = X;
|
||||
}
|
||||
|
||||
@@ -78,11 +78,11 @@ Color::Color(const QColor &c)
|
||||
set_alpha(c.alphaF());
|
||||
}
|
||||
|
||||
void Color::toHsv(float *hue, float *sat, float *val) const
|
||||
void Color::toHsv(double *hue, double *sat, double *val) const
|
||||
{
|
||||
float fCMax = qMax(qMax(red(), green()), blue());
|
||||
float fCMin = qMin(qMin(red(), green()), blue());
|
||||
float fDelta = fCMax - fCMin;
|
||||
double fCMax = qMax(qMax(red(), green()), blue());
|
||||
double fCMin = qMin(qMin(red(), green()), blue());
|
||||
double fDelta = fCMax - fCMin;
|
||||
|
||||
if(fDelta > 0) {
|
||||
if(fCMax == red()) {
|
||||
@@ -111,31 +111,31 @@ void Color::toHsv(float *hue, float *sat, float *val) const
|
||||
}
|
||||
}
|
||||
|
||||
float Color::hsv_hue() const
|
||||
double Color::hsv_hue() const
|
||||
{
|
||||
float h, s, v;
|
||||
double h, s, v;
|
||||
toHsv(&h, &s, &v);
|
||||
return h;
|
||||
}
|
||||
|
||||
float Color::hsv_saturation() const
|
||||
double Color::hsv_saturation() const
|
||||
{
|
||||
float h, s, v;
|
||||
double h, s, v;
|
||||
toHsv(&h, &s, &v);
|
||||
return s;
|
||||
}
|
||||
|
||||
float Color::value() const
|
||||
double Color::value() const
|
||||
{
|
||||
float h, s, v;
|
||||
double h, s, v;
|
||||
toHsv(&h, &s, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
void Color::toHsl(float *hue, float *sat, float *lightness) const
|
||||
void Color::toHsl(double *hue, double *sat, double *lightness) const
|
||||
{
|
||||
float fCMin = qMin(red(), qMin(green(), blue()));
|
||||
float fCMax = qMax(red(), qMax(green(), blue()));
|
||||
double fCMin = qMin(red(), qMin(green(), blue()));
|
||||
double fCMax = qMax(red(), qMax(green(), blue()));
|
||||
|
||||
*lightness = 0.5 * (fCMin + fCMax);
|
||||
|
||||
@@ -173,30 +173,30 @@ void Color::toHsl(float *hue, float *sat, float *lightness) const
|
||||
}
|
||||
}
|
||||
|
||||
float Color::hsl_hue() const
|
||||
double Color::hsl_hue() const
|
||||
{
|
||||
float h, s, l;
|
||||
double h, s, l;
|
||||
toHsl(&h, &s, &l);
|
||||
return h;
|
||||
}
|
||||
|
||||
float Color::hsl_saturation() const
|
||||
double Color::hsl_saturation() const
|
||||
{
|
||||
float h, s, l;
|
||||
double h, s, l;
|
||||
toHsl(&h, &s, &l);
|
||||
return s;
|
||||
}
|
||||
|
||||
float Color::lightness() const
|
||||
double Color::lightness() const
|
||||
{
|
||||
float h, s, l;
|
||||
double h, s, l;
|
||||
toHsl(&h, &s, &l);
|
||||
return l;
|
||||
}
|
||||
|
||||
void Color::toData(char *data, const PixelFormat::Format &format) const
|
||||
{
|
||||
OIIO::convert_types(OIIO::TypeDesc::FLOAT,
|
||||
OIIO::convert_types(OIIO::TypeDesc::DOUBLE,
|
||||
data_,
|
||||
PixelFormat::GetOIIOTypeDesc(format),
|
||||
data,
|
||||
@@ -209,7 +209,7 @@ Color Color::fromData(const char *data, const PixelFormat::Format &format)
|
||||
|
||||
OIIO::convert_types(PixelFormat::GetOIIOTypeDesc(format),
|
||||
data,
|
||||
OIIO::TypeDesc::FLOAT,
|
||||
OIIO::TypeDesc::DOUBLE,
|
||||
c.data_,
|
||||
kRGBAChannels);
|
||||
|
||||
@@ -221,17 +221,17 @@ QColor Color::toQColor() const
|
||||
QColor c;
|
||||
|
||||
// QColor only supports values from 0.0 to 1.0 and are only used for UI representations
|
||||
c.setRedF(clamp(red(), 0.0f, 1.0f));
|
||||
c.setGreenF(clamp(green(), 0.0f, 1.0f));
|
||||
c.setBlueF(clamp(blue(), 0.0f, 1.0f));
|
||||
c.setAlphaF(clamp(alpha(), 0.0f, 1.0f));
|
||||
c.setRedF(clamp(red(), 0.0, 1.0));
|
||||
c.setGreenF(clamp(green(), 0.0, 1.0));
|
||||
c.setBlueF(clamp(blue(), 0.0, 1.0));
|
||||
c.setAlphaF(clamp(alpha(), 0.0, 1.0));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
float Color::GetRoughLuminance() const
|
||||
double Color::GetRoughLuminance() const
|
||||
{
|
||||
return (2*red()+blue()+3*green())/6.0f;
|
||||
return (2*red()+blue()+3*green())/6.0;
|
||||
}
|
||||
|
||||
const Color &Color::operator+=(const Color &rhs)
|
||||
@@ -252,7 +252,7 @@ const Color &Color::operator-=(const Color &rhs)
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Color &Color::operator*=(const float &rhs)
|
||||
const Color &Color::operator*=(const double &rhs)
|
||||
{
|
||||
for (int i=0;i<kRGBAChannels;i++) {
|
||||
data_[i] *= rhs;
|
||||
@@ -261,7 +261,7 @@ const Color &Color::operator*=(const float &rhs)
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Color &Color::operator/=(const float &rhs)
|
||||
const Color &Color::operator/=(const double &rhs)
|
||||
{
|
||||
for (int i=0;i<kRGBAChannels;i++) {
|
||||
data_[i] /= rhs;
|
||||
@@ -284,14 +284,14 @@ Color Color::operator-(const Color &rhs) const
|
||||
return c;
|
||||
}
|
||||
|
||||
Color Color::operator*(const float &rhs) const
|
||||
Color Color::operator*(const double &rhs) const
|
||||
{
|
||||
Color c(*this);
|
||||
c *= rhs;
|
||||
return c;
|
||||
}
|
||||
|
||||
Color Color::operator/(const float &rhs) const
|
||||
Color Color::operator/(const double &rhs) const
|
||||
{
|
||||
Color c(*this);
|
||||
c /= rhs;
|
||||
|
||||
+28
-28
@@ -30,7 +30,7 @@
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
/**
|
||||
* @brief High precision 32-bit float based RGBA color value
|
||||
* @brief High precision 64-bit float based RGBA color value
|
||||
*/
|
||||
class Color
|
||||
{
|
||||
@@ -38,11 +38,11 @@ public:
|
||||
Color()
|
||||
{
|
||||
for (int i=0;i<kRGBAChannels;i++) {
|
||||
data_[i] = 0;
|
||||
data_[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
Color(const float& r, const float& g, const float& b, const float& a = 1.0f)
|
||||
Color(const double& r, const double& g, const double& b, const double& a = 1.0)
|
||||
{
|
||||
data_[0] = r;
|
||||
data_[1] = g;
|
||||
@@ -59,30 +59,30 @@ public:
|
||||
*
|
||||
* Hue expects a value between 0.0 and 360.0. Saturation and Value expect a value between 0.0 and 1.0.
|
||||
*/
|
||||
static Color fromHsv(const float& h, const float& s, const float &v);
|
||||
static Color fromHsv(const double& h, const double& s, const double &v);
|
||||
|
||||
const float& red() const {return data_[0];}
|
||||
const float& green() const {return data_[1];}
|
||||
const float& blue() const {return data_[2];}
|
||||
const float& alpha() const {return data_[3];}
|
||||
const double& red() const {return data_[0];}
|
||||
const double& green() const {return data_[1];}
|
||||
const double& blue() const {return data_[2];}
|
||||
const double& alpha() const {return data_[3];}
|
||||
|
||||
void toHsv(float* hue, float* sat, float* val) const;
|
||||
float hsv_hue() const;
|
||||
float hsv_saturation() const;
|
||||
float value() const;
|
||||
void toHsv(double* hue, double* sat, double* val) const;
|
||||
double hsv_hue() const;
|
||||
double hsv_saturation() const;
|
||||
double value() const;
|
||||
|
||||
void toHsl(float* hue, float* sat, float* lightness) const;
|
||||
float hsl_hue() const;
|
||||
float hsl_saturation() const;
|
||||
float lightness() const;
|
||||
void toHsl(double* hue, double* sat, double* lightness) const;
|
||||
double hsl_hue() const;
|
||||
double hsl_saturation() const;
|
||||
double lightness() const;
|
||||
|
||||
void set_red(const float& red) {data_[0] = red;}
|
||||
void set_green(const float& green) {data_[1] = green;}
|
||||
void set_blue(const float& blue) {data_[2] = blue;}
|
||||
void set_alpha(const float& alpha) {data_[3] = alpha;}
|
||||
void set_red(const double& red) {data_[0] = red;}
|
||||
void set_green(const double& green) {data_[1] = green;}
|
||||
void set_blue(const double& blue) {data_[2] = blue;}
|
||||
void set_alpha(const double& alpha) {data_[3] = alpha;}
|
||||
|
||||
float* data() {return data_;}
|
||||
const float* data() const {return data_;}
|
||||
double* data() {return data_;}
|
||||
const double* data() const {return data_;}
|
||||
|
||||
void toData(char* data, const PixelFormat::Format& format) const;
|
||||
|
||||
@@ -92,22 +92,22 @@ public:
|
||||
|
||||
// Suuuuper rough luminance value mostly used for UI (determining whether to overlay with black
|
||||
// or white text)
|
||||
float GetRoughLuminance() const;
|
||||
double GetRoughLuminance() const;
|
||||
|
||||
// Assignment math operators
|
||||
const Color& operator+=(const Color& rhs);
|
||||
const Color& operator-=(const Color& rhs);
|
||||
const Color& operator*=(const float& rhs);
|
||||
const Color& operator/=(const float& rhs);
|
||||
const Color& operator*=(const double& rhs);
|
||||
const Color& operator/=(const double& rhs);
|
||||
|
||||
// Binary math operators
|
||||
Color operator+(const Color& rhs) const;
|
||||
Color operator-(const Color& rhs) const;
|
||||
Color operator*(const float& rhs) const;
|
||||
Color operator/(const float& rhs) const;
|
||||
Color operator*(const double& rhs) const;
|
||||
Color operator/(const double& rhs) const;
|
||||
|
||||
private:
|
||||
float data_[kRGBAChannels];
|
||||
double data_[kRGBAChannels];
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -302,7 +302,7 @@ QStringList ColorManager::ListAvailableColorspaces(OCIO::ConstConfigRcPtr config
|
||||
return spaces;
|
||||
}
|
||||
|
||||
void ColorManager::GetDefaultLumaCoefs(float *rgb) const
|
||||
void ColorManager::GetDefaultLumaCoefs(double *rgb) const
|
||||
{
|
||||
config_->getDefaultLumaCoefs(rgb);
|
||||
}
|
||||
@@ -320,16 +320,6 @@ Color ColorManager::GetDefaultLumaCoefs() const
|
||||
return c;
|
||||
}
|
||||
|
||||
ColorManager::OCIOMethod ColorManager::GetOCIOMethodForMode(RenderMode::Mode mode)
|
||||
{
|
||||
return static_cast<OCIOMethod>(Core::GetPreferenceForRenderMode(mode, QStringLiteral("OCIOMethod")).toInt());
|
||||
}
|
||||
|
||||
void ColorManager::SetOCIOMethodForMode(RenderMode::Mode mode, ColorManager::OCIOMethod method)
|
||||
{
|
||||
Core::SetPreferenceForRenderMode(mode, QStringLiteral("OCIOMethod"), method);
|
||||
}
|
||||
|
||||
void ColorManager::AssociateAlphaPixFmtFilter(ColorManager::AlphaAction action, FramePtr f)
|
||||
{
|
||||
int pixel_count = f->width() * f->height() * kRGBAChannels;
|
||||
|
||||
@@ -82,18 +82,9 @@ public:
|
||||
|
||||
static QStringList ListAvailableColorspaces(OCIO::ConstConfigRcPtr config);
|
||||
|
||||
void GetDefaultLumaCoefs(float* rgb) const;
|
||||
void GetDefaultLumaCoefs(double *rgb) const;
|
||||
Color GetDefaultLumaCoefs() const;
|
||||
|
||||
enum OCIOMethod {
|
||||
kOCIOFast,
|
||||
kOCIOAccurate
|
||||
};
|
||||
|
||||
static OCIOMethod GetOCIOMethodForMode(RenderMode::Mode mode);
|
||||
|
||||
static void SetOCIOMethodForMode(RenderMode::Mode mode, OCIOMethod method);
|
||||
|
||||
class SetLocale
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -33,19 +33,35 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const
|
||||
|
||||
const QString& view = (transform.view().isEmpty()) ? config->GetDefaultView(output) : transform.view();
|
||||
|
||||
OCIO::DisplayTransformRcPtr display_transform = OCIO::DisplayTransform::Create();
|
||||
auto display_transform = OCIO::DisplayViewTransform::Create();
|
||||
|
||||
display_transform->setInputColorSpaceName(input.toUtf8());
|
||||
display_transform->setSrc(input.toUtf8());
|
||||
display_transform->setDisplay(output.toUtf8());
|
||||
display_transform->setView(view.toUtf8());
|
||||
|
||||
if (!transform.look().isEmpty()) {
|
||||
display_transform->setLooksOverride(transform.look().toUtf8());
|
||||
display_transform->setLooksOverrideEnabled(true);
|
||||
}
|
||||
|
||||
OCIO_SET_C_LOCALE_FOR_SCOPE;
|
||||
|
||||
if (transform.look().isEmpty()) {
|
||||
processor_ = config->GetConfig()->getProcessor(display_transform);
|
||||
} else {
|
||||
auto group = OCIO::GroupTransform::Create();
|
||||
|
||||
const char* out_cs = OCIO::LookTransform::GetLooksResultColorSpace(config->GetConfig(),
|
||||
config->GetConfig()->getCurrentContext(),
|
||||
transform.look().toUtf8());
|
||||
|
||||
auto lt = OCIO::LookTransform::Create();
|
||||
lt->setSrc(input.toUtf8());
|
||||
lt->setDst(out_cs);
|
||||
lt->setLooks(transform.look().toUtf8());
|
||||
lt->setSkipColorSpaceConversion(false);
|
||||
group->appendTransform(lt);
|
||||
|
||||
display_transform->setSrc(out_cs);
|
||||
group->appendTransform(display_transform);
|
||||
|
||||
processor_ = config->GetConfig()->getProcessor(group);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -55,26 +71,39 @@ ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const
|
||||
|
||||
}
|
||||
|
||||
cpu_processor_ = processor_->getDefaultCPUProcessor();
|
||||
id_ = GenerateID(config, input, transform);
|
||||
}
|
||||
|
||||
void ColorProcessor::ConvertFrame(Frame *f)
|
||||
{
|
||||
OCIO::PackedImageDesc img(reinterpret_cast<float*>(f->data()),
|
||||
OCIO::BitDepth ocio_bit_depth = PixelFormat::GetOCIOBitDepthFromPixelFormat(f->format());
|
||||
|
||||
if (ocio_bit_depth == OCIO::BIT_DEPTH_UNKNOWN) {
|
||||
qCritical() << "Tried to color convert frame with no format";
|
||||
return;
|
||||
}
|
||||
|
||||
OCIO::PackedImageDesc img(f->data(),
|
||||
f->width(),
|
||||
f->height(),
|
||||
kRGBAChannels,
|
||||
ocio_bit_depth,
|
||||
OCIO::AutoStride,
|
||||
OCIO::AutoStride,
|
||||
f->linesize_bytes());
|
||||
|
||||
processor_->apply(img);
|
||||
cpu_processor_->apply(img);
|
||||
}
|
||||
|
||||
Color ColorProcessor::ConvertColor(Color in)
|
||||
Color ColorProcessor::ConvertColor(const Color& in)
|
||||
{
|
||||
processor_->applyRGBA(in.data());
|
||||
return in;
|
||||
// I've been bamboozled
|
||||
float c[4] = {float(in.red()), float(in.green()), float(in.blue()), float(in.alpha())};
|
||||
|
||||
cpu_processor_->applyRGBA(c);
|
||||
|
||||
return Color(c[0], c[1], c[2], c[3]);
|
||||
}
|
||||
|
||||
QString ColorProcessor::GenerateID(ColorManager *config, const QString &input, const ColorTransform &transform)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#define COLORPROCESSOR_H
|
||||
|
||||
#include "codec/frame.h"
|
||||
#include "common/ocioutils.h"
|
||||
#include "render/color.h"
|
||||
#include "render/colortransform.h"
|
||||
|
||||
@@ -51,7 +52,7 @@ public:
|
||||
void ConvertFrame(FramePtr f);
|
||||
void ConvertFrame(Frame* f);
|
||||
|
||||
Color ConvertColor(Color in);
|
||||
Color ConvertColor(const Color &in);
|
||||
|
||||
const QString& id() const
|
||||
{
|
||||
@@ -63,6 +64,8 @@ public:
|
||||
private:
|
||||
OCIO::ConstProcessorRcPtr processor_;
|
||||
|
||||
OCIO::ConstCPUProcessorRcPtr cpu_processor_;
|
||||
|
||||
QString id_;
|
||||
|
||||
};
|
||||
|
||||
@@ -21,11 +21,10 @@
|
||||
#ifndef COLORTRANSFORM_H
|
||||
#define COLORTRANSFORM_H
|
||||
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "common/define.h"
|
||||
#include "common/ocioutils.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
|
||||
@@ -86,6 +86,28 @@ QString PixelFormat::GetName(const PixelFormat::Format &format)
|
||||
return tr("Unknown (%1)").arg(format);
|
||||
}
|
||||
|
||||
OCIO::BitDepth PixelFormat::GetOCIOBitDepthFromPixelFormat(PixelFormat::Format format)
|
||||
{
|
||||
switch (format) {
|
||||
case PixelFormat::PIX_FMT_RGBA8:
|
||||
return OCIO::BIT_DEPTH_UINT8;
|
||||
case PixelFormat::PIX_FMT_RGBA16U:
|
||||
return OCIO::BIT_DEPTH_UINT16;
|
||||
break;
|
||||
case PixelFormat::PIX_FMT_RGBA16F:
|
||||
return OCIO::BIT_DEPTH_F16;
|
||||
break;
|
||||
case PixelFormat::PIX_FMT_RGBA32F:
|
||||
return OCIO::BIT_DEPTH_F32;
|
||||
break;
|
||||
case PixelFormat::PIX_FMT_INVALID:
|
||||
case PixelFormat::PIX_FMT_COUNT:
|
||||
break;
|
||||
}
|
||||
|
||||
return OCIO::BIT_DEPTH_UNKNOWN;
|
||||
}
|
||||
|
||||
PixelFormat* PixelFormat::instance_ = nullptr;
|
||||
|
||||
void PixelFormat::CreateInstance()
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <QString>
|
||||
|
||||
#include "common/ocioutils.h"
|
||||
#include "render/rendermodes.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
@@ -116,6 +117,8 @@ public:
|
||||
*/
|
||||
static QString GetName(const Format& format);
|
||||
|
||||
static OCIO::BitDepth GetOCIOBitDepthFromPixelFormat(PixelFormat::Format format);
|
||||
|
||||
signals:
|
||||
void FormatChanged();
|
||||
|
||||
|
||||
@@ -585,7 +585,9 @@ void PreviewAutoCacher::TryRender()
|
||||
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_,
|
||||
color_manager_,
|
||||
single_frame_render_->property("time").value<rational>(),
|
||||
RenderMode::kOffline, true));
|
||||
RenderMode::kOffline,
|
||||
viewer_node_->video_frame_cache(),
|
||||
true));
|
||||
|
||||
single_frame_render_ = nullptr;
|
||||
}
|
||||
@@ -626,7 +628,9 @@ void PreviewAutoCacher::RequeueFrames()
|
||||
video_tasks_.insert(watcher, hash);
|
||||
watcher->SetTicket(RenderManager::instance()->RenderFrame(copied_viewer_node_,
|
||||
color_manager_,
|
||||
t, RenderMode::kOffline, false));
|
||||
t, RenderMode::kOffline,
|
||||
viewer_node_->video_frame_cache(),
|
||||
false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ QByteArray RenderManager::Hash(const Node *n, const VideoParams ¶ms, const r
|
||||
return hasher.result();
|
||||
}
|
||||
|
||||
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager *color_manager, const rational &time, RenderMode::Mode mode, bool prioritize)
|
||||
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager *color_manager, const rational &time, RenderMode::Mode mode, FrameHashCache *cache, bool prioritize)
|
||||
{
|
||||
return RenderFrame(viewer,
|
||||
color_manager,
|
||||
@@ -101,10 +101,11 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager *c
|
||||
mode,
|
||||
QSize(0, 0),
|
||||
QMatrix4x4(),
|
||||
cache,
|
||||
prioritize);
|
||||
}
|
||||
|
||||
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, const rational &time, RenderMode::Mode mode, const QSize &force_size, const QMatrix4x4 &matrix, bool prioritize)
|
||||
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, const rational &time, RenderMode::Mode mode, const QSize &force_size, const QMatrix4x4 &matrix, FrameHashCache *cache, bool prioritize)
|
||||
{
|
||||
// Create ticket
|
||||
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
|
||||
@@ -115,7 +116,7 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* c
|
||||
ticket->setProperty("matrix", matrix);
|
||||
ticket->setProperty("mode", mode);
|
||||
ticket->setProperty("type", kTypeVideo);
|
||||
ticket->setProperty("cache", viewer->video_frame_cache()->GetCacheDirectory());
|
||||
ticket->setProperty("cache", cache->GetCacheDirectory());
|
||||
ticket->setProperty("colormanager", Node::PtrToValue(color_manager));
|
||||
|
||||
// Queue appending the ticket and running the next job on our thread to make this function thread-safe
|
||||
|
||||
@@ -80,8 +80,8 @@ public:
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*/
|
||||
RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, bool prioritize = false);
|
||||
RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, const QSize& force_size, const QMatrix4x4& matrix, bool prioritize = false);
|
||||
RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, FrameHashCache* cache = nullptr, bool prioritize = false);
|
||||
RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, const QSize& force_size, const QMatrix4x4& matrix, FrameHashCache* cache = nullptr, bool prioritize = false);
|
||||
|
||||
/**
|
||||
* @brief Asynchronously generate a chunk of audio
|
||||
|
||||
@@ -297,7 +297,7 @@ QVariant RenderProcessor::ProcessVideoFootage(StreamPtr stream, const rational &
|
||||
|
||||
qDebug() << "FIXME: Accessing video_stream->colorspace() may cause race conditions";
|
||||
|
||||
ColorManager* color_manager = video_stream->footage()->project()->color_manager();
|
||||
ColorManager* color_manager = Node::ValueToPtr<ColorManager>(ticket_->property("colormanager"));
|
||||
ColorProcessorPtr processor = ColorProcessor::Create(color_manager,
|
||||
video_stream->colorspace(),
|
||||
ColorTransform(OCIO::ROLE_SCENE_LINEAR));
|
||||
@@ -434,7 +434,7 @@ QVariant RenderProcessor::ProcessFrameGeneration(const Node *node, const Generat
|
||||
|
||||
QVariant RenderProcessor::GetCachedFrame(const Node *node, const rational &time)
|
||||
{
|
||||
if (ticket_->property("mode").toInt() == RenderMode::kOffline
|
||||
if (!ticket_->property("cache").toString().isEmpty()
|
||||
&& node->id() == QStringLiteral("org.olivevideoeditor.Olive.videoinput")) {
|
||||
const VideoParams& video_params = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"))->video_params();
|
||||
|
||||
@@ -442,6 +442,8 @@ QVariant RenderProcessor::GetCachedFrame(const Node *node, const rational &time)
|
||||
|
||||
FramePtr f = FrameHashCache::LoadCacheFrame(ticket_->property("cache").toString(), hash);
|
||||
|
||||
qDebug() << ticket_->property("cache").toString() << hash.toHex();
|
||||
|
||||
if (f) {
|
||||
// The cached frame won't load with the correct divider by default, so we enforce it here
|
||||
VideoParams p = f->video_params();
|
||||
@@ -452,8 +454,12 @@ QVariant RenderProcessor::GetCachedFrame(const Node *node, const rational &time)
|
||||
|
||||
f->set_video_params(p);
|
||||
|
||||
qDebug() << "Using cached frame!";
|
||||
|
||||
Renderer::TexturePtr texture = render_ctx_->CreateTexture(f->video_params(), f->data(), f->linesize_pixels());
|
||||
return QVariant::fromValue(texture);
|
||||
} else {
|
||||
qDebug() << "Not using cached frame because frame is null";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef SHADERINFO_H
|
||||
#define SHADERINFO_H
|
||||
|
||||
#include <QMatrix4x4>
|
||||
|
||||
#include "codec/samplebuffer.h"
|
||||
#include "common/filefunctions.h"
|
||||
#include "node/input.h"
|
||||
@@ -142,6 +144,16 @@ public:
|
||||
bilinear_ = true;
|
||||
}
|
||||
|
||||
const QMatrix4x4& GetMatrix() const
|
||||
{
|
||||
return matrix_;
|
||||
}
|
||||
|
||||
void SetMatrix(const QMatrix4x4& matrix)
|
||||
{
|
||||
matrix_ = matrix;
|
||||
}
|
||||
|
||||
const QString& GetShaderID() const
|
||||
{
|
||||
return shader_id_;
|
||||
@@ -192,6 +204,8 @@ private:
|
||||
|
||||
bool bilinear_;
|
||||
|
||||
QMatrix4x4 matrix_;
|
||||
|
||||
};
|
||||
|
||||
class ShaderCode {
|
||||
|
||||
@@ -114,11 +114,6 @@ bool ExportTask::Run()
|
||||
|
||||
void FrameColorConvert(ColorProcessorPtr processor, FramePtr frame)
|
||||
{
|
||||
// OCIO conversion requires a frame in 32F format
|
||||
if (frame->format() != PixelFormat::PIX_FMT_RGBA32F) {
|
||||
frame = PixelFormat::ConvertPixelFormat(frame, PixelFormat::PIX_FMT_RGBA32F);
|
||||
}
|
||||
|
||||
// Color conversion must be done with unassociated alpha, and the pipeline is always associated
|
||||
ColorManager::DisassociateAlpha(frame);
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ bool LoadOTIOTask::Run()
|
||||
if (imported_footage.contains(footage_url)) {
|
||||
probed_item = imported_footage.value(footage_url);
|
||||
} else {
|
||||
probed_item = Decoder::ProbeMedia(project_.get(), footage_url, &IsCancelled());
|
||||
probed_item = Decoder::Probe(project_.get(), footage_url, &IsCancelled());
|
||||
imported_footage.insert(footage_url, probed_item);
|
||||
project_->root()->add_child(probed_item);
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ void ThreadPoolThread::RunTicket(RenderTicketPtr ticket)
|
||||
|
||||
void ThreadPoolThread::run()
|
||||
{
|
||||
while (!IsCancelled()) {
|
||||
while (true) {
|
||||
wait_cond_.wait(&mutex_);
|
||||
|
||||
if (ticket_) {
|
||||
@@ -122,9 +122,13 @@ void ThreadPoolThread::run()
|
||||
ticket_ = nullptr;
|
||||
}
|
||||
|
||||
if (IsCancelled()) {
|
||||
break;
|
||||
} else {
|
||||
emit Done();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPoolThread::CancelEvent()
|
||||
{
|
||||
|
||||
@@ -76,7 +76,7 @@ void ColorGradientWidget::paintEvent(QPaintEvent *e)
|
||||
p.setPen(QPen(GetUISelectorColor(), qMax(1, selector_radius / 2)));
|
||||
p.setBrush(Qt::NoBrush);
|
||||
|
||||
float clamped_val = clamp(val_, 0.0f, 1.0f);
|
||||
double clamped_val = clamp(val_, 0.0, 1.0);
|
||||
|
||||
if (orientation_ == Qt::Horizontal) {
|
||||
p.drawRect(qRound(width() * (1.0 - clamped_val)) - selector_radius, 0, selector_radius * 2, height() - 1);
|
||||
@@ -87,7 +87,7 @@ void ColorGradientWidget::paintEvent(QPaintEvent *e)
|
||||
|
||||
void ColorGradientWidget::SelectedColorChangedEvent(const Color &c, bool external)
|
||||
{
|
||||
float hue, sat;
|
||||
double hue, sat;
|
||||
|
||||
c.toHsv(&hue, &sat, &val_);
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ private:
|
||||
|
||||
Color end_;
|
||||
|
||||
float val_;
|
||||
double val_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ void ColorWheelWidget::SelectedColorChangedEvent(const Color &c, bool external)
|
||||
{
|
||||
if (external) {
|
||||
force_redraw_ = true;
|
||||
val_ = clamp(c.value(), 0.0f, 1.0f);
|
||||
val_ = clamp(c.value(), 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ Color ColorWheelWidget::GetColorFromTriangle(const ColorWheelWidget::Triangle &t
|
||||
|
||||
QPoint ColorWheelWidget::GetCoordsFromColor(const Color &c) const
|
||||
{
|
||||
float hue, sat, val;
|
||||
double hue, sat, val;
|
||||
c.toHsv(&hue, &sat, &val);
|
||||
|
||||
qreal hypotenuse = sat * GetRadius();
|
||||
|
||||
@@ -170,6 +170,11 @@ protected:
|
||||
|
||||
void doneCurrent();
|
||||
|
||||
QWidget* inner_widget() const
|
||||
{
|
||||
return inner_widget_;
|
||||
}
|
||||
|
||||
protected slots:
|
||||
/**
|
||||
* @brief Called whenever the internal rendering context has been created
|
||||
|
||||
@@ -92,7 +92,7 @@ void HistogramScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipeli
|
||||
renderer()->Blit(pipeline_secondary_, shader_job, texture_row_sums_->params());
|
||||
|
||||
// Draw line overlays
|
||||
QPainter p(this);
|
||||
QPainter p(inner_widget());
|
||||
QFont font = p.font();
|
||||
font.setPixelSize(10);
|
||||
QFontMetrics font_metrics = QFontMetrics(font);
|
||||
|
||||
@@ -60,7 +60,7 @@ void WaveformScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipelin
|
||||
ShaderValue(QVector2D(width(), height()), NodeParam::kVec2));
|
||||
|
||||
// Set luma coefficients
|
||||
float luma_coeffs[3] = {0.0f, 0.0f, 0.0f};
|
||||
double luma_coeffs[3] = {0.0f, 0.0f, 0.0f};
|
||||
color_manager()->GetDefaultLumaCoefs(luma_coeffs);
|
||||
job.InsertValue(QStringLiteral("luma_coeffs"),
|
||||
ShaderValue(QVector3D(luma_coeffs[0], luma_coeffs[1], luma_coeffs[2]), NodeParam::kVec3));
|
||||
@@ -85,7 +85,7 @@ void WaveformScope::DrawScope(Renderer::TexturePtr managed_tex, QVariant pipelin
|
||||
float waveform_end_dim_x = (width() - 1.0) - waveform_start_dim_x;
|
||||
|
||||
// Draw line overlays
|
||||
QPainter p(this);
|
||||
QPainter p(inner_widget());
|
||||
QFont font;
|
||||
font.setPixelSize(10);
|
||||
QFontMetrics font_metrics = QFontMetrics(font);
|
||||
|
||||
@@ -392,6 +392,7 @@ FramePtr ViewerWidget::DecodeCachedImage(const QString &fn, const rational& time
|
||||
|
||||
void ViewerWidget::DecodeCachedImage(RenderTicketPtr ticket, const QString &fn, const rational& time) const
|
||||
{
|
||||
ticket->Start();
|
||||
ticket->Finish(QVariant::fromValue(DecodeCachedImage(fn, time)), false);
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ void ViewerDisplayWidget::SetImage(FramePtr in_buffer)
|
||||
|| texture_->format() != in_buffer->format()) {
|
||||
texture_ = renderer()->CreateTexture(in_buffer->video_params(), in_buffer->data(), in_buffer->linesize_pixels());
|
||||
} else {
|
||||
texture_->Upload(in_buffer->data(), in_buffer->linesize_bytes());
|
||||
texture_->Upload(in_buffer->data(), in_buffer->linesize_pixels());
|
||||
}
|
||||
|
||||
doneCurrent();
|
||||
@@ -298,8 +298,7 @@ void ViewerDisplayWidget::OnPaint()
|
||||
}
|
||||
|
||||
// Draw texture through color transform
|
||||
renderer()->BlitColorManaged(color_service(), texture_, VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F));
|
||||
|
||||
renderer()->BlitColorManaged(color_service(), texture_, VideoParams(width(), height(), PixelFormat::PIX_FMT_RGBA16F), true);
|
||||
}
|
||||
|
||||
QTransform world_transform = GenerateWorldTransform();
|
||||
@@ -312,14 +311,14 @@ void ViewerDisplayWidget::OnPaint()
|
||||
|
||||
gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time));
|
||||
|
||||
QPainter p(this);
|
||||
QPainter p(inner_widget());
|
||||
p.setWorldTransform(world_transform);
|
||||
gizmos_->DrawGizmos(gizmo_db_, &p, QVector2D(GetTexturePosition(size())), size());
|
||||
}
|
||||
|
||||
// Draw action/title safe areas
|
||||
if (safe_margin_.is_enabled()) {
|
||||
QPainter p(this);
|
||||
QPainter p(inner_widget());
|
||||
p.setWorldTransform(world_transform);
|
||||
|
||||
p.setPen(Qt::lightGray);
|
||||
|
||||
Reference in New Issue
Block a user