From 7691ba57f887a937d0baf3cbe811811f4d4a1c7d Mon Sep 17 00:00:00 2001 From: Oliver Uvman Date: Sat, 5 Apr 2014 06:15:40 +0200 Subject: [PATCH 1/5] Enable GL-version specific shader source loading - Load now uses ofShader to load shaders from path, so we know for sure it will work the same way. - Ensure FBOs are set to correct width/height when allocate is called. - Can set shader source for GL ES/2/3 by setting specific strings in constructor, or by calling loadVersioned. - Can reload shaders from file. --- README.md | 13 ++- src/ofxFXObject.cpp | 198 +++++++++++++++++++++++++++----------------- src/ofxFXObject.h | 41 ++++++++- 3 files changed, 171 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 2f49274..496f82c 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ The structure it´s easy. - ```int internalFormat```: if it use GL_RGB, GL_RGBA, GL_RGB16f, GL_RGBA16f, GL_RGB32f, GL_RGBA32f, etc... - ```string fragShader```: it´s the code of the shader. Note that some changes have to be made in order to fill everything on a string -2. ```allocate(width,height,GL_RGBA)```: This usually it´s no need to bee re-define. It´s basically allocate the FBO´s and loads the shader by using injectShader(); +2. ```allocate(width,height,GL_RGBA)```: This usually it´s no need to be re-define. It´s basically allocate the FBO´s and loads the shader by using injectShader(); -3. ```setCode(string fragContent)```: here is where the shaders are loaded. See the example bellow. +3. ```setCode(string fragContent)```: here is where the shaders are loaded. See the example below. 4. ```begin(int texN)``` and ```end(int texN)```: remember nTextures variable? you can passthrough information to it by using this end() and begin() and giving the argument the number of texture you want to open. This texture can be access from the shader by the ```uniform sample2DRect tex0``` or ```tex1``` or ```tex2``` and so on. @@ -57,6 +57,12 @@ fxObject.setCode("#version 120\n\ }"); ``` +Also look at the functions load, loadVersioned, and the different shader strings +to see how you can specify your shader code. You can also see how this is used +to easily load OpenGL2 and OpenGL3 shaders correctly if you look inside the +test-shader-load example. Note that if you don't specify any Vertex Shader for +OpenGL3, a simple pass-through shader will be added for you. :) + On update: ```c++ @@ -198,5 +204,8 @@ On this addon you will find examples of the classes I just describe. Some of the * conway: life game made by [Kalwalt](http://www.kalwaltart.it/) +## Tests +* test-buffer-copying is a regression test that shows three simple buffers printed side by side. They should all look the same. If they don't look the same, we are somehow changing textures as we are copying them. +* test-shader-load is a test to ensure that loading shaders from file and from string works properly. Should be tested both with and without ```#define USE_PROGRAMMABLE_RENDERER``` set in main.cpp. diff --git a/src/ofxFXObject.cpp b/src/ofxFXObject.cpp index e972dd8..03eafce 100644 --- a/src/ofxFXObject.cpp +++ b/src/ofxFXObject.cpp @@ -55,61 +55,16 @@ ofxFXObject::ofxFXObject():nTextures(0),width(0),height(0){ // - backbuffer texture // - tex0, tex1, tex2, ... : this are dynamicaly defined and allocated and can be // filled with information by using .begin(0) and .end(0), or .begin(1) and .end(1), etc - // - // This default shader is a timer made of a mix of Ricardo Caballero´s webGL Sandbox shaders - // http://mrdoob.com/projects/glsl_sandbox/ - // - - fragmentShader = STRINGIFY(uniform float time; - uniform vec2 mouse; - uniform vec2 resolution; - - float box( vec2 p, vec4 rect ){ - float trim = min(rect.z, rect.w) * 0.5; - float minX = min(p.x - rect.x, rect.x + rect.z - p.x); - float minY = min(p.y - rect.y, rect.y + rect.w - p.y); - return ((minX > 0.0) && (minY > 0.0) && ((minX + minY) > trim)) ? 1.0 : 0.0; - } - - float digit( vec2 p, vec4 dim, float d){ - d = (d - mod(d,1.0)) / 10.0; - d = mod( d, 1.0 ); - - p.xy -= dim.xy; - p.xy /= dim.zw; - - float c = 0.0; - - c += box( p, vec4( 0.05, 0.9, 0.9, 0.1 ) ) * ( cos( (0.85*d+0.1)*30.0) - sin(pow(d,1.0)) < 0.0 ? 1.0 : 0.0 ); - c += box( p, vec4( 0.05, 0.45, 0.9, 0.1 ) ) * ( min( pow(6.0*d,2.0), pow(20.0*(d-0.7),2.0) ) < 1.0 ? 0.0 : 1.0 ); - c += box( p, vec4( 0.05, 0.0, 0.9, 0.1 ) ) * ( max( cos(18.6*pow(d,0.75)), 1.0-pow(40.0*(d-0.8),2.0)) > 0.0 ? 1.0 : 0.0 ); - c += box( p, vec4( 0.0, 0.08, 0.1, 0.39 ) ) * ( cos( d * 30.0 ) * abs(d-0.4) > 0.1 ? 1.0 : 0.0 ); - c += box( p, vec4( 0.9, 0.08, 0.1, 0.39) ) * ( pow( 4.0*d-0.8, 2.0) > 0.1 ? 1.0 : 0.0 ); - c += box( p, vec4( 0.0, 0.52, 0.1, 0.39 ) ) * ( sin((d-0.05)*10.5) - 12.0*sin(pow(d,10.0)) > 0.0 ? 0.0 : 1.0 ); - c += box( p, vec4( 0.9, 0.52, 0.1, 0.39 ) ) * ( pow( d-0.55, 2.0 ) > 0.02 ? 1.0 : 0.0 ); - - return c; - } - - void main( void ){ - vec2 p = (gl_FragCoord.xy / resolution.xy); - p.y = 1.0 - p.y; - - float c= 0.0; - c += ( time < 100.0 ) ? 0.0 : digit( p, vec4( 0.2, 0.5, 0.09, 0.1 ), time/100.0 ); - c += ( time < 10.0) ? 0.0 : digit( p, vec4( 0.3, 0.5, 0.09, 0.1 ), time/10.0 ); - c += digit( p, vec4( 0.4, 0.5, 0.09, 0.1 ), time ); - c += box( p, vec4( 0.5, 0.5, 0.01, 0.01 ) ); - c += digit( p, vec4( 0.52, 0.5, 0.09, 0.1 ), time*10.0 ); - - gl_FragColor = vec4( 0.0, c * 0.5, c, 1.0 )*(abs(sin(time*0.5))+0.5); - }); + + fragmentShader = ""; + vertexShader = ""; } ofxFXObject::ofxFXObject(ofxFXObject& parent){ passes = parent.getPasses(); internalFormat = parent.getInternalFormat(); fragmentShader = parent.getCode(); + vertexShader = parent.getVertexCode(); } ofxFXObject::~ofxFXObject(){ @@ -124,6 +79,7 @@ ofxFXObject& ofxFXObject::operator =(ofxFXObject& parent){ passes = parent.getPasses(); internalFormat = parent.getInternalFormat(); fragmentShader = parent.getCode(); + vertexShader = parent.getVertexCode(); ofVec2f resolution = parent.getResolution(); allocate(resolution.x, resolution.y); @@ -144,43 +100,132 @@ void ofxFXObject::allocate(int _width, int _height){ compileCode(); }; -bool ofxFXObject::load( string path ) -{ - ofBuffer buffer = ofBufferFromFile( path ); - if (buffer.size()){ - return setCode( buffer.getText() ); - } else{ - ofLog( OF_LOG_ERROR, "Could not load shader from file " + path ); +bool ofxFXObject::loadVersioned(string glESPath, string gl2Path, string gl3Path){ +#ifdef TARGET_OPENGLES + if (!glESPath.empty()) + return load(glESPath); +#else + if (ofIsGLProgrammableRenderer()){ + if (!gl3Path.empty()) + return load(gl3Path); + } else { + if (!gl2Path.empty()) + return load(gl2Path); + } +#endif + return false; +} + +bool ofxFXObject::load( string path ){ + ofShader code_loader; + code_loader.load(path); + + string frag = code_loader.getShaderSource(GL_FRAGMENT_SHADER); + string vert = code_loader.getShaderSource(GL_VERTEX_SHADER); + + if (frag.empty() && vert.empty()){ + ofLog(OF_LOG_ERROR, "Could not load shader from file " + path); return false; } -}; -bool ofxFXObject::setCode(string _fragShader){ + bool loaded = setCode(frag, vert); + if (loaded) + shaderFilePath = path; + return loaded; +} + +bool ofxFXObject::reload(){ + if (!shaderFilePath.empty()) + return load(shaderFilePath); + return false; +} + +bool ofxFXObject::setCode(string frag, string vert){ + if (fragmentShader == frag && vertexShader == vert) + return false; + bool loaded = false; - if ( fragmentShader != _fragShader ){ - - ofShader test; - test.setupShaderFromSource(GL_FRAGMENT_SHADER, _fragShader); - bFine = test.linkProgram(); - - if( bFine ){ - fragmentShader = _fragShader; - loaded = compileCode(); - } + ofShader test; + if (frag.empty() == false) + test.setupShaderFromSource(GL_FRAGMENT_SHADER, frag); + if (vert.empty() == false) + test.setupShaderFromSource(GL_VERTEX_SHADER, vert); + + bFine = test.linkProgram(); + + if( bFine ){ + if (frag.empty() == false) + fragmentShader = frag; + if (vert.empty() == false) + vertexShader = vert; + loaded = compileCode(); } return loaded; } +void ofxFXObject::selectShaderSource(){ + if (fragmentShader.empty()){ +#ifdef TARGET_OPENGLES + fragmentShader = glESFragmentShader; +#else + if (ofIsGLProgrammableRenderer()){ + fragmentShader = gl3FragmentShader; + } else { + fragmentShader = gl2FragmentShader; + } + } +#endif + + if (vertexShader.empty()){ +#ifdef TARGET_OPENGLES + vertexShader = glESVertexShader; +#else + if (ofIsGLProgrammableRenderer()){ + vertexShader = gl3VertexShader; + // If the vertex shader for GL3 isn't specified, we fill + // in a simple pass-through shader. This way, users can + // give only fragment shaders, just like for GL2/ES. This + // is necessary because having a vertex shader is mandatory + // in GL3. + if (vertexShader.empty()){ + vertexShader = "#version 150\n"; + vertexShader += STRINGIFY( + uniform mat4 modelViewProjectionMatrix; + in vec4 position; + void main(){ + gl_Position = modelViewProjectionMatrix * position; + }); + } + } else { + vertexShader = gl2VertexShader; + } +#endif + } +} + +bool ofxFXObject::needsFboResize(){ + if (nTextures > 0){ + // Assume all textures have the same size. + if (textures[0].getWidth() != width) + return true; + if (textures[0].getHeight() != height) + return true; + } + return false; +} + bool ofxFXObject::compileCode(){ + // Load the correct shader sources into fragmentShader and vertexShader. + selectShaderSource(); // Looks how many textures are declared in the injected fragment shader int num = 0; for (int i = 0; i < 10; i++){ string searchFor = "tex" + ofToString(i); - if ( fragmentShader.find(searchFor)!= -1) + if (fragmentShader.find(searchFor)!= -1) num++; else break; @@ -192,19 +237,19 @@ bool ofxFXObject::compileCode(){ num++; } - // Check if the same number of tectures have already been created and allocated - if ( num != nTextures ){ - // If the number of textures is different - if (textures != NULL ){ + // We need to re-allocate frame buffers if the number of textures is + // different, or if the width or height have changed. + if (num != nTextures || needsFboResize()){ + if (textures != NULL){ if (nTextures > 0) { delete [] textures; } } - // Initialate the right amount of textures + // Initialate the right amount of textures with correct size. nTextures = num; if (nTextures > 0){ textures = new ofFbo[nTextures]; - } else if ( nTextures == 0 ){ + } else if (nTextures == 0){ textures = NULL; } @@ -214,10 +259,11 @@ bool ofxFXObject::compileCode(){ } } - //bool loaded; // Compile the shader and load it to the GPU shader.unload(); shader.setupShaderFromSource(GL_FRAGMENT_SHADER, fragmentShader); + if (vertexShader.empty() == false) + shader.setupShaderFromSource(GL_VERTEX_SHADER, vertexShader); bFine = shader.linkProgram(); return bFine; diff --git a/src/ofxFXObject.h b/src/ofxFXObject.h index 3352e5f..5f2b2d8 100644 --- a/src/ofxFXObject.h +++ b/src/ofxFXObject.h @@ -58,10 +58,20 @@ class ofxFXObject: public ofBaseHasTexture { virtual void allocate(int _width, int _height, int _internalFormat);; virtual void allocate(int _width, int _height); - virtual bool setCode(string fragShader); - virtual void setUseTexture(bool bUseTex){ }; + // Load shaders from your bin/data directory. Works in the same way as ofShader::load. + // Pass empty strings for the shaders you don't implement. + virtual bool loadVersioned(string glESPath = "", string gl2Path = "", string gl3Path = ""); + // Load a single shader by path, you have to make sure yourself the correct + // GLSL version is used if you call this function. virtual bool load(string path); + // If you've loaded a shader from file, you can use this to reload it. + virtual bool reload(); // reloads the shader from the same file path as above + // Forcefully sets the shader code to be used. + virtual bool setCode(string fragShader, string vertShader = ""); + // Load the shader code into a shader, allocate ofFbos, etc. virtual bool compileCode(); + + virtual void setUseTexture(bool bUseTex){ }; void setPasses(int _passes) { passes = _passes; }; void setInternalFormat(int _internalFormat) { internalFormat = _internalFormat; compileCode(); }; @@ -72,6 +82,7 @@ class ofxFXObject: public ofBaseHasTexture { bool compiled() const{ return bFine; }; string getCode() const { return fragmentShader; }; + string getVertexCode() const { return vertexShader; }; float getWidth() const { return width;}; float getHeight() const { return height;}; int getPasses() const { return passes; }; @@ -99,10 +110,34 @@ class ofxFXObject: public ofBaseHasTexture { ofxSwapBuffer pingPong; ofFbo *textures; ofShader shader; - string fragmentShader; int nTextures, internalFormat, width, height; bool bFine; bool bUpdate; + + bool needsFboResize(); + void selectShaderSource(); + string shaderFilePath; + + // Shader Source Strings: These will always contain the strings used + // for the shader source after compileCode has been run. + string fragmentShader; + string vertexShader; + + // Constructor Shader Source Strings: These strings can be specified + // by inheritors in their constructors, and will be loaded when + // appropriate. If any of the above strings are empty, the ones + // below are tried. If shaders are loaded from file, these are also + // ignored. + string glESFragmentShader; + string glESVertexShader; + + string gl2FragmentShader; + string gl2VertexShader; + + string gl3VertexShader; + string gl3FragmentShader; // Simply ignore setting this if you want a passthrough shader! :D + + // Geometry shaders not supported at the moment! }; #endif From 5415170bdfa3c3133fe4d3a829e1eff4ca967651 Mon Sep 17 00:00:00 2001 From: Oliver Uvman Date: Mon, 7 Apr 2014 01:20:51 +0200 Subject: [PATCH 2/5] ofxBlur uses versioned shader strings --- src/filters/ofxBlur.h | 49 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/filters/ofxBlur.h b/src/filters/ofxBlur.h index e2b56e5..71a77bf 100644 --- a/src/filters/ofxBlur.h +++ b/src/filters/ofxBlur.h @@ -1,5 +1,5 @@ /* - * ofxBlurFast.h + * ofxBlur.h * * Created by Patricio Gonzalez Vivo on 25/11/11. * Copyright (c) 2011 http://PatricioGonzalezVivo.com All rights reserved. @@ -60,11 +60,52 @@ class ofxBlur : public ofxFXObject { // Fade constant fade = 0.03f; - // Since we want to run several passes and we have backbuffer declared, // it will contain the first frame we want to act on during the first // pass, and after that it will contain the result of each previous pass. - fragmentShader = STRINGIFY( + + gl3FragmentShader = "#version 150\n"; + gl3FragmentShader += STRINGIFY( + out vec4 outputColor; + + uniform sampler2DRect backbuffer; + uniform float fade; + + float kernel[9]; + vec2 offset[9]; + + void main(void){ + vec2 st = gl_FragCoord.st; + vec4 sum = vec4(0.0); + + offset[0] = vec2(-1.0, -1.0); + offset[1] = vec2(0.0, -1.0); + offset[2] = vec2(1.0, -1.0); + + offset[3] = vec2(-1.0, 0.0); + offset[4] = vec2(0.0, 0.0); + offset[5] = vec2(1.0, 0.0); + + offset[6] = vec2(-1.0, 1.0); + offset[7] = vec2(0.0, 1.0); + offset[8] = vec2(1.0, 1.0); + + kernel[0] = 1.0/16.0; kernel[1] = 2.0/16.0; kernel[2] = 1.0/16.0; + kernel[3] = 2.0/16.0; kernel[4] = 4.0/16.0; kernel[5] = 2.0/16.0; + kernel[6] = 1.0/16.0; kernel[7] = 2.0/16.0; kernel[8] = 1.0/16.0; + + int i = 0; + for (i = 0; i < 9; i++){ + vec4 tmp = texture(backbuffer, st + offset[i]); + sum += tmp * kernel[i]; + } + + vec4 previousValue = texture(backbuffer, st); + outputColor = (1.0 - fade) * previousValue + fade * vec4(sum.rgb, previousValue.a); + }); + + + gl2FragmentShader = STRINGIFY( uniform sampler2DRect backbuffer; uniform float fade; @@ -100,7 +141,7 @@ class ofxBlur : public ofxFXObject { vec4 previousValue = texture2DRect(backbuffer, st); gl_FragColor = (1.0 - fade) * previousValue + fade * vec4(sum.rgb, previousValue.a); }); - }; + } protected: void injectUniforms() { From 6fe88436489b317fa2a45944c5c2a95e5de0bd11 Mon Sep 17 00:00:00 2001 From: Oliver Uvman Date: Mon, 7 Apr 2014 01:21:26 +0200 Subject: [PATCH 3/5] Add test projects --- test-buffer-copying/addons.make | 1 + .../bin/data/shadersGL3/shader.frag | 10 ++ .../bin/data/shadersGL3/shader.vert | 9 ++ test-buffer-copying/src/main.cpp | 28 ++++ test-buffer-copying/src/ofApp.cpp | 120 +++++++++++++++++ test-buffer-copying/src/ofApp.h | 34 +++++ test-buffer-copying/src/ofxPassthrough.h | 60 +++++++++ test-shader-load/addons.make | 1 + test-shader-load/bin/data/blur_gl2.frag | 35 +++++ test-shader-load/bin/data/blur_gl3.frag | 38 ++++++ test-shader-load/src/main.cpp | 24 ++++ test-shader-load/src/ofApp.cpp | 122 ++++++++++++++++++ test-shader-load/src/ofApp.h | 37 ++++++ test-shader-load/src/ofxFileBlur.h | 22 ++++ 14 files changed, 541 insertions(+) create mode 100644 test-buffer-copying/addons.make create mode 100644 test-buffer-copying/bin/data/shadersGL3/shader.frag create mode 100644 test-buffer-copying/bin/data/shadersGL3/shader.vert create mode 100644 test-buffer-copying/src/main.cpp create mode 100644 test-buffer-copying/src/ofApp.cpp create mode 100644 test-buffer-copying/src/ofApp.h create mode 100644 test-buffer-copying/src/ofxPassthrough.h create mode 100644 test-shader-load/addons.make create mode 100644 test-shader-load/bin/data/blur_gl2.frag create mode 100644 test-shader-load/bin/data/blur_gl3.frag create mode 100644 test-shader-load/src/main.cpp create mode 100644 test-shader-load/src/ofApp.cpp create mode 100644 test-shader-load/src/ofApp.h create mode 100644 test-shader-load/src/ofxFileBlur.h diff --git a/test-buffer-copying/addons.make b/test-buffer-copying/addons.make new file mode 100644 index 0000000..a241ba5 --- /dev/null +++ b/test-buffer-copying/addons.make @@ -0,0 +1 @@ +ofxFX diff --git a/test-buffer-copying/bin/data/shadersGL3/shader.frag b/test-buffer-copying/bin/data/shadersGL3/shader.frag new file mode 100644 index 0000000..8ce09cb --- /dev/null +++ b/test-buffer-copying/bin/data/shadersGL3/shader.frag @@ -0,0 +1,10 @@ +#version 130 + +out vec4 outputColor; + +uniform vec4 line_color; + +void main() +{ + outputColor = line_color; +} diff --git a/test-buffer-copying/bin/data/shadersGL3/shader.vert b/test-buffer-copying/bin/data/shadersGL3/shader.vert new file mode 100644 index 0000000..9dcbe62 --- /dev/null +++ b/test-buffer-copying/bin/data/shadersGL3/shader.vert @@ -0,0 +1,9 @@ +#version 130 + +uniform mat4 modelViewProjectionMatrix; +in vec4 position; + +void main() +{ + gl_Position = modelViewProjectionMatrix * position; +} diff --git a/test-buffer-copying/src/main.cpp b/test-buffer-copying/src/main.cpp new file mode 100644 index 0000000..9d96b6b --- /dev/null +++ b/test-buffer-copying/src/main.cpp @@ -0,0 +1,28 @@ +#include "ofMain.h" +#include "ofApp.h" +#include "ofAppGlutWindow.h" + +// comment out the line below if you want to use a fixed pipeline opengl renderer, +// otherwise leave this line uncommented if you want to use a programmable pipeline opengl renderer. +#define USE_PROGRAMMABLE_RENDERER + +#ifdef USE_PROGRAMMABLE_RENDERER +#include "ofGLProgrammableRenderer.h" +#endif + +//======================================================================== +int main( ){ + +#ifdef USE_PROGRAMMABLE_RENDERER + ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); +#endif + + ofAppGlutWindow window; + ofSetupOpenGL(&window, 300*3, 300, OF_WINDOW); + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); + +} diff --git a/test-buffer-copying/src/ofApp.cpp b/test-buffer-copying/src/ofApp.cpp new file mode 100644 index 0000000..14987d5 --- /dev/null +++ b/test-buffer-copying/src/ofApp.cpp @@ -0,0 +1,120 @@ +#include "ofApp.h" +#include "ofFbo.h" + +void ofApp::setup(){ + + ofSetLogLevel(OF_LOG_VERBOSE); + ofEnableAlphaBlending(); + + render_buffer.allocate(width, height, GL_RGBA); + fx_pass.allocate(width, height); +} + +void ofApp::draw_rect_to_fbo_and_update_effect() { + render_buffer.begin(); + { + ofPushStyle(); + ofPushMatrix(); + { + // Draw a dark-teal, half transparent background + // but don't cover everything + ofSetColor(0, 75, 75, 128); + ofRect(5, 5, width-10, height-10); + + // Draw an opaque inner teal rectangle + float xr = width / 4.0; + float yr = height / 4.0; + float wr = width / 2.0; + float hr = height / 2.0; + ofSetColor(0, 128, 128); + ofRect(xr, yr, wr, hr); + + // And finally a half-transparent white dot. This will + // "cut a hole" through our rectangles, allowing us to + // see whatever is behind. This is an odd behaviour, + // unrelated to ofxFX and our fbo business. + ofSetColor(255, 255, 255, 128); + ofCircle(width/2, height/2, 30); + + } + ofPopMatrix(); + ofPopStyle(); + } + render_buffer.end(); + + fx_pass << render_buffer; +} + + +void ofApp::update(){ + } + +//-------------------------------------------------------------- +void ofApp::draw(){ + + draw_rect_to_fbo_and_update_effect(); + + ofBackgroundGradient(ofColor(0), ofColor(255), OF_GRADIENT_LINEAR); + ofSetColor(0); + ofRect(0,height/2,width*3,height/2); + + // This must be called for fbo.draw calls to work. We're probably in + // some alpha blending mode of some sort. Idk. + ofSetColor(255); + + // Left, directly from fbo. This works nicely. + render_buffer.draw(0, 0, width, height); + + // Middle, from the fbo's texture as drawn to one of fx_pass's fbos + fx_pass[0].draw(width, 0, width, height); + + // Right, with fx_pass's shader applied. + fx_pass.draw(width*2, 0, width, height); + + // All of these should look exactly the same. +} + +//-------------------------------------------------------------- +void ofApp::keyPressed(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseMoved(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseDragged(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mousePressed(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseReleased(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::windowResized(int w, int h){ + +} + +//-------------------------------------------------------------- +void ofApp::gotMessage(ofMessage msg){ + +} + +//-------------------------------------------------------------- +void ofApp::dragEvent(ofDragInfo dragInfo){ + +} diff --git a/test-buffer-copying/src/ofApp.h b/test-buffer-copying/src/ofApp.h new file mode 100644 index 0000000..840baae --- /dev/null +++ b/test-buffer-copying/src/ofApp.h @@ -0,0 +1,34 @@ +#pragma once + +#include "ofMain.h" +#include "ofxPassthrough.h" + +class ofApp : public ofBaseApp{ + public: + + void setup(); + void update(); + void draw(); + + // Inherited but unused. + void keyPressed(int key); + void keyReleased(int key); + void mouseMoved(int x, int y); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + + private: + // To make it easier to draw to fbo in either update() or draw(). + // Does not make a difference where it is called from, but is + // called from update() in sandbox-example. + void draw_rect_to_fbo_and_update_effect(); + + int width = 300; + int height = 300; + ofxPassthrough fx_pass; + ofFbo render_buffer; +}; diff --git a/test-buffer-copying/src/ofxPassthrough.h b/test-buffer-copying/src/ofxPassthrough.h new file mode 100644 index 0000000..6731ceb --- /dev/null +++ b/test-buffer-copying/src/ofxPassthrough.h @@ -0,0 +1,60 @@ +// +// ofxBloom.h +// emptyExample +// +// Created by Patricio Gonzalez Vivo on 25/11/11. +// Copyright (c) 2011 http://PatricioGonzalezVivo.com. All rights reserved. +// + +#pragma once + +#define STRINGIFY(A) #A + +#include "ofMain.h" +#include "ofxFXObject.h" + +class ofxPassthrough : public ofxFXObject { +public: + ofxPassthrough(){ + passes = 1; + internalFormat = GL_RGBA; + + if (ofIsGLProgrammableRenderer()) { // OpenGL 3.0 + string vertexShader = "#version 150\n"; + vertexShader += STRINGIFY( + uniform mat4 modelViewProjectionMatrix; + uniform mat4 textureMatrix; + + in vec4 position; + in vec2 texcoord; + + out vec2 texCoordVarying; + + void main(){ + texCoordVarying = texcoord; + gl_Position = modelViewProjectionMatrix * position; + }); + + shader.setupShaderFromSource(GL_VERTEX_SHADER, vertexShader); + + fragmentShader = "#version 150\n"; + fragmentShader += STRINGIFY(uniform sampler2DRect tex0; + in vec2 texCoordVarying; + out vec4 outputColor; + + void main(){ + vec2 st = gl_FragCoord.st; + outputColor = texture(tex0, st); + }); + + } else { // OpenGL 2.0 + fragmentShader = ""; // For some reason "#version 120\n" makes this break. + fragmentShader += STRINGIFY(uniform sampler2DRect tex0; + + void main(){ + vec2 st = gl_TexCoord[0].st; + gl_FragColor = texture2DRect(tex0, st); + }); + } + } +}; diff --git a/test-shader-load/addons.make b/test-shader-load/addons.make new file mode 100644 index 0000000..a241ba5 --- /dev/null +++ b/test-shader-load/addons.make @@ -0,0 +1 @@ +ofxFX diff --git a/test-shader-load/bin/data/blur_gl2.frag b/test-shader-load/bin/data/blur_gl2.frag new file mode 100644 index 0000000..165a34f --- /dev/null +++ b/test-shader-load/bin/data/blur_gl2.frag @@ -0,0 +1,35 @@ +uniform sampler2DRect backbuffer; +uniform float fade; + +float kernel[9]; +vec2 offset[9]; + +void main(void){ + vec2 st = gl_TexCoord[0].st; + vec4 sum = vec4(0.0); + + offset[0] = vec2(-1.0, -1.0); + offset[1] = vec2(0.0, -1.0); + offset[2] = vec2(1.0, -1.0); + + offset[3] = vec2(-1.0, 0.0); + offset[4] = vec2(0.0, 0.0); + offset[5] = vec2(1.0, 0.0); + + offset[6] = vec2(-1.0, 1.0); + offset[7] = vec2(0.0, 1.0); + offset[8] = vec2(1.0, 1.0); + + kernel[0] = 1.0/16.0; kernel[1] = 2.0/16.0; kernel[2] = 1.0/16.0; + kernel[3] = 2.0/16.0; kernel[4] = 4.0/16.0; kernel[5] = 2.0/16.0; + kernel[6] = 1.0/16.0; kernel[7] = 2.0/16.0; kernel[8] = 1.0/16.0; + + int i = 0; + for (i = 0; i < 9; i++){ + vec4 tmp = texture2DRect(backbuffer, st + offset[i]); + sum += tmp * kernel[i]; + } + + vec4 previousValue = texture2DRect(backbuffer, st); + gl_FragColor = (1.0 - fade) * previousValue + fade * vec4(sum.rgb, previousValue.a); +} diff --git a/test-shader-load/bin/data/blur_gl3.frag b/test-shader-load/bin/data/blur_gl3.frag new file mode 100644 index 0000000..aa07ee0 --- /dev/null +++ b/test-shader-load/bin/data/blur_gl3.frag @@ -0,0 +1,38 @@ +#version 150 + +out vec4 outputColor; +uniform sampler2DRect backbuffer; +uniform float fade; + +float kernel[9]; +vec2 offset[9]; + +void main(void){ + vec2 st = gl_FragCoord.st; + vec4 sum = vec4(0.0); + + offset[0] = vec2(-1.0, -1.0); + offset[1] = vec2(0.0, -1.0); + offset[2] = vec2(1.0, -1.0); + + offset[3] = vec2(-1.0, 0.0); + offset[4] = vec2(0.0, 0.0); + offset[5] = vec2(1.0, 0.0); + + offset[6] = vec2(-1.0, 1.0); + offset[7] = vec2(0.0, 1.0); + offset[8] = vec2(1.0, 1.0); + + kernel[0] = 1.0/16.0; kernel[1] = 2.0/16.0; kernel[2] = 1.0/16.0; + kernel[3] = 2.0/16.0; kernel[4] = 4.0/16.0; kernel[5] = 2.0/16.0; + kernel[6] = 1.0/16.0; kernel[7] = 2.0/16.0; kernel[8] = 1.0/16.0; + + int i = 0; + for (i = 0; i < 9; i++){ + vec4 tmp = texture(backbuffer, st + offset[i]); + sum += tmp * kernel[i]; + } + + vec4 previousValue = texture(backbuffer, st); + outputColor = (1.0 - fade) * previousValue + fade * vec4(sum.rgb, previousValue.a); +} diff --git a/test-shader-load/src/main.cpp b/test-shader-load/src/main.cpp new file mode 100644 index 0000000..d94cf6d --- /dev/null +++ b/test-shader-load/src/main.cpp @@ -0,0 +1,24 @@ +#include "ofMain.h" +#include "ofApp.h" +#include "ofAppGlutWindow.h" + +// This program should look exactly the same whether this is commented out or not. +// Defined -> OpenGL3 is used. Not defined -> OpenGL2 +#define USE_PROGRAMMABLE_RENDERER + +#ifdef USE_PROGRAMMABLE_RENDERER +#include "ofGLProgrammableRenderer.h" +#endif + +//======================================================================== +int main( ){ + +#ifdef USE_PROGRAMMABLE_RENDERER + ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE); +#endif + + ofAppGlutWindow window; + ofSetupOpenGL(&window, 300*3, 300, OF_WINDOW); + ofRunApp(new ofApp()); + +} diff --git a/test-shader-load/src/ofApp.cpp b/test-shader-load/src/ofApp.cpp new file mode 100644 index 0000000..21e7efc --- /dev/null +++ b/test-shader-load/src/ofApp.cpp @@ -0,0 +1,122 @@ +#include "ofApp.h" +#include "ofFbo.h" + +void ofApp::setup(){ + + ofSetLogLevel(OF_LOG_VERBOSE); + ofEnableAlphaBlending(); + + render_buffer.allocate(width, height, GL_RGBA); + + fx_string.setFade(1.0); + fx_string.allocate(width, height); + + fx_file.setFade(1.0); + fx_file.allocate(width, height); +} + +void ofApp::draw_rect_to_fbo_and_update_effect() { + render_buffer.begin(); + { + ofPushStyle(); + ofPushMatrix(); + { + // Draw a dark-teal, half transparent background + // but don't cover everything + ofSetColor(0, 75, 75, 128); + ofRect(5, 5, width-10, height-10); + + // Draw an opaque inner teal rectangle + float xr = width / 4.0; + float yr = height / 4.0; + float wr = width / 2.0; + float hr = height / 2.0; + ofSetColor(0, 128, 128); + ofRect(xr, yr, wr, hr); + + // And finally a half-transparent white dot. This will + // "cut a hole" through our rectangles, allowing us to + // see whatever is behind. This is an odd behaviour, + // unrelated to ofxFX and our fbo business. + ofSetColor(255, 255, 255, 128); + ofCircle(width/2, height/2, 30); + + } + ofPopMatrix(); + ofPopStyle(); + } + render_buffer.end(); + + fx_string << render_buffer; + fx_file << render_buffer; +} + + +void ofApp::update(){ + } + +//-------------------------------------------------------------- +void ofApp::draw(){ + + draw_rect_to_fbo_and_update_effect(); + + ofBackgroundGradient(ofColor(0), ofColor(255), OF_GRADIENT_LINEAR); + ofSetColor(0); + ofRect(0,height/2,width*3,height/2); + + ofSetColor(255); + + // Left, directly from fbo. This should render clearly. + render_buffer.draw(0, 0, width, height); + + // Middle, with fx_file's shader applied. Should blur. + fx_file.draw(width, 0, width, height); + + // Right, with fx_string's shader applied. Should be equal to fx_file's output. + fx_string.draw(width*2, 0, width, height); +} + +//-------------------------------------------------------------- +void ofApp::keyPressed(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseMoved(int x, int y){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseDragged(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mousePressed(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::mouseReleased(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void ofApp::windowResized(int w, int h){ + +} + +//-------------------------------------------------------------- +void ofApp::gotMessage(ofMessage msg){ + +} + +//-------------------------------------------------------------- +void ofApp::dragEvent(ofDragInfo dragInfo){ + +} diff --git a/test-shader-load/src/ofApp.h b/test-shader-load/src/ofApp.h new file mode 100644 index 0000000..09ac240 --- /dev/null +++ b/test-shader-load/src/ofApp.h @@ -0,0 +1,37 @@ +#pragma once + +#include "ofMain.h" +#include "ofxFXObject.h" +#include "ofxBlur.h" +#include "ofxFileBlur.h" + +class ofApp : public ofBaseApp{ + public: + + void setup(); + void update(); + void draw(); + + // Inherited but unused. + void keyPressed(int key); + void keyReleased(int key); + void mouseMoved(int x, int y); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + + private: + // To make it easier to draw to fbo in either update() or draw(). + // Does not make a difference where it is called from, but is + // called from update() in sandbox-example. + void draw_rect_to_fbo_and_update_effect(); + + int width = 300; + int height = 300; + ofxFileBlur fx_file; + ofxBlur fx_string; + ofFbo render_buffer; +}; diff --git a/test-shader-load/src/ofxFileBlur.h b/test-shader-load/src/ofxFileBlur.h new file mode 100644 index 0000000..e7b500d --- /dev/null +++ b/test-shader-load/src/ofxFileBlur.h @@ -0,0 +1,22 @@ +#pragma once + +#include "ofMain.h" +#include "ofxFXObject.h" + +class ofxFileBlur : public ofxFXObject { + public: + float fade; + void setFade(float _fade) { fade = _fade;}; + + ofxFileBlur(){ + passes = 3; + internalFormat = GL_RGBA; + fade = 0.03f; + loadVersioned("", "blur_gl2", "blur_gl3"); + } + + protected: + void injectUniforms() { + shader.setUniform1f("fade", fade); + } +}; From 43d99b462cf1f244ec7b83317f2c612860948d93 Mon Sep 17 00:00:00 2001 From: Oliver Uvman Date: Mon, 7 Apr 2014 06:35:15 +0200 Subject: [PATCH 4/5] ofxBloom uses versioned shader strings --- src/filters/ofxBloom.h | 119 +++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 69 deletions(-) diff --git a/src/filters/ofxBloom.h b/src/filters/ofxBloom.h index 913a32a..615e202 100644 --- a/src/filters/ofxBloom.h +++ b/src/filters/ofxBloom.h @@ -19,78 +19,59 @@ class ofxBloom : public ofxFXObject { passes = 1; internalFormat = GL_RGBA; - if (ofIsGLProgrammableRenderer()) { // OpenGL 3.0 - string vertexShader = "#version 150\n"; - vertexShader += STRINGIFY( - uniform mat4 modelViewProjectionMatrix; - uniform mat4 textureMatrix; + gl3FragmentShader = "#version 150\n"; + gl3FragmentShader += STRINGIFY( + uniform sampler2DRect tex0; + in vec2 texCoordVarying; + out vec4 outputColor; - in vec4 position; - in vec2 texcoord; - - out vec2 texCoordVarying; + void main(){ + vec4 sum = vec4(0); + vec2 st = gl_FragCoord.st; + int j; + int i; + for(i=-4; i<4; i++){ + for (j=-3; j<3; j++){ + sum += texture(tex0, st + vec2(j, i)*0.004) * 0.25; + } + } + + if (texture(tex0, st).r < 0.3){ + outputColor = sum * sum * 0.012 + texture(tex0, st); + } else { + if (texture(tex0, st).r < 0.5){ + outputColor = sum * sum * 0.009 + texture(tex0, st); + } else { + outputColor = sum * sum * 0.0075 + texture(tex0, st); + } + } + outputColor.a = texture(tex0, st).a; + }); + gl2FragmentShader = ""; // For some reason "#version 120\n" makes this break. + gl2FragmentShader += STRINGIFY( + uniform sampler2DRect tex0; void main(){ - texCoordVarying = texcoord; - gl_Position = modelViewProjectionMatrix * position; + vec4 sum = vec4(0); + vec2 st = gl_TexCoord[0].st; + int j; + int i; + for(i=-4; i<4; i++){ + for (j=-3; j<3; j++){ + sum += texture2DRect(tex0, st + vec2(j, i)*0.004) * 0.25; + } + } + + if (texture2DRect(tex0, st).r < 0.3){ + gl_FragColor = sum * sum * 0.012 + texture2DRect(tex0, st); + } else { + if (texture2DRect(tex0, st).r < 0.5){ + gl_FragColor = sum * sum * 0.009 + texture2DRect(tex0, st); + } else { + gl_FragColor = sum * sum * 0.0075 + texture2DRect(tex0, st); + } + } + gl_FragColor.a = texture2DRect(tex0, st).a; }); - - shader.setupShaderFromSource(GL_VERTEX_SHADER, vertexShader); - - fragmentShader = "#version 150\n"; - fragmentShader += STRINGIFY(uniform sampler2DRect tex0; - in vec2 texCoordVarying; - out vec4 outputColor; - - void main(){ - vec4 sum = vec4(0); - vec2 st = gl_FragCoord.st; - int j; - int i; - for(i=-4; i<4; i++){ - for (j=-3; j<3; j++){ - sum += texture(tex0, st + vec2(j, i)*0.004) * 0.25; - } - } - - if (texture(tex0, st).r < 0.3){ - outputColor = sum * sum * 0.012 + texture(tex0, st); - } else { - if (texture(tex0, st).r < 0.5){ - outputColor = sum * sum * 0.009 + texture(tex0, st); - } else { - outputColor = sum * sum * 0.0075 + texture(tex0, st); - } - } - outputColor.a = texture(tex0, st).a; - }); - - } else { // OpenGL 2.0 - fragmentShader = ""; // For some reason "#version 120\n" makes this break. - fragmentShader += STRINGIFY(uniform sampler2DRect tex0; - - void main(){ - vec4 sum = vec4(0); - vec2 st = gl_TexCoord[0].st; - int j; - int i; - for(i=-4; i<4; i++){ - for (j=-3; j<3; j++){ - sum += texture2DRect(tex0, st + vec2(j, i)*0.004) * 0.25; - } - } - - if (texture2DRect(tex0, st).r < 0.3){ - gl_FragColor = sum * sum * 0.012 + texture2DRect(tex0, st); - } else { - if (texture2DRect(tex0, st).r < 0.5){ - gl_FragColor = sum * sum * 0.009 + texture2DRect(tex0, st); - } else { - gl_FragColor = sum * sum * 0.0075 + texture2DRect(tex0, st); - } - } - gl_FragColor.a = texture2DRect(tex0, st).a; - }); - } } }; From ff54fc465138d311c04f2974abf32d83865f23af Mon Sep 17 00:00:00 2001 From: Oliver Uvman Date: Mon, 7 Apr 2014 06:43:35 +0200 Subject: [PATCH 5/5] ofxPassthrough (test) uses versnd shader strings --- test-buffer-copying/src/ofxPassthrough.h | 54 ++++++++---------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/test-buffer-copying/src/ofxPassthrough.h b/test-buffer-copying/src/ofxPassthrough.h index 6731ceb..bbda62c 100644 --- a/test-buffer-copying/src/ofxPassthrough.h +++ b/test-buffer-copying/src/ofxPassthrough.h @@ -19,42 +19,22 @@ class ofxPassthrough : public ofxFXObject { passes = 1; internalFormat = GL_RGBA; - if (ofIsGLProgrammableRenderer()) { // OpenGL 3.0 - string vertexShader = "#version 150\n"; - vertexShader += STRINGIFY( - uniform mat4 modelViewProjectionMatrix; - uniform mat4 textureMatrix; - - in vec4 position; - in vec2 texcoord; - - out vec2 texCoordVarying; - - void main(){ - texCoordVarying = texcoord; - gl_Position = modelViewProjectionMatrix * position; - }); - - shader.setupShaderFromSource(GL_VERTEX_SHADER, vertexShader); - - fragmentShader = "#version 150\n"; - fragmentShader += STRINGIFY(uniform sampler2DRect tex0; - in vec2 texCoordVarying; - out vec4 outputColor; - - void main(){ - vec2 st = gl_FragCoord.st; - outputColor = texture(tex0, st); - }); - - } else { // OpenGL 2.0 - fragmentShader = ""; // For some reason "#version 120\n" makes this break. - fragmentShader += STRINGIFY(uniform sampler2DRect tex0; - - void main(){ - vec2 st = gl_TexCoord[0].st; - gl_FragColor = texture2DRect(tex0, st); - }); - } + gl3FragmentShader = "#version 150\n"; + gl3FragmentShader += STRINGIFY(uniform sampler2DRect tex0; + in vec2 texCoordVarying; + out vec4 outputColor; + + void main(){ + vec2 st = gl_FragCoord.st; + outputColor = texture(tex0, st); + }); + + gl2FragmentShader = ""; // For some reason "#version 120\n" makes this break. + gl2FragmentShader += STRINGIFY(uniform sampler2DRect tex0; + + void main(){ + vec2 st = gl_TexCoord[0].st; + gl_FragColor = texture2DRect(tex0, st); + }); } };