Merge branch 'blender-v3.1-release'
This commit is contained in:
commit
259f4e50ef
|
@ -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
|
||||
|
|
|
@ -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__*/
|
Loading…
Reference in New Issue