#include "cinder/app/App.h" #include "cinder/app/RendererGl.h" #include "cinder/gl/gl.h" using namespace ci; using namespace ci::app; using namespace std; class CirclesApp : public App { public: void setup() override; void update() override; void draw() override; private: gl::BatchRef mBatch; gl::VboRef mInstances; std::vector<vec4> mData; }; void CirclesApp::setup() { // Create the shader. const char *vertShader = R"V0G0N( #version 150 uniform mat4 ciModelViewProjection; in vec4 ciPosition; in vec2 ciTexCoord0; in vec4 ciColor; in vec4 iData; // per instance: xy = center, z = radius, w = width out vec4 vertColor; void main( void ) { vertColor = ciColor; vec4 position = ciPosition; position.xy *= mix( iData.z, iData.w / 0.9, ciTexCoord0.x ); // Vertices on inner radius have coordinate x = 1 and radius 0.9, so compensate for that. position.xy += iData.xy; gl_Position = ciModelViewProjection * position; } )V0G0N"; const char *fragShader = R"V0G0N( #version 150 in vec4 vertColor; out vec4 fragColor; void main( void ) { fragColor = pow( vertColor, vec4( 1.0 / 2.2 ) ); } )V0G0N"; gl::GlslProgRef glsl = gl::GlslProg::create( vertShader, fragShader ); // Create ring mesh. With a width of 0.1, we have an inner radius of 0.9. See shader. gl::VboMeshRef mesh = gl::VboMesh::create( geom::Ring().radius( 1.0f ).width( 0.1f ).subdivisions( 128 ) ); // Create ring instances. mData.clear(); mData.emplace_back( 0, 0, 150.0f, 144.0f ); // x,y = center, z = outer radius, w = inner radius mData.emplace_back( 0, 0, 140.0f, 135.0f ); mData.emplace_back( 0, 0, 130.0f, 126.0f ); mData.emplace_back( 0, 0, 120.0f, 117.0f ); mData.emplace_back( 0, 0, 110.0f, 108.0f ); mInstances = gl::Vbo::create( GL_ARRAY_BUFFER, mData.size() * sizeof( vec4 ), mData.data(), GL_STATIC_DRAW ); // Describe the layout of the instance data. geom::BufferLayout layout; layout.append( geom::Attrib::CUSTOM_0, sizeof( vec4 ) / sizeof( float ), 0, 0, 1 /* per instance */ ); // Append instance data to mesh. mesh->appendVbo( layout, mInstances ); // Create batch, combining the mesh, the shader and a full description of the data. mBatch = gl::Batch::create( mesh, glsl, { { geom::Attrib::CUSTOM_0, "iData" } } ); } void CirclesApp::update() { } void CirclesApp::draw() { gl::clear(); gl::ScopedColor scpColor( 1, 1, 1 ); gl::ScopedModelMatrix scpModel; gl::translate( getWindowSize() / 2 ); mBatch->drawInstanced( mData.size() ); } CINDER_APP( CirclesApp, RendererGl( RendererGl::Options().msaa( 32 ) ) )