├── LICENSE
├── README.md
├── cinderblock.png
├── cinderblock.xml
└── src
├── Composer.h
├── composer
├── Layer.h
├── Postprocess.h
└── Scene.h
└── postprocessing
└── StockShaderProcesses.h
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, Stephen Schieberl
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Cinder-Composer
2 |
3 | ALPHA
4 |
5 | A header only 'photoshop' style scene graph for composing scenes, objects, rasterised layers and post processing effects.
6 |
7 | TODO: add examples + documentation.
8 |
9 |
10 |
--------------------------------------------------------------------------------
/cinderblock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felixfaire/Cinder-Composer/386240d8c319102079ceaca3b36b939fc6e86541/cinderblock.png
--------------------------------------------------------------------------------
/cinderblock.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 | src
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Composer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // ====== Composer ====== //
4 | #include "composer/Scene.h"
5 | #include "composer/Postprocess.h"
6 | #include "composer/Layer.h"
7 |
8 |
--------------------------------------------------------------------------------
/src/composer/Layer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Layer.h
3 | //
4 | // Created by Felix Faire on 18/01/2017.
5 | //
6 | //
7 |
8 | #ifndef Layer_h
9 | #define Layer_h
10 |
11 |
12 | #include "cinder/app/App.h"
13 | #include "cinder/app/RendererGl.h"
14 | #include "cinder/gl/gl.h"
15 |
16 | using namespace ci;
17 | using namespace ci::app;
18 |
19 | class Layer;
20 | typedef std::shared_ptr LayerRef;
21 |
22 | /**
23 | This base class represents a layer in
24 | a renderable scene. This layer can be given a scenes
25 | postprocessing fx and even other layers to render
26 | */
27 | class Layer
28 | {
29 | public:
30 |
31 | static LayerRef create( int width, int height, int msaa = 0 )
32 | {
33 | return std::make_shared( width, height, msaa );
34 | }
35 |
36 | Layer( int width , int height, int msaa = 0 )
37 | {
38 | mFbo = gl::Fbo::create( width, height, gl::Fbo::Format().samples( msaa ) );
39 | }
40 |
41 | void update()
42 | {
43 | for (const auto& scene : mScenes)
44 | scene->update();
45 |
46 | renderInternal();
47 | }
48 |
49 | void renderInternal()
50 | {
51 | if (mAlpha.value() == 0.0f)
52 | return;
53 |
54 | for (const auto& layer : mLayers)
55 | layer->renderInternal();
56 |
57 | {
58 | gl::ScopedFramebuffer frameScp( mFbo );
59 | gl::ScopedViewport viewScp( mFbo->getSize() );
60 |
61 | if (mFade == 0.0f)
62 | {
63 | gl::clear( ColorA( 0.0f, 0.0f, 0.0f, 0.0f ) );
64 | }
65 | else
66 | {
67 | gl::ScopedGlslProg colScp( gl::getStockShader( gl::ShaderDef().color() ) );
68 | gl::color( 0.0f, 0.0f, 0.0f, 1.0f - mFade );
69 | gl::drawSolidRect( getWindowBounds() );
70 | }
71 |
72 | for (const auto& layer : mLayers)
73 | layer->drawTex( getWindowBounds() );
74 |
75 | for (const auto& scene : mScenes)
76 | scene->drawInternal();
77 |
78 | }
79 |
80 | }
81 |
82 | void drawTex( Rectf bounds ) const
83 | {
84 | if (mAlpha == 0.0f)
85 | return;
86 |
87 | gl::ScopedBlendAlpha alphaScp;
88 | gl::color( 1.0f, 1.0f, 1.0f, mAlpha.value() );
89 | gl::draw( mFbo->getColorTexture(), bounds );
90 | }
91 |
92 | void drawFinalTex( Rectf bounds )
93 | {
94 | if (mAlpha == 0.0f)
95 | return;
96 |
97 | gl::FboRef finalTexture = mFbo;
98 |
99 | if (mPostprocesses.size() > 0)
100 | {
101 | postProcessTexture();
102 | finalTexture = mFinalFbo;
103 | }
104 |
105 | gl::ScopedBlendAlpha alphaScp;
106 | gl::color( 1.0f, 1.0f, 1.0f, mAlpha.value() );
107 | gl::draw( finalTexture->getColorTexture(), bounds );
108 | }
109 |
110 | void postProcessTexture()
111 | {
112 | // Copy Fbo into post pipeline
113 | {
114 | gl::ScopedFramebuffer fboScp( mFinalFbo );
115 | gl::ScopedViewport viewScp( mFinalFbo->getSize() );
116 | gl::ScopedGlslProg glScp( gl::getStockShader( gl::ShaderDef().texture() ));
117 | gl::ScopedTextureBind texScp( mFbo->getColorTexture() );
118 | gl::ScopedMatrices matScp;
119 | gl::setMatricesWindow( mFinalFbo->getSize() );
120 | gl::ScopedBlendAlpha alphaScp;
121 | gl::clear();
122 |
123 | gl::drawSolidRect( Rectf(0, 0, mFinalFbo->getWidth(), mFinalFbo->getHeight()) );
124 | }
125 |
126 | // Process all post activities
127 | for (const auto& process : mPostprocesses)
128 | {
129 | process->process( mFinalFbo->getColorTexture(), mProcessFbo );
130 | std::swap( mProcessFbo, mFinalFbo );
131 | }
132 | }
133 |
134 | void addLayer( std::shared_ptr newLayer ) { mLayers.push_back( newLayer ); }
135 | void addScene( std::shared_ptr newScene ) { mScenes.push_back( newScene ); }
136 |
137 | void addPostProcess( std::shared_ptr newProcess )
138 | {
139 | mPostprocesses.push_back( newProcess );
140 |
141 | if (mProcessFbo == nullptr)
142 | {
143 | mProcessFbo = gl::Fbo::create( mFbo->getWidth(), mFbo->getHeight() );
144 | mFinalFbo = gl::Fbo::create( mFbo->getWidth(), mFbo->getHeight() );
145 | }
146 | }
147 |
148 | void showScene( int index, float duration )
149 | {
150 | CI_ASSERT( index < mScenes.size() );
151 |
152 | for (int i = 0; i < mScenes.size(); ++i)
153 | {
154 | float alpha = (index == i) ? 1.0f : 0.0f;
155 | timeline().apply( &mScenes[i]->mAlpha, alpha, duration );
156 | }
157 | }
158 |
159 | void showLayer( int index, float duration )
160 | {
161 | CI_ASSERT( index < mLayers.size() );
162 |
163 | for (int i = 0; i < mLayers.size(); ++i)
164 | {
165 | float alpha = (index == i) ? 1.0f : 0.0f;
166 | timeline().apply( &mLayers[i]->mAlpha, alpha, duration );
167 | }
168 | }
169 |
170 |
171 | Anim mAlpha = 1.0f;
172 | float mFade = 0.0f;
173 |
174 | // Optional array of other layers
175 | std::vector> mLayers;
176 |
177 | // Optional Array of scenes
178 | std::vector> mScenes;
179 |
180 | // Optional array of postprocessing stages
181 | std::vector> mPostprocesses;
182 |
183 | gl::FboRef mFbo;
184 | gl::FboRef mProcessFbo;
185 | gl::FboRef mFinalFbo;
186 | };
187 |
188 | #endif /* Layer_h */
189 |
--------------------------------------------------------------------------------
/src/composer/Postprocess.h:
--------------------------------------------------------------------------------
1 | //
2 | // Postprocess.h
3 | //
4 | // Created by Felix Faire on 18/01/2017.
5 | //
6 | //
7 |
8 | #ifndef SceneLayer_h
9 | #define SceneLayer_h
10 |
11 |
12 | #include "cinder/gl/gl.h"
13 | #include "cinder/app/App.h"
14 |
15 | using namespace ci;
16 | using namespace ci::app;
17 |
18 |
19 | /**
20 | This abstract class represents a post processing stage that can happen
21 | on a layer
22 | */
23 | class Postprocess;
24 | typedef std::shared_ptr PostprocessRef;
25 |
26 | class Postprocess
27 | {
28 | public:
29 | Postprocess(){}
30 |
31 | virtual void process( const gl::TextureRef& inputTexture, gl::FboRef& targetFbo ) = 0;
32 | };
33 |
34 | /**
35 | This class allows the simple specification of a fragment shader to do the post processing
36 | the shader must specify
37 |
38 | uniform sampler2D tex0;
39 | in vec2 TexCoord
40 | */
41 | class ShaderPostprocess;
42 | typedef std::shared_ptr ShaderPostprocessRef;
43 |
44 | class ShaderPostprocess : public Postprocess
45 | {
46 | public:
47 | ShaderPostprocess( DataSourceRef fragmentShaderSource )
48 | {
49 | CI_ASSERT(fragmentShaderSource->isFilePath());
50 |
51 | gl::GlslProg::Format fmt;
52 | fmt.vertex( getThruVertex() ).fragment( fragmentShaderSource );
53 | createShader( fmt );
54 | }
55 |
56 | ShaderPostprocess( const std::string& fragmentShaderString )
57 | {
58 | gl::GlslProg::Format fmt;
59 | fmt.vertex( getThruVertex() ).fragment( fragmentShaderString );
60 | createShader( fmt );
61 | }
62 |
63 | void process( const gl::TextureRef& texture, gl::FboRef& targetFbo ) override
64 | {
65 | CI_ASSERT(texture != nullptr);
66 | CI_ASSERT(targetFbo != nullptr);
67 | CI_ASSERT(mPostProcessShader != nullptr);
68 |
69 | gl::ScopedFramebuffer fboScp( targetFbo );
70 | gl::ScopedViewport viewScp( targetFbo->getSize() );
71 | gl::ScopedGlslProg glScp( mPostProcessShader );
72 | gl::ScopedTextureBind texScp( texture );
73 | gl::ScopedMatrices matScp;
74 | gl::setMatricesWindow( targetFbo->getSize() );
75 | gl::clear();
76 |
77 | mPostProcessShader->uniform( "tex0", 0 );
78 | updateUniforms( mPostProcessShader );
79 | gl::drawSolidRect( Rectf(0.0f, 0.0f, (float)targetFbo->getWidth(), (float)targetFbo->getHeight()) );
80 | }
81 |
82 | virtual void updateUniforms( gl::GlslProgRef& prog ) {}
83 |
84 |
85 | protected:
86 |
87 | gl::GlslProgRef mPostProcessShader;
88 |
89 | const std::string getThruVertex()
90 | {
91 | return CI_GLSL( 150,
92 |
93 | uniform mat4 ciModelViewProjection;
94 |
95 | in vec4 ciPosition;
96 | in vec2 ciTexCoord0;
97 |
98 | out vec2 TexCoord;
99 |
100 | void main()
101 | {
102 | TexCoord = ciTexCoord0;
103 | gl_Position = ciModelViewProjection * ciPosition;
104 | }
105 |
106 | );
107 | }
108 |
109 | void createShader( const gl::GlslProg::Format& fmt )
110 | {
111 | try
112 | {
113 | mPostProcessShader = gl::GlslProg::create( fmt );
114 | }
115 | catch( const std::exception& e )
116 | {
117 | console() << "PostProcess shader error: " << e.what() << std::endl;
118 | CI_ASSERT( false );
119 | }
120 | }
121 |
122 | };
123 |
124 |
125 |
126 | #endif /* SceneLayer_h */
127 |
--------------------------------------------------------------------------------
/src/composer/Scene.h:
--------------------------------------------------------------------------------
1 | //
2 | // Scene.h
3 | //
4 | // Created by Felix Faire on 18/01/2017.
5 | //
6 | //
7 |
8 | #ifndef Scene_h
9 | #define Scene_h
10 |
11 | #include "cinder/gl/gl.h"
12 | #include "cinder/Timeline.h"
13 |
14 | using namespace ci;
15 | using namespace ci::app;
16 |
17 | class Scene;
18 | typedef std::shared_ptr SceneRef;
19 |
20 | /**
21 | This abstract class contains the contents of the scene
22 | and can be rendered to a layer
23 | */
24 | class Scene
25 | {
26 | public:
27 |
28 | Scene()
29 | {
30 | }
31 |
32 | void drawInternal()
33 | {
34 | if (mAlpha != 0.0f)
35 | draw();
36 | }
37 |
38 | virtual void update() = 0;
39 | virtual void draw() = 0;
40 |
41 | Anim mAlpha = 1.0f;
42 | };
43 |
44 |
45 |
46 | #endif /* Scene_h */
47 |
--------------------------------------------------------------------------------
/src/postprocessing/StockShaderProcesses.h:
--------------------------------------------------------------------------------
1 | //
2 | // StockShaderProcesses.h
3 | //
4 | // Created by Felix Faire on 28/02/2017.
5 | //
6 | //
7 |
8 | #ifndef StockShaderProcesses_h
9 | #define StockShaderProcesses_h
10 |
11 | #include "composer/Postprocess.h"
12 |
13 |
14 | // === MIRROR =================================================================
15 |
16 | class MirrorProcess
17 | {
18 | public:
19 | static ShaderPostprocessRef create()
20 | {
21 | return std::make_shared( CI_GLSL( 400,
22 |
23 | uniform sampler2D tex0;
24 | in vec2 TexCoord;
25 | out vec4 FragColor;
26 |
27 | void main()
28 | {
29 | vec2 p = TexCoord;
30 | FragColor = texture( tex0, vec2( 0.5 - abs( (p.x - 0.5) ), p.y ) );
31 | }
32 |
33 | ));
34 | }
35 | };
36 |
37 |
38 | // === INVERT =================================================================
39 |
40 | class InvertProcess
41 | {
42 | public:
43 | static ShaderPostprocessRef create()
44 | {
45 | return std::make_shared( CI_GLSL( 400,
46 |
47 | uniform sampler2D tex0;
48 | in vec2 TexCoord;
49 | out vec4 FragColor;
50 |
51 | void main()
52 | {
53 | vec2 p = TexCoord;
54 | vec4 col = texture( tex0, p );
55 | col.xyz = vec3( 1.0 ) - col.xyz;
56 | FragColor = col;
57 | }
58 |
59 | ));
60 | }
61 | };
62 |
63 |
64 | // === GREYSCALE ==============================================================
65 |
66 | class GreyscaleProcess
67 | {
68 | public:
69 | static ShaderPostprocessRef create()
70 | {
71 | return std::make_shared( CI_GLSL( 400,
72 |
73 | uniform sampler2D tex0;
74 | in vec2 TexCoord;
75 | out vec4 FragColor;
76 |
77 | void main()
78 | {
79 | vec2 p = TexCoord;
80 | vec4 tex = texture( tex0, p );
81 | vec3 col = vec3( 0.0 );
82 |
83 | float gray = dot( tex.rgb, vec3( 0.299, 0.587, 0.114 ) );
84 |
85 | FragColor = vec4( gray, gray, gray, tex.a );
86 | }
87 |
88 | ));
89 | }
90 | };
91 |
92 |
93 | // === BLACK LEVELS ===========================================================
94 |
95 | class BlackLevelsProcess : public ShaderPostprocess
96 | {
97 | public:
98 |
99 | static std::shared_ptr create( float black = 0.0f, float white = 1.0f )
100 | {
101 | return std::make_shared( black, white );
102 | }
103 |
104 | BlackLevelsProcess( float black = 0.0f, float white = 1.0f )
105 | : ShaderPostprocess( getFragmentShader() )
106 | {
107 | }
108 |
109 | void updateUniforms( gl::GlslProgRef& prog ) override
110 | {
111 | prog->uniform( "u_black", mBlackOut );
112 | prog->uniform( "u_white", mWhiteOut );
113 | prog->uniform( "u_brightness", mBrightness );
114 | prog->uniform( "u_contrast", mContrast );
115 | }
116 |
117 | void setLevels( float blackOut, float whiteOut )
118 | {
119 | mBlackOut = blackOut;
120 | mWhiteOut = whiteOut;
121 | }
122 |
123 | void setBrightness( float brightness ) { mBrightness = brightness; }
124 | void setContrast( float contrast ) { mContrast = contrast; }
125 |
126 | static const std::string getFragmentShader()
127 | {
128 | return CI_GLSL( 400,
129 |
130 | uniform sampler2D tex0;
131 | uniform float u_black;
132 | uniform float u_white;
133 | uniform float u_brightness;
134 | uniform float u_contrast;
135 |
136 | in vec2 TexCoord;
137 |
138 | out vec4 FragColor;
139 |
140 | vec3 map(vec3 value, vec3 inMin, vec3 inMax, vec3 outMin, vec3 outMax)
141 | {
142 | return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
143 | }
144 |
145 | void main()
146 | {
147 | vec4 tex = texture( tex0, TexCoord );
148 |
149 | vec3 b = vec3( u_black );
150 | vec3 w = vec3( u_white );
151 |
152 | // Levels
153 | tex.xyz = map( clamp( tex.xyz, b, w), b, w, vec3(0.0), vec3(1.0) );
154 |
155 | // Brightness Curve
156 | tex.xyz = vec3(1.0) - pow( vec3(1.0) - tex.xyz, vec3(u_brightness) );
157 |
158 | // Contrast Curve
159 | tex.xyz = mix( vec3( 0.5 ), tex.xyz, vec3(u_contrast) );
160 |
161 | FragColor = tex;
162 | }
163 |
164 | );
165 | }
166 |
167 | private:
168 |
169 | float mBlackOut = 0.0;
170 | float mWhiteOut = 1.0;
171 |
172 | float mBrightness = 1.0;
173 | float mContrast = 1.0;
174 |
175 | };
176 |
177 |
178 | // === VIGNETTE ==============================================================
179 |
180 | class VignetteProcess : public ShaderPostprocess
181 | {
182 | public:
183 |
184 | static std::shared_ptr create( float black = 0.0f, float white = 1.0f )
185 | {
186 | return std::make_shared( black, white );
187 | }
188 |
189 | VignetteProcess( float black = 0.0f, float white = 1.0f )
190 | : ShaderPostprocess( getFragmentShader() )
191 | {
192 | }
193 |
194 | void updateUniforms( gl::GlslProgRef& prog ) override
195 | {
196 |
197 | }
198 |
199 | static const std::string getFragmentShader()
200 | {
201 | return CI_GLSL( 400,
202 |
203 | uniform sampler2D tex0;
204 |
205 | in vec2 TexCoord;
206 |
207 | out vec4 FragColor;
208 |
209 | float lengthSquared( vec2 p )
210 | {
211 | return p.x * p.x + p.y * p.y;
212 | }
213 |
214 | void main()
215 | {
216 | vec4 tex = texture( tex0, TexCoord );
217 |
218 | vec2 p = (TexCoord - 0.5) * 2.0;
219 |
220 | tex.xyz -= pow( lengthSquared( p * 0.8 ) - 0.1, 1.8 ) * 0.3;
221 |
222 | FragColor = tex;
223 | }
224 |
225 | );
226 | }
227 |
228 | private:
229 |
230 |
231 | };
232 |
233 | #endif /* StockShaderProcesses_h */
234 |
--------------------------------------------------------------------------------