diff --git a/CMakeLists.txt b/CMakeLists.txt index 6962296..73a8380 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 2.8) add_definitions(-std=c++1y) +find_package(boost) +include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) + add_subdirectory("contrib") add_subdirectory("lib") add_subdirectory("src") diff --git a/contrib/moggle b/contrib/moggle index bb8a9ab..8845eef 160000 --- a/contrib/moggle +++ b/contrib/moggle @@ -1 +1 @@ -Subproject commit bb8a9ab41750803845dfc540b183d2647e2da8e8 +Subproject commit 8845eefc8631ea9bdfc01ed5ff6b598cd65b69ce diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 794f022..e3a81f5 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -2,7 +2,7 @@ file(GLOB sources "*.cpp") file(GLOB headers "*.hpp") -set(libs common ${JCLWrapper_LIBRARIES} ${JNSAppWrapper_LIBRARIES} ${ImageStreams_LIBRARIES} moggle_xxx) +set(libs common ${JCLWrapper_LIBRARIES} ${JNSAppWrapper_LIBRARIES} ${ImageStreams_LIBRARIES} moggle moggle_xxx) add_library(common ${headers} ${sources}) target_link_libraries(common ${libs}) diff --git a/lib/app.cpp b/lib/app.cpp index 8f44be8..82a05a1 100644 --- a/lib/app.cpp +++ b/lib/app.cpp @@ -25,6 +25,33 @@ std::vector quad = { static const GLsizei FBO_SIZE = 1024; +Parameters::Parameters(cl::Context& cl_context, std::initializer_list x) +: cl_context(cl_context) +, parameters(x) +, cl_parameter_buffer(cl_context, CL_MEM_USE_HOST_PTR, parameters.size() * sizeof(float), ¶meters[0]) +{} + +void Parameters::resize(size_t n){ + parameters.resize(n); + cl_parameter_buffer = cl::Buffer(cl_context, CL_MEM_USE_HOST_PTR, parameters.size() * sizeof(float), ¶meters[0]); +} + +size_t Parameters::size() const { + return parameters.size(); +} + +float & Parameters::operator[](size_t n){ + return parameters[n]; +} + +float Parameters::operator[](size_t n) const { + return parameters[n]; +} + +cl::Buffer const & Parameters::get_cl() const { + return cl_parameter_buffer; +} + App::App(GLContext& gl_context) : gl_vbo(create_vbo(generate_random_points(N))) , gl_vao(create_vao(gl_vbo)) @@ -32,13 +59,14 @@ App::App(GLContext& gl_context) , gl_quad_vao(create_vao(gl_quad_vbo)) , gl_points_program(create_shader_from_files("Points.vsh", "Points.fsh")) , gl_texture_program(create_shader_from_files("Texture.vsh", "Texture.fsh")) -, gl_fbo(moggle::fbo::create_default(FBO_SIZE, FBO_SIZE)) +, gl_fbo(moggle::create_default_fbo(FBO_SIZE, FBO_SIZE)) , cl_context(create_shared_cl_context(gl_context)) , cl_device(cl_context.getInfo().front()) , cl_queue(cl_context, cl_device) -, cl_buffer(cl_context, 0, gl_vbo.id) +, cl_buffer(cl_context, 0, gl_vbo.get_id()) , cl_program(create_cl_program("Kernel.cl")) , k_update(cl_program, "update") +, parameters(cl_context, {10.962073, 31.211250, 1.537946, 0.013040}) { moggle::gl::clear_color(0.0f, 0.0f, 0.0f, 1.0f); @@ -55,15 +83,38 @@ void App::draw(std::function bind, std::function flush){ auto dt = 1/60.0; time += dt; + static quaternion speed(1, 0, 0, 0); + static int frame = 0; + + if(frame > 200){ + static bool dir = true; + frame = 0; + if(dir) { + speed = quaternion{40.0, 0, 0.1, 0}; + dir = false; + } else { + speed = quaternion{40.0, 0.1, 0, 0}; + dir = true; + } + speed = normalize(speed); + } + frame++; + rotation = speed * rotation; + auto const mat = quaternion_to_R3_rotation(normalize(rotation)); + // OpenCL update - k_update(cl_queue, N, p_s, p_r, p_b, p_dt, cl_buffer); + cl::checky(k_update(cl_queue, N, parameters.get_cl(), cl_buffer)); cl::checky(cl_queue.finish()); // OpenGL to fbo gl_fbo.bind(); moggle::gl::viewport(0, 0, FBO_SIZE, FBO_SIZE); + if(clear){ + gl_fbo.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } gl_points_program.use(); + gl_points_program.uniform>("modelmatrix").set(mat); gl_vao.bind(); moggle::gl::draw_arrays(GL_POINTS, 0, N); @@ -76,6 +127,7 @@ void App::draw(std::function bind, std::function flush){ gl_fbo.get_texture().bind(GL_TEXTURE_2D); gl_texture_program.uniform("tex").set(0); gl_texture_program.uniform("maxf").set(maxf); + gl_texture_program.uniform("gamma").set(gamma); gl_quad_vao.bind(); moggle::gl::draw_arrays(GL_TRIANGLE_STRIP, 0, 4); diff --git a/lib/app.hpp b/lib/app.hpp index e24be02..2173f97 100644 --- a/lib/app.hpp +++ b/lib/app.hpp @@ -1,6 +1,7 @@ #pragma once #include "fbo.hpp" +#include "quaternion.hpp" #include #include #include @@ -9,6 +10,8 @@ #include #include +#include + // Used for the bare points using GLPoint = moggle::hvector4; @@ -18,16 +21,39 @@ struct Vertex { moggle::vector2 tex; }; +struct Parameters{ + Parameters(cl::Context& cl_context, std::initializer_list x); + void resize(size_t n); + size_t size() const; + + auto begin() { return parameters.begin(); } + auto end() { return parameters.end(); } + + auto begin() const { return parameters.begin(); } + auto end() const { return parameters.end(); } + + float & operator[](size_t n); + float operator[](size_t n) const; + + cl::Buffer const & get_cl() const; + +private: + cl::Context& cl_context; + std::vector parameters; + cl::Buffer cl_parameter_buffer; +}; + struct App { size_t W = 128; size_t H = 128; - size_t N = 1 << 18; + size_t N = 1 << 19; float time = 0; - float p_s = 10.962073; - float p_r = 31.211250; - float p_b = 1.537946; - float p_dt = 0.013040; - float maxf = 500; + float maxf = 10; + float gamma = 2; + bool clear = false; + + using quaternion = boost::math::quaternion; + quaternion rotation = quaternion(1, 0, 0, 0); App(GLContext & gl_context); void draw(std::function bind, std::function flush); @@ -50,4 +76,7 @@ private: KernelOp k_update; cl::Program create_cl_program(std::string file); + +public: + Parameters parameters; }; diff --git a/lib/fbo.hpp b/lib/fbo.hpp index 4debf14..77c10d2 100644 --- a/lib/fbo.hpp +++ b/lib/fbo.hpp @@ -1,91 +1,18 @@ #pragma once #include +#include #include "renderbuffer.hpp" #include "texture.hpp" -#include - -/* - * One can attach either an external renderbuffer/texture, or move one into fbo - * In the latter case, the fbo will own the renderbuffer/texture - * - * Attachment can be one of: GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, or GL_STENCIL_ATTACHMENT - */ - namespace moggle { -struct fbo { - explicit fbo(bool create_now = false) { - if(create_now) create(); - } - - ~fbo() { destroy(); } - - fbo(fbo const &) = delete; - fbo & operator=(fbo const&) = delete; - - fbo(fbo && r) : id(r.id) { r.id = 0; } - fbo & operator=(fbo && r) { std::swap(id, r.id); return *this; } - - bool created() const { return id; } - explicit operator bool() const { return created(); } - - void create(){ if(!id) gl::generate_framebuffers(1, &id); } - void destroy(){ gl::delete_renderbuffers(1, &id); id = 0; } - - void bind() { - create(); - gl::bind_framebuffer(GL_FRAMEBUFFER, id); - } - - GLuint get_id() const { - return id; - } - - // Only well defined if the fbo owns the texture - texture & get_texture() { - return textures.front(); - } - - void attach(GLenum attachment, renderbuffer const & rb){ - bind(); - gl::framebuffer_renderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rb.get_id()); - } - - void attach(GLenum attachment, renderbuffer && rb){ - renderbuffers.push_back(std::move(rb)); - attach(attachment, renderbuffers.back()); - } - - void attach(GLenum attachment, GLenum textarget, texture const & t){ - bind(); - gl::framebuffer_texture_2d(GL_FRAMEBUFFER, attachment, textarget, t.get_id(), 0); - } - - void attach(GLenum attachment, GLenum textarget, texture && t){ - textures.push_back(std::move(t)); - attach(attachment, textarget, textures.back()); - } - - void clear(GLenum bufferbits){ - bind(); - gl::clear(bufferbits); - } - - static fbo create_default(GLsizei width, GLsizei height){ - fbo f; - f.attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture::create(width, height, GL_RGBA32F)); - f.attach(GL_DEPTH_ATTACHMENT, renderbuffer::create(width, height, 1, GL_DEPTH_COMPONENT16)); - f.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - return f; - } - -private: - std::vector renderbuffers; - std::vector textures; - - GLuint id = 0; -}; +inline fbo create_default_fbo(GLsizei width, GLsizei height){ + fbo f; + f.attach(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, create_texture(width, height, GL_RGBA32F)); + f.attach(GL_DEPTH_ATTACHMENT, create_renderbuffer(width, height, 1, GL_DEPTH_COMPONENT16)); + f.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + return f; +} } diff --git a/lib/quaternion.hpp b/lib/quaternion.hpp new file mode 100644 index 0000000..c54ff67 --- /dev/null +++ b/lib/quaternion.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include +#include + +// Will create a R3 rotation if the quaternion is normalized +// Typical use is: mat4 matrix = quaternion_to_R3_rotation(normalize(foo)); +template +moggle::matrix4 quaternion_to_R3_rotation(boost::math::quaternion const & q){ + using ::std::numeric_limits; + + T a = q.R_component_1(); + T b = q.R_component_2(); + T c = q.R_component_3(); + T d = q.R_component_4(); + + T aa = a*a; + T ab = a*b; + T ac = a*c; + T ad = a*d; + T bb = b*b; + T bc = b*c; + T bd = b*d; + T cc = c*c; + T cd = c*d; + T dd = d*d; + + return { + (aa+bb-cc-dd), 2*(-ad+bc), 2*(ac+bd), 0, + 2*(ad+bc), (aa-bb+cc-dd), 2*(-ab+cd), 0, + 2*(-ac+bd), 2*(ab+cd), (aa-bb-cc+dd), 0, + 0, 0, 0, 1 + }; +} + +namespace boost { + namespace math { + template + quaternion normalize(quaternion q){ + return q /= abs(q); + } + } +} diff --git a/lib/renderbuffer.hpp b/lib/renderbuffer.hpp index 857b098..d574c4f 100644 --- a/lib/renderbuffer.hpp +++ b/lib/renderbuffer.hpp @@ -1,57 +1,14 @@ #pragma once -#include +#include namespace moggle { -struct renderbuffer { - explicit renderbuffer(bool create_now = false) { - if(create_now) create(); - } - - ~renderbuffer() { destroy(); } - - renderbuffer(renderbuffer const &) = delete; - renderbuffer & operator=(renderbuffer const&) = delete; - - renderbuffer(renderbuffer && r) : id(r.id) { r.id = 0; } - renderbuffer & operator=(renderbuffer && r) { std::swap(id, r.id); return *this; } - - bool created() const { return id; } - explicit operator bool() const { return created(); } - - void create(){ if(!id) gl::generate_renderbuffers(1, &id); } - void destroy(){ gl::delete_renderbuffers(1, &id); id = 0; } - - void bind() { - create(); - gl::bind_renderbuffer(GL_RENDERBUFFER, id); - } - - GLuint get_id() const { - return id; - } - - void storage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height){ - bind(); - gl::renderbuffer_storage(target, internalformat, width, height); - } - - void storage_multisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height){ - bind(); - // TODO: wrap this call - glRenderbufferStorageMultisample(target, samples, internalformat, width, height); - } - - static renderbuffer create(GLsizei width, GLsizei height, GLsizei samples = 1, GLenum format = GL_RGBA4){ - renderbuffer r; - if(samples <= 1) r.storage(GL_RENDERBUFFER, format, width, height); - else r.storage_multisample(GL_RENDERBUFFER, samples, format, width, height); - return r; - } - -private: - GLuint id = 0; -}; +inline renderbuffer create_renderbuffer(GLsizei width, GLsizei height, GLsizei samples = 1, GLenum format = GL_RGBA4){ + renderbuffer r; + if(samples <= 1) r.storage(GL_RENDERBUFFER, format, width, height); + else r.storage_multisample(GL_RENDERBUFFER, samples, format, width, height); + return r; +} } diff --git a/lib/texture.hpp b/lib/texture.hpp index dc457f4..9284008 100644 --- a/lib/texture.hpp +++ b/lib/texture.hpp @@ -1,62 +1,14 @@ #pragma once -#include -#include - -/* - * NOTE: - * in glTexImage2D, border MUST be 0, so this parameter is left out in this interface. - */ +#include namespace moggle { -struct texture { - explicit texture(bool create_now = false) { - if(create_now) create(); - } - - ~texture() { destroy(); } - - texture(texture const &) = delete; - texture & operator=(texture const&) = delete; - - texture(texture && t) : id(t.id) { t.id = 0; } - texture & operator=(texture && t) { std::swap(id, t.id); return *this; } - - bool created() const { return id; } - explicit operator bool() const { return created(); } - - void create(){ if(!id) gl::generate_textures(1, &id); } - void destroy(){ gl::delete_textures(1, &id); id = 0; } - - void bind(GLenum target) { - create(); - gl::bind_texture(target, id); - } - - GLuint get_id() const { return id; } - - template - void image_2d(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLenum format, const T * data){ - bind(target); - auto type = gl_type_traits::gl_constant; - gl::texture_image_2d(target, level, internalformat, width, height, 0, format, type, data); - } - - void image_2d(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, std::nullptr_t){ - bind(target); - gl::texture_image_2d(target, level, internalformat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - } - - //! creates empty texture - static texture create(GLsizei width, GLsizei height, GLint internalformat = GL_RGBA, GLenum target = GL_TEXTURE_2D){ - texture t; - t.image_2d(target, 0, internalformat, width, height, nullptr); - return t; - } - -private: - GLuint id = 0; -}; +//! creates empty texture +inline texture create_texture(GLsizei width, GLsizei height, GLint internalformat = GL_RGBA, GLenum target = GL_TEXTURE_2D){ + texture t; + t.image_2d(target, 0, internalformat, width, height, nullptr); + return t; +} } diff --git a/resources/Kernel.cl b/resources/Kernel.cl index 425c192..3a1cbf7 100644 --- a/resources/Kernel.cl +++ b/resources/Kernel.cl @@ -1,7 +1,12 @@ -kernel void update(float s, float r, float b, float dt, __global float4* buffer){ +kernel void update(__constant float* p, __global float4 * buffer){ size_t i = get_global_id(0); + const float s = p[0]; + const float r = p[1]; + const float b = p[2]; + const float dt = p[3]; + const float4 w = buffer[i]; float4 v = w; @@ -9,6 +14,9 @@ kernel void update(float s, float r, float b, float dt, __global float4* buffer) v.y += dt * (w.x * (r - w.z) - w.y); v.z += dt * (w.x * w.y - b * w.z); +// if(sin(0.1 * v.x) > 0.3){ +// v *= 1.0012f; +// } + buffer[i] = v; } - diff --git a/resources/Points.vsh b/resources/Points.vsh index e6ac4cb..b755604 100644 --- a/resources/Points.vsh +++ b/resources/Points.vsh @@ -1,10 +1,13 @@ #version 330 in vec4 position; +uniform mat4 modelmatrix; out float mx; void main(){ - gl_Position = vec4(1); - gl_Position.xy = 0.04*position.xy; + gl_Position = 0.04*modelmatrix*(position - vec4(0.0, 0.0, 25.0, 0.0)); + + // reset depth + gl_Position.zw = vec2(1.0); mx = cos(0.1337*position.z); } diff --git a/resources/Texture.fsh b/resources/Texture.fsh index 142d627..ae2f6af 100644 --- a/resources/Texture.fsh +++ b/resources/Texture.fsh @@ -2,11 +2,12 @@ uniform sampler2D tex; uniform float maxf; +uniform float gamma; in vec2 tex_coord_; out vec4 fragColor; void main(){ - fragColor = sqrt(texture(tex, tex_coord_) / maxf); + fragColor = pow(texture(tex, tex_coord_) / (maxf * gamma), vec4(1.0 / gamma)); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d883213..9c1142d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,7 +3,7 @@ set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) file(GLOB sources "*.cpp") -set(libs common ${JCLWrapper_LIBRARIES} ${JNSAppWrapper_LIBRARIES} ${ImageStreams_LIBRARIES} moggle_xxx) +set(libs common ${BOOST_LIBRARIES} ${JCLWrapper_LIBRARIES} ${JNSAppWrapper_LIBRARIES} ${ImageStreams_LIBRARIES} moggle_xxx) message(STATUS "Linking against the following libraries: ${libs}") foreach(source ${sources}) diff --git a/src/main.cpp b/src/main.cpp index 5ff27de..6c1818d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,16 +22,14 @@ int main() { } }); -// const float s = 10.962073; -// const float r = 31.211250; -// const float b = 1.537946; - app.create_window({{ - {"s", 10.962073, 9, 13, [&](double x){ a->p_s = x; }}, - {"r", 31.211250, 30, 32, [&](double x){ a->p_r = x; }}, - {"b", 1.537946, 0.0001, 3, [&](double x){ a->p_b = x; }}, - {"dt", 0.013040, 0.0001, 0.03, [&](double x){ a->p_dt = x; }}, - {"max", 500, 0.1, 50000, [&](double x){ a->maxf = x; }}, + {"s", 10.962073, 9, 13, [&](double x){ a->parameters[0] = x; }}, + {"r", 31.211250, 30, 32, [&](double x){ a->parameters[1] = x; }}, + {"b", 1.537946, 0.0001, 3, [&](double x){ a->parameters[2] = x; }}, + {"dt", 0.013040, 0.0001, 0.03, [&](double x){ a->parameters[3] = x; }}, + {"max", 20, 0.1, 250, [&](double x){ a->maxf = x*x; }}, + {"gamma", 2, 0.1, 10, [&](double x){ a->gamma = x; }}, + {"clear", 1, 0, 2, [&](double x){ a->clear = (x >= 1); }}, }}); app.run();