summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/compute/example/opengl_sphere.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/compute/example/opengl_sphere.cpp')
-rw-r--r--src/boost/libs/compute/example/opengl_sphere.cpp242
1 files changed, 242 insertions, 0 deletions
diff --git a/src/boost/libs/compute/example/opengl_sphere.cpp b/src/boost/libs/compute/example/opengl_sphere.cpp
new file mode 100644
index 00000000..38999f34
--- /dev/null
+++ b/src/boost/libs/compute/example/opengl_sphere.cpp
@@ -0,0 +1,242 @@
+//---------------------------------------------------------------------------//
+// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
+//
+// Distributed under the Boost Software License, Version 1.0
+// See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt
+//
+// See http://boostorg.github.com/compute for more information.
+//---------------------------------------------------------------------------//
+
+#include <iostream>
+#include <algorithm>
+
+#include <GL/gl.h>
+
+#include <vtkActor.h>
+#include <vtkCamera.h>
+#include <vtkgl.h>
+#include <vtkInteractorStyleSwitch.h>
+#include <vtkMapper.h>
+#include <vtkObjectFactory.h>
+#include <vtkOpenGLExtensionManager.h>
+#include <vtkOpenGLRenderWindow.h>
+#include <vtkProperty.h>
+#include <vtkRenderer.h>
+#include <vtkRenderWindow.h>
+#include <vtkRenderWindowInteractor.h>
+#include <vtkSmartPointer.h>
+
+#include <boost/compute/system.hpp>
+#include <boost/compute/algorithm/iota.hpp>
+#include <boost/compute/interop/opengl.hpp>
+#include <boost/compute/interop/vtk.hpp>
+#include <boost/compute/utility/dim.hpp>
+#include <boost/compute/utility/source.hpp>
+
+namespace compute = boost::compute;
+
+// tesselates a sphere with radius, phi_slices, and theta_slices. returns
+// a shared opencl/opengl buffer containing the vertex data.
+compute::opengl_buffer tesselate_sphere(float radius,
+ size_t phi_slices,
+ size_t theta_slices,
+ compute::command_queue &queue)
+{
+ using compute::dim;
+
+ const compute::context &context = queue.get_context();
+
+ const size_t vertex_count = phi_slices * theta_slices;
+
+ // create opengl buffer
+ GLuint vbo;
+ vtkgl::GenBuffersARB(1, &vbo);
+ vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, vbo);
+ vtkgl::BufferDataARB(vtkgl::ARRAY_BUFFER,
+ sizeof(float) * 4 * vertex_count,
+ NULL,
+ vtkgl::STREAM_DRAW);
+ vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, 0);
+
+ // create shared opengl/opencl buffer
+ compute::opengl_buffer vertex_buffer(context, vbo);
+
+ // tesselate_sphere kernel source
+ const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
+ __kernel void tesselate_sphere(float radius,
+ uint phi_slices,
+ uint theta_slices,
+ __global float4 *vertex_buffer)
+ {
+ const uint phi_i = get_global_id(0);
+ const uint theta_i = get_global_id(1);
+
+ const float phi = phi_i * 2.f * M_PI_F / phi_slices;
+ const float theta = theta_i * 2.f * M_PI_F / theta_slices;
+
+ float4 v;
+ v.x = radius * cos(theta) * cos(phi);
+ v.y = radius * cos(theta) * sin(phi);
+ v.z = radius * sin(theta);
+ v.w = 1.f;
+
+ vertex_buffer[phi_i*phi_slices+theta_i] = v;
+ }
+ );
+
+ // build tesselate_sphere program
+ compute::program program =
+ compute::program::create_with_source(source, context);
+ program.build();
+
+ // setup tesselate_sphere kernel
+ compute::kernel kernel(program, "tesselate_sphere");
+ kernel.set_arg<compute::float_>(0, radius);
+ kernel.set_arg<compute::uint_>(1, phi_slices);
+ kernel.set_arg<compute::uint_>(2, theta_slices);
+ kernel.set_arg(3, vertex_buffer);
+
+ // acqurire buffer so that it is accessible to OpenCL
+ compute::opengl_enqueue_acquire_buffer(vertex_buffer, queue);
+
+ // execute tesselate_sphere kernel
+ queue.enqueue_nd_range_kernel(
+ kernel, dim(0, 0), dim(phi_slices, theta_slices), dim(1, 1)
+ );
+
+ // release buffer so that it is accessible to OpenGL
+ compute::opengl_enqueue_release_buffer(vertex_buffer, queue);
+
+ return vertex_buffer;
+}
+
+// simple vtkMapper subclass to render the tesselated sphere on the gpu.
+class gpu_sphere_mapper : public vtkMapper
+{
+public:
+ vtkTypeMacro(gpu_sphere_mapper, vtkMapper)
+
+ static gpu_sphere_mapper* New()
+ {
+ return new gpu_sphere_mapper;
+ }
+
+ void Render(vtkRenderer *renderer, vtkActor *actor)
+ {
+ if(!m_initialized){
+ Initialize(renderer, actor);
+ m_initialized = true;
+ }
+
+ if(!m_tesselated){
+ m_vertex_count = m_phi_slices * m_theta_slices;
+
+ // tesselate sphere
+ m_vertex_buffer = tesselate_sphere(
+ m_radius, m_phi_slices, m_theta_slices, m_command_queue
+ );
+
+ // ensure tesselation is finished (seems to be required on AMD)
+ m_command_queue.finish();
+
+ // set tesselated flag to true
+ m_tesselated = true;
+ }
+
+ // draw sphere
+ glEnableClientState(GL_VERTEX_ARRAY);
+ vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, m_vertex_buffer.get_opengl_object());
+ glVertexPointer(4, GL_FLOAT, sizeof(float)*4, 0);
+ glDrawArrays(GL_POINTS, 0, m_vertex_count);
+ }
+
+ void Initialize(vtkRenderer *renderer, vtkActor *actor)
+ {
+ // initialize opengl extensions
+ vtkOpenGLExtensionManager *extensions =
+ static_cast<vtkOpenGLRenderWindow *>(renderer->GetRenderWindow())
+ ->GetExtensionManager();
+ extensions->LoadExtension("GL_ARB_vertex_buffer_object");
+
+ // initialize opencl/opengl shared context
+ m_context = compute::opengl_create_shared_context();
+ compute::device device = m_context.get_device();
+ std::cout << "device: " << device.name() << std::endl;
+
+ // create command queue for the gpu device
+ m_command_queue = compute::command_queue(m_context, device);
+ }
+
+ double* GetBounds()
+ {
+ static double bounds[6];
+ bounds[0] = -m_radius; bounds[1] = m_radius;
+ bounds[2] = -m_radius; bounds[3] = m_radius;
+ bounds[4] = -m_radius; bounds[5] = m_radius;
+ return bounds;
+ }
+
+protected:
+ gpu_sphere_mapper()
+ {
+ m_radius = 5.0f;
+ m_phi_slices = 100;
+ m_theta_slices = 100;
+ m_initialized = false;
+ m_tesselated = false;
+ }
+
+private:
+ float m_radius;
+ int m_phi_slices;
+ int m_theta_slices;
+ int m_vertex_count;
+ bool m_initialized;
+ bool m_tesselated;
+ compute::context m_context;
+ compute::command_queue m_command_queue;
+ compute::opengl_buffer m_vertex_buffer;
+};
+
+int main(int argc, char *argv[])
+{
+ // create gpu sphere mapper
+ vtkSmartPointer<gpu_sphere_mapper> mapper =
+ vtkSmartPointer<gpu_sphere_mapper>::New();
+
+ // create actor for gpu sphere mapper
+ vtkSmartPointer<vtkActor> actor =
+ vtkSmartPointer<vtkActor>::New();
+ actor->GetProperty()->LightingOff();
+ actor->GetProperty()->SetInterpolationToFlat();
+ actor->SetMapper(mapper);
+
+ // create render window
+ vtkSmartPointer<vtkRenderer> renderer =
+ vtkSmartPointer<vtkRenderer>::New();
+ renderer->SetBackground(.1, .2, .31);
+ vtkSmartPointer<vtkRenderWindow> renderWindow =
+ vtkSmartPointer<vtkRenderWindow>::New();
+ renderWindow->SetSize(800, 600);
+ renderWindow->AddRenderer(renderer);
+ vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
+ vtkSmartPointer<vtkRenderWindowInteractor>::New();
+ vtkInteractorStyleSwitch *interactorStyle =
+ vtkInteractorStyleSwitch::SafeDownCast(
+ renderWindowInteractor->GetInteractorStyle()
+ );
+ interactorStyle->SetCurrentStyleToTrackballCamera();
+ renderWindowInteractor->SetRenderWindow(renderWindow);
+ renderer->AddActor(actor);
+
+ // render
+ renderer->ResetCamera();
+ vtkCamera *camera = renderer->GetActiveCamera();
+ camera->Elevation(-90.0);
+ renderWindowInteractor->Initialize();
+ renderWindow->Render();
+ renderWindowInteractor->Start();
+
+ return 0;
+}