diff --git a/addons/ofxAndroid/src/ofAppAndroidWindow.cpp b/addons/ofxAndroid/src/ofAppAndroidWindow.cpp index 72e47e93fa1..eef5eb79b69 100644 --- a/addons/ofxAndroid/src/ofAppAndroidWindow.cpp +++ b/addons/ofxAndroid/src/ofAppAndroidWindow.cpp @@ -122,7 +122,19 @@ ofAppAndroidWindow::ofAppAndroidWindow() { window = this; msaaSamples = 1; glesVersion = 2; - +#ifdef TARGET_PROGRAMMABLE_GL + #ifdef GL_ES_VERSION_3_0 + glesVersion = 3; + #ifdef GL_ES_VERSION_3_1 + glesVersionMinor = 1; + #endif + #else + glesVersion = 2; + #endif +#else + glesVersion = 1; +#endif + window = this; ofGetMainLoop()->setCurrentWindow(this); } @@ -164,17 +176,22 @@ ofAppAndroidWindow::~ofAppAndroidWindow() { // TODO Auto-generated destructor stub } + bool ofAppAndroidWindow::isSurfaceDestroyed() { return surfaceDestroyed; } void ofAppAndroidWindow::setup(const ofGLESWindowSettings & settings) { + glesVersion = settings.getGLESVersionMajor(); + glesVersionMinor = settings.getGLESVersionMinor(); setup( (const ofxAndroidWindowSettings &)settings ); } void ofAppAndroidWindow::setup(const ofxAndroidWindowSettings & settings){ + glesVersion = settings.getGLESVersionMajor(); + glesVersionMinor = settings.getGLESVersionMinor(); if(window == nullptr) { ofLogError("ofAppAndroidWindow") << "Setup and Window is nullptr ! Fixing"; setCurrentWindow(); @@ -186,25 +203,18 @@ void ofAppAndroidWindow::setup(const ofxAndroidWindowSettings & settings){ }else{ currentRenderer = std::make_shared(this); } - jclass javaClass = ofGetJNIEnv()->FindClass("cc/openframeworks/OFAndroid"); - if(javaClass==nullptr){ ofLogError("ofAppAndroidWindow") << "setupOpenGL(): couldn't find OFAndroid java class"; return; } - makeCurrent(); - jmethodID method = ofGetJNIEnv()->GetStaticMethodID(javaClass,"setupGL","(IZ)V"); if(!method){ ofLogError("ofAppAndroidWindow") << "setupOpenGL(): couldn't find OFAndroid setupGL method"; return; } - ofGetJNIEnv()->CallStaticVoidMethod(javaClass,method,glesVersion,settings.preserveContextOnPause); - - } void ofAppAndroidWindow::update(){ @@ -330,6 +340,10 @@ int ofAppAndroidWindow::getGlesVersion() return glesVersion; } +int ofAppAndroidWindow::getGlesVersionMinor() +{ + return glesVersionMinor; +} extern "C"{ @@ -443,57 +457,46 @@ Java_cc_openframeworks_OFAndroid_onSurfaceDestroyed( JNIEnv* env, jclass thiz } } + JNIEXPORT void JNICALL -Java_cc_openframeworks_OFAndroid_onSurfaceCreated( JNIEnv* env, jclass thiz ){ - if(appSetup){ - ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated"; - if(!surfaceDestroyed){ - ofNotifyEvent(ofxAndroidEvents().unloadGL); - } - ofNotifyEvent(ofxAndroidEvents().reloadGL); - window->renderer()->pushStyle(); - window->renderer()->setupGraphicDefaults(); - window->renderer()->popStyle(); - window->setThreadedEvents(false); - int glesVersion = window->getGlesVersion(); - bSetupScreen = true; - if( glesVersion < 2 ) - { - ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated OpenGLES 1"; - dynamic_cast(window->renderer().get())->setup(); - } - else - { - ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated OpenGLES 2.0"; - dynamic_cast(window->renderer().get())->setup(glesVersion,0); - } +Java_cc_openframeworks_OFAndroid_onSurfaceCreated( JNIEnv* env, jclass thiz ){ + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated"; - }else{ - if(window != nullptr) { - int glesVersion = window->getGlesVersion(); - bSetupScreen = true; - if (glesVersion < 2) { - ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated OpenGLES 1"; - dynamic_cast(window->renderer().get())->setup(); - } else { - ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated OpenGLES 2.0"; - dynamic_cast(window->renderer().get())->setup( - glesVersion, 0); - } - } - } + if(!surfaceDestroyed && appSetup){ + ofNotifyEvent(ofxAndroidEvents().unloadGL); + } + ofNotifyEvent(ofxAndroidEvents().reloadGL); + + if(appSetup){ + window->renderer()->pushStyle(); + window->renderer()->setupGraphicDefaults(); + window->renderer()->popStyle(); + window->setThreadedEvents(false); + } + + bSetupScreen = true; + int glesVersion = window->getGlesVersion(); + int glesVersionMinor = window->getGlesVersionMinor(); + + if(glesVersion < 2){ + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated OpenGLES 1"; + dynamic_cast(window->renderer().get())->setup(); + }else{ + ofLogVerbose("ofAppAndroidWindow") << "onSurfaceCreated OpenGLES 2.0+"; + dynamic_cast(window->renderer().get())->setup(glesVersion, glesVersionMinor); + } - surfaceDestroyed = false; + surfaceDestroyed = false; } JNIEXPORT jboolean JNICALL Java_cc_openframeworks_OFAndroid_isWindowReady( JNIEnv* env, jclass thiz) { - if(window != nullptr && window->renderer() != nullptr) { - return true; - } else { + if(window != nullptr && window->renderer() != nullptr) { + return true; + } else { return false; - } + } } JNIEXPORT void JNICALL @@ -554,25 +557,19 @@ Java_cc_openframeworks_OFAndroid_setAssetManager(JNIEnv *env, jclass thiz, jobject jAssetManager) { env->NewGlobalRef(jAssetManager); - AAssetManager *aaAssetManager = AAssetManager_fromJava(env, jAssetManager); if (aaAssetManager == nullptr) { ofLogError("ofAppAndroidWindow") << "Could not obtain the AAssetManager"; return; } - assetManager = aaAssetManager; if(window == nullptr || (window != nullptr && window->renderer() == nullptr)) { ofLogVerbose("ofAppAndroidWindow") << "setAssetManager window is null"; return; } - window->setAssetManager(assetManager); - - - } /* Call to render the next GL frame */ diff --git a/addons/ofxAndroid/src/ofAppAndroidWindow.h b/addons/ofxAndroid/src/ofAppAndroidWindow.h index cae62bac8c0..d31554a98f2 100644 --- a/addons/ofxAndroid/src/ofAppAndroidWindow.h +++ b/addons/ofxAndroid/src/ofAppAndroidWindow.h @@ -110,16 +110,20 @@ class ofAppAndroidWindow: public ofAppBaseGLESWindow { int getGlesVersion(); + int getGlesVersionMinor(); AAssetManager& getAssetManager(); void setAssetManager(AAssetManager* assetManager); + int glesVersion; + int glesVersionMinor; + private: ofCoreEvents coreEvents; std::shared_ptr currentRenderer; - int glesVersion; + int msaaSamples; AAssetManager* assetManager = nullptr; diff --git a/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp b/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp index f5201c37fb8..4ec0683dcc7 100644 --- a/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp +++ b/addons/ofxAndroid/src/ofxAndroidVideoGrabber.cpp @@ -132,35 +132,34 @@ ofxAndroidVideoGrabber::Data::~Data(){ } void ofxAndroidVideoGrabber::Data::loadTexture(){ - ofTextureData td; - GLuint texId[1]; - glGenTextures(1, texId); - - glEnable(GL_TEXTURE_EXTERNAL_OES); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, texId[0]); - - glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (!ofIsGLProgrammableRenderer()) { - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } + ofTextureData td; + GLuint texId[1]; + glGenTextures(1, texId); + + glEnable(GL_TEXTURE_EXTERNAL_OES); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, texId[0]); - glDisable(GL_TEXTURE_EXTERNAL_OES); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // Set the externally created texture reference - texture.setUseExternalTextureID(texId[0]); - texture.texData.width = width; - texture.texData.height = height; - texture.texData.tex_w = width; - texture.texData.tex_h = height; - texture.texData.tex_t = 1; // Hack! - texture.texData.tex_u = 1; - texture.texData.textureTarget = GL_TEXTURE_EXTERNAL_OES; - texture.texData.glInternalFormat = GL_RGBA; +#ifndef TARGET_PROGRAMMABLE_GL + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +#endif + glDisable(GL_TEXTURE_EXTERNAL_OES); + // Set the externally created texture reference + texture.setUseExternalTextureID(texId[0]); + texture.texData.width = width; + texture.texData.height = height; + texture.texData.tex_w = width; + texture.texData.tex_h = height; + texture.texData.tex_t = 1; // Hack! + texture.texData.tex_u = 1; + texture.texData.textureTarget = GL_TEXTURE_EXTERNAL_OES; + texture.texData.glInternalFormat = GL_RGBA; } @@ -262,7 +261,7 @@ void ofxAndroidVideoGrabber::close(){ } else { ofLogError("ofxAndroidVideoGrabber") << "close(): couldn't get OFAndroidVideoGrabber close grabber method"; } - + data->bGrabberInited = false; } diff --git a/addons/ofxAndroid/src/ofxAndroidVideoPlayer.cpp b/addons/ofxAndroid/src/ofxAndroidVideoPlayer.cpp index 3e83236d352..0f834b6a030 100644 --- a/addons/ofxAndroid/src/ofxAndroidVideoPlayer.cpp +++ b/addons/ofxAndroid/src/ofxAndroidVideoPlayer.cpp @@ -26,7 +26,9 @@ void ofxAndroidVideoPlayer::reloadTexture(){ glTexParameterf(texture.texData.textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(texture.texData.textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(texture.texData.textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#ifndef TARGET_PROGRAMMABLE_GL glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +#endif glDisable(texture.texData.textureTarget); diff --git a/libs/openFrameworks/3d/ofMesh.inl b/libs/openFrameworks/3d/ofMesh.inl index e9e5363b0fc..0990186b27b 100644 --- a/libs/openFrameworks/3d/ofMesh.inl +++ b/libs/openFrameworks/3d/ofMesh.inl @@ -2939,8 +2939,7 @@ template ofMesh_ ofMesh_::axis( float size ) { ofMesh_ mesh; - // mesh only available as wireframe // - mesh.setMode(OF_PRIMITIVE_LINES); + mesh.setMode(OF_PRIMITIVE_TRIANGLES); V vertices[6] = { V(0,0,0), diff --git a/libs/openFrameworks/app/ofAppEGLWindow.cpp b/libs/openFrameworks/app/ofAppEGLWindow.cpp index 0aee905afe0..24a62277aa2 100644 --- a/libs/openFrameworks/app/ofAppEGLWindow.cpp +++ b/libs/openFrameworks/app/ofAppEGLWindow.cpp @@ -259,7 +259,8 @@ ofAppEGLWindow::ofAppEGLWindow() { x11Display = NULL; x11Screen = NULL; x11ScreenNum = 0l; - glesVersion = 1; + glesVersionMajor = 1; + glesVersionMinor = 0; if(instance!=NULL){ ofLogError("ofAppEGLWindow") << "trying to create more than one instance"; @@ -402,7 +403,8 @@ void ofAppEGLWindow::setup(const ofAppEGLWindowSettings & _settings) { eglConfig = NULL; eglVersionMajor = -1; eglVersionMinor = -1; - glesVersion = 1; + glesVersionMajor = 1; + glesVersionMinor = 0; // X11 check // char * pDisplay; @@ -439,7 +441,8 @@ void ofAppEGLWindow::setup(const ofAppEGLWindowSettings & _settings) { initNative(); - glesVersion = settings.glesVersion; + glesVersionMajor = settings.glesVersionMajor(); + glesVersionMinor = settings.glesVersionMinor(); // we set this here, and if we need to make a fullscreen // app, we do it during the first loop. windowMode = settings.windowMode; @@ -477,7 +480,7 @@ void ofAppEGLWindow::setup(const ofAppEGLWindowSettings & _settings) { makeCurrent(); if(currentRenderer->getType()==ofGLProgrammableRenderer::TYPE){ - static_cast(currentRenderer.get())->setup(settings.glesVersion,0); + static_cast(currentRenderer.get())->setup(settings.glesVersionMajor(),settings.glesVersionMinor()); }else{ static_cast(currentRenderer.get())->setup(); } @@ -547,7 +550,7 @@ bool ofAppEGLWindow::createSurface() { // success! } - EGLint glesVersion; + EGLint glesVersionBit; int glesVersionForContext; if(ofGetCurrentRenderer()) { @@ -556,12 +559,12 @@ bool ofAppEGLWindow::createSurface() { ofLogNotice("ofAppEGLWindow") << "createSurface(): no current renderer selected"; } - if(this->glesVersion==2){ - glesVersion = EGL_OPENGL_ES2_BIT; - glesVersionForContext = 2; - ofLogNotice("ofAppEGLWindow") << "createSurface(): GLES2 renderer detected"; + if(this->glesVersionMajor>=2){ + glesVersionBit = EGL_OPENGL_ES2_BIT; + glesVersionForContext = this->glesVersionMajor; + ofLogNotice("ofAppEGLWindow") << "createSurface(): GLES" << glesVersionForContext << " renderer detected"; }else{ - glesVersion = EGL_OPENGL_ES_BIT; + glesVersionBit = EGL_OPENGL_ES_BIT; glesVersionForContext = 1; ofLogNotice("ofAppEGLWindow") << "createSurface(): default renderer detected"; } @@ -580,7 +583,7 @@ bool ofAppEGLWindow::createSurface() { attribute_list_framebuffer_config[i++] = iter->second; } attribute_list_framebuffer_config[i++] = EGL_RENDERABLE_TYPE; - attribute_list_framebuffer_config[i++] = glesVersion; //openGL ES version + attribute_list_framebuffer_config[i++] = glesVersionBit; //openGL ES version attribute_list_framebuffer_config[i] = EGL_NONE; // add the terminator EGLint num_configs; @@ -1424,7 +1427,7 @@ void ofAppEGLWindow::setupNativeInput(){ tc.c_lflag &= ~ECHO; tc.c_lflag |= ECHONL; tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc); - + mb.mouseButtonState = 0; kb.shiftPressed = false; @@ -1492,7 +1495,7 @@ void ofAppEGLWindow::printInput(){ void ofAppEGLWindow::destroyNativeInput(){ ofLogNotice("ofAppEGLWindow") << "destroyNativeInput()"; - + for(device::iterator iter = inputDevices.begin(); iter != inputDevices.end(); iter++){ if(iter->second >= 0){ ::close(iter->second); @@ -1514,7 +1517,7 @@ void ofAppEGLWindow::processInput(int fd, const char * node){ static ofMouseEventArgs mouseEvent; struct input_event ev; char key = 0; - + bool pushKeyEvent = false; bool pushMouseEvent = false; bool pushTouchEvent = false; @@ -1564,7 +1567,7 @@ void ofAppEGLWindow::processInput(int fd, const char * node){ pushMouseEvent = true; } }else if(ev.code == BTN_TOUCH){ - if(ev.value == 0){ // release + if(ev.value == 0){ // release touchEvent.type = ofTouchEventArgs::up; touchEvent.id = 0; mt[touchEvent.id] = 0; @@ -1728,7 +1731,7 @@ void ofAppEGLWindow::processInput(int fd, const char * node){ }else{ ofLogNotice("ofAppEGLWindow") << "readKeyboardEvents(): input_event.code is outside of our small range"; } - } + } } }else if (ev.type == EV_REL){ int axis = ev.code; @@ -1779,7 +1782,7 @@ void ofAppEGLWindow::processInput(int fd, const char * node){ pushTouchEvent = true; } } - else + else { if (mt[touchEvent.id] == 0){ touchEvent.type = ofTouchEventArgs::down; @@ -1837,8 +1840,8 @@ void ofAppEGLWindow::processInput(int fd, const char * node){ } } - - + + if(pushKeyEvent){ lock(); @@ -1846,7 +1849,7 @@ void ofAppEGLWindow::processInput(int fd, const char * node){ unlock(); pushKeyEvent = false; } - + if(pushMouseEvent){ // lock the thread for a moment while we copy the data lock(); @@ -1922,7 +1925,7 @@ void ofAppEGLWindow::readNativeUDevEvents() { removeInput(devnode); } } - + udev_device_unref(dev); }else{ ofLogNotice("ofAppEGLWindow") << "readNativeUDevEvents(): device returned by receive_device() is NULL"; diff --git a/libs/openFrameworks/app/ofAppEGLWindow.h b/libs/openFrameworks/app/ofAppEGLWindow.h index a70a35e2aff..991d344990f 100644 --- a/libs/openFrameworks/app/ofAppEGLWindow.h +++ b/libs/openFrameworks/app/ofAppEGLWindow.h @@ -269,7 +269,7 @@ class ofAppEGLWindow : public ofAppBaseGLESWindow, public ofThread { void readNativeUDevEvents(); void readNativeInputEvents(); - void processInput(int fd, const char * node); + void processInput(int fd, const char * node); void addInput(const char * node, bool isMouse); void removeInput(const char * node); void printInput(); @@ -279,6 +279,7 @@ class ofAppEGLWindow : public ofAppBaseGLESWindow, public ofThread { private: ofAppEGLWindowSettings settings; int glesVersion; ///< \brief Indicate the version of OpenGL for Embedded Systems. + int glesVersionMinor; bool keyboardDetected; bool mouseDetected; long threadTimeout; diff --git a/libs/openFrameworks/app/ofAppRunner.cpp b/libs/openFrameworks/app/ofAppRunner.cpp index df84e27ffbb..ed2f10a396a 100644 --- a/libs/openFrameworks/app/ofAppRunner.cpp +++ b/libs/openFrameworks/app/ofAppRunner.cpp @@ -206,7 +206,19 @@ int ofRunMainLoop(){ void ofSetupOpenGL(int w, int h, ofWindowMode screenMode){ #ifdef TARGET_OPENGLES ofGLESWindowSettings settings; - settings.glesVersion = 1; + #ifdef GL_ES_VERSION_3_0 + #ifdef GL_ES_VERSION_3_1 + settings.setGLESVersion(3,1); + #else + settings.setGLESVersion(3,0); + #endif + #else + #ifdef GL_ES_VERSION_2_0 + settings.setGLESVersion(2); + #else + settings.setGLESVersion(1); + #endif + #endif #else ofGLWindowSettings settings; settings.glVersionMajor = 2; diff --git a/libs/openFrameworks/app/ofWindowSettings.h b/libs/openFrameworks/app/ofWindowSettings.h index 9d13d24de05..dd14368e026 100644 --- a/libs/openFrameworks/app/ofWindowSettings.h +++ b/libs/openFrameworks/app/ofWindowSettings.h @@ -49,7 +49,10 @@ class ofWindowSettings{ ,height(768) ,sizeSet(false) ,position(0,0) - ,positionSet(false){} + ,positionSet(false) + ,hiDPI(false) {} + + ofWindowSettings(const ofWindowSettings& other) = default; virtual ~ofWindowSettings(){}; @@ -87,12 +90,21 @@ class ofWindowSettings{ return positionSet; } + bool isHiDPI() const { + return hiDPI; + } + + void setHiDPI(const bool isHighDPI=true) { + hiDPI=isHighDPI; + } + protected: int width; int height; bool sizeSet; glm::vec2 position; bool positionSet; + bool hiDPI; }; class ofGLWindowSettings: public ofWindowSettings{ @@ -101,6 +113,8 @@ class ofGLWindowSettings: public ofWindowSettings{ :glVersionMajor(2) ,glVersionMinor(1){} + ofGLWindowSettings(const ofGLWindowSettings& other) = default; + ofGLWindowSettings(const ofWindowSettings & settings) :ofWindowSettings(settings) ,glVersionMajor(2) @@ -125,22 +139,30 @@ class ofGLWindowSettings: public ofWindowSettings{ class ofGLESWindowSettings: public ofWindowSettings{ public: - ofGLESWindowSettings() - :glesVersion(1){} + ofGLESWindowSettings() + :glesVersion(1), glesVersionMinor(0){} - ofGLESWindowSettings(const ofWindowSettings & settings) - :ofWindowSettings(settings), glesVersion(1) { + ofGLESWindowSettings(const ofGLESWindowSettings& other) = default; + + ofGLESWindowSettings(const ofWindowSettings & settings) + :ofWindowSettings(settings), glesVersion(1), glesVersionMinor(0) { const ofGLESWindowSettings * glesSettings = dynamic_cast(&settings); if(glesSettings){ glesVersion = glesSettings->glesVersion; + glesVersionMinor = glesSettings->glesVersionMinor; } } + + virtual ~ofGLESWindowSettings(){}; + + void setGLESVersion(int versionMajor, int versionMinor = 0){ + glesVersion = versionMajor; + glesVersionMinor = versionMinor; + } - virtual ~ofGLESWindowSettings(){}; - - void setGLESVersion(int version){ - glesVersion = version; - } + int getGLESVersionMajor() const { return glesVersion; } + int getGLESVersionMinor() const { return glesVersionMinor ; } - int glesVersion; + int glesVersion; + int glesVersionMinor; }; diff --git a/libs/openFrameworks/gl/ofBufferObject.cpp b/libs/openFrameworks/gl/ofBufferObject.cpp index db752728744..3517efecca1 100644 --- a/libs/openFrameworks/gl/ofBufferObject.cpp +++ b/libs/openFrameworks/gl/ofBufferObject.cpp @@ -81,7 +81,7 @@ void ofBufferObject::unbind(GLenum target) const{ } } -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) void ofBufferObject::bindBase(GLenum target,GLuint index) const{ if(data){ glBindBufferBase(target,index,data->id); @@ -187,7 +187,9 @@ void * ofBufferObject::map(GLenum access){ return ret; } +#endif +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) void ofBufferObject::unmap(){ if(!this->data) return; @@ -262,9 +264,15 @@ void ofBufferObject::copyTo(ofBufferObject & dstBuffer, int readOffset, int writ void ofBufferObject::invalidate(){ - glInvalidateBufferData(data->id); +#if !defined(TARGET_OPENGLES) || defined(GL_ES_VERSION_3_1) + // Desktop + GLES 3.1+ support glInvalidateBufferData + if (data && data->id != 0) { + glInvalidateBufferData(data->id); + } +#endif + // On GLES 2.0 / GLES 3.0 (including iOS with MetalANGLE) this is a no-op + // (the driver is free to ignore the hint anyway) } - #endif GLsizeiptr ofBufferObject::size() const{ diff --git a/libs/openFrameworks/gl/ofBufferObject.h b/libs/openFrameworks/gl/ofBufferObject.h index 637a5b318b1..1210b729492 100644 --- a/libs/openFrameworks/gl/ofBufferObject.h +++ b/libs/openFrameworks/gl/ofBufferObject.h @@ -41,7 +41,8 @@ class ofBufferObject { /// binds the passed target to buffer 0 void unbind(GLenum target) const; -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) + +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) /// glBindBufferBase: https://www.opengl.org/sdk/docs/man4/html/glBindBufferBase.xhtml void bindBase(GLenum target,GLuint index) const; @@ -102,11 +103,6 @@ class ofBufferObject { /// for this buffer and mapping that target void * map(GLenum access); - /// glUnmapNamedBuffer: https://www.opengl.org/sdk/docs/man4/html/glUnmapBuffer.xhtml - /// before GL 4.5 emulates glUnmapNamedBuffer by unmapping and unbinding - /// the last known target for this buffer - void unmap(); - /// typed version of map, returns an array of T when used like: /// buffer.map(access) template @@ -114,6 +110,14 @@ class ofBufferObject { return static_cast(map(access)); } +#endif + +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + /// glUnmapNamedBuffer: https://www.opengl.org/sdk/docs/man4/html/glUnmapBuffer.xhtml + /// before GL 4.5 emulates glUnmapNamedBuffer by unmapping and unbinding + /// the last known target for this buffer + void unmap(); + /// glMapNamedBufferRange: https://www.opengl.org/sdk/docs/man4/html/glMapBufferRange.xhtml /// before GL 4.5 emulates glMapNamedBufferRange by binding to last known target /// for this buffer and mapping that target diff --git a/libs/openFrameworks/gl/ofFbo.cpp b/libs/openFrameworks/gl/ofFbo.cpp index edf6e842e5f..cf0ec24f7cc 100644 --- a/libs/openFrameworks/gl/ofFbo.cpp +++ b/libs/openFrameworks/gl/ofFbo.cpp @@ -34,7 +34,7 @@ using std::vector; */ -#if defined(TARGET_OPENGLES) & !defined(TARGET_EMSCRIPTEN) +#if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) bool ofFbo::bglFunctionsInitialized=false; typedef void (* glGenFramebuffersType) (GLsizei n, GLuint* framebuffers); @@ -246,7 +246,7 @@ dirty(false), defaultTextureIndex(0), bIsAllocated(false) { -#if defined(TARGET_OPENGLES) & !defined(TARGET_EMSCRIPTEN) +#if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) if(!bglFunctionsInitialized){ if(ofIsGLProgrammableRenderer()){ glGenFramebuffers = (glGenFramebuffersType)dlsym(RTLD_DEFAULT, "glGenFramebuffers"); @@ -302,12 +302,12 @@ ofFbo::ofFbo(const ofFbo & mom){ textures = mom.textures; dirty = mom.dirty; defaultTextureIndex = mom.defaultTextureIndex; - activeDrawBuffers = mom.activeDrawBuffers; - if(fbo!=0){ - #ifdef TARGET_ANDROID - ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); - #endif - } + activeDrawBuffers = mom.activeDrawBuffers; + if(fbo!=0){ + #ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); + #endif + } } //-------------------------------------------------------------- @@ -322,11 +322,11 @@ ofFbo & ofFbo::operator=(const ofFbo & mom){ fboTextures = mom.fboTextures; if(settings.numSamples){ retainFB(fboTextures); - } - if(mom.settings.depthStencilAsTexture){ - depthBufferTex = mom.depthBufferTex; - }else{ - depthBuffer = mom.depthBuffer; + } + if(mom.settings.depthStencilAsTexture){ + depthBufferTex = mom.depthBufferTex; + }else{ + depthBuffer = mom.depthBuffer; retainRB(depthBuffer); } stencilBuffer = mom.stencilBuffer; @@ -339,12 +339,12 @@ ofFbo & ofFbo::operator=(const ofFbo & mom){ textures = mom.textures; dirty = mom.dirty; defaultTextureIndex = mom.defaultTextureIndex; - activeDrawBuffers = mom.activeDrawBuffers; - if(fbo!=0){ - #ifdef TARGET_ANDROID - ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); - #endif - } + activeDrawBuffers = mom.activeDrawBuffers; + if(fbo!=0){ + #ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); + #endif + } return *this; } @@ -361,47 +361,47 @@ ofFbo::ofFbo(ofFbo && mom) ,dirty(std::move(mom.dirty)) ,defaultTextureIndex(std::move(mom.defaultTextureIndex)) ,bIsAllocated(std::move(mom.bIsAllocated)){ - if(fbo!=0){ - #ifdef TARGET_ANDROID - ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); - #endif - } - mom.fbo = 0; - mom.depthBuffer = 0; - mom.fboTextures = 0; - mom.stencilBuffer = 0; + if(fbo!=0){ + #ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); + #endif + } + mom.fbo = 0; + mom.depthBuffer = 0; + mom.fboTextures = 0; + mom.stencilBuffer = 0; } ofFbo & ofFbo::operator=(ofFbo && mom){ - if(&mom==this) return *this; - clear(); - settings = std::move(mom.settings); - bIsAllocated = std::move(mom.bIsAllocated); - - fbo = mom.fbo; - fboTextures = mom.fboTextures; - if(mom.settings.depthStencilAsTexture){ - depthBufferTex = std::move(mom.depthBufferTex); - }else{ - depthBuffer = mom.depthBuffer; - } - stencilBuffer = std::move(mom.stencilBuffer); - - colorBuffers = std::move(mom.colorBuffers); - textures = std::move(mom.textures); - dirty = std::move(mom.dirty); - defaultTextureIndex = std::move(mom.defaultTextureIndex); - - if(fbo!=0){ - #ifdef TARGET_ANDROID - ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); - #endif - } - mom.fbo = 0; - mom.depthBuffer = 0; - mom.fboTextures = 0; - mom.stencilBuffer = 0; - return *this; + if(&mom==this) return *this; + clear(); + settings = std::move(mom.settings); + bIsAllocated = std::move(mom.bIsAllocated); + + fbo = mom.fbo; + fboTextures = mom.fboTextures; + if(mom.settings.depthStencilAsTexture){ + depthBufferTex = std::move(mom.depthBufferTex); + }else{ + depthBuffer = mom.depthBuffer; + } + stencilBuffer = std::move(mom.stencilBuffer); + + colorBuffers = std::move(mom.colorBuffers); + textures = std::move(mom.textures); + dirty = std::move(mom.dirty); + defaultTextureIndex = std::move(mom.defaultTextureIndex); + + if(fbo!=0){ + #ifdef TARGET_ANDROID + ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); + #endif + } + mom.fbo = 0; + mom.depthBuffer = 0; + mom.fboTextures = 0; + mom.stencilBuffer = 0; + return *this; } //-------------------------------------------------------------- @@ -462,7 +462,7 @@ void ofFbo::clear() { } -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) //-------------------------------------------------------------- void ofFbo::clearColorBuffer(const ofFloatColor & color){ glClearBufferfv(GL_COLOR, 0, &color.r); @@ -496,8 +496,8 @@ void ofFbo::destroy() { //-------------------------------------------------------------- bool ofFbo::checkGLSupport() { -#ifndef TARGET_OPENGLES - +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + // Desktop + GLES 3.0+ (FBO is core spec — no extension check needed on ES3) if (!ofIsGLProgrammableRenderer()){ if(ofGLCheckExtension("GL_EXT_framebuffer_object")){ ofLogVerbose("ofFbo") << "GL frame buffer object supported"; @@ -506,17 +506,16 @@ bool ofFbo::checkGLSupport() { return false; } } - glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &_maxColorAttachments); glGetIntegerv(GL_MAX_DRAW_BUFFERS, &_maxDrawBuffers); glGetIntegerv(GL_MAX_SAMPLES, &_maxSamples); ofLogVerbose("ofFbo") << "checkGLSupport(): " - << "maxColorAttachments: " << _maxColorAttachments << ", " - << "maxDrawBuffers: " << _maxDrawBuffers << ", " - << "maxSamples: " << _maxSamples; + << "maxColorAttachments: " << _maxColorAttachments << ", " + << "maxDrawBuffers: " << _maxDrawBuffers << ", " + << "maxSamples: " << _maxSamples; #else - + // GLES 2.0 — FBO is still an extension (GL_OES_framebuffer_object) if(ofIsGLProgrammableRenderer() || ofGLCheckExtension("GL_OES_framebuffer_object")){ ofLogVerbose("ofFbo") << "GL frame buffer object supported"; }else{ @@ -524,7 +523,6 @@ bool ofFbo::checkGLSupport() { return false; } #endif - return true; } @@ -532,21 +530,25 @@ bool ofFbo::checkGLSupport() { //-------------------------------------------------------------- void ofFbo::allocate(int width, int height, int internalformat, int numSamples) { - settings.width = width; - settings.height = height; - settings.internalformat = internalformat; - settings.numSamples = numSamples; + settings.width = width; + settings.height = height; + settings.internalformat = internalformat; + settings.numSamples = numSamples; #ifdef TARGET_OPENGLES - settings.useDepth = false; - settings.useStencil = false; - //we do this as the fbo and the settings object it contains could be created before the user had the chance to disable or enable arb rect. - settings.textureTarget = GL_TEXTURE_2D; + settings.textureTarget = GL_TEXTURE_2D; +#else + settings.textureTarget = ofGetUsingArbTex() ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D; +#endif + +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + // GLES 3.0+ (and desktop) can safely default to depth + stencil + settings.useDepth = true; + settings.useStencil = true; #else - settings.useDepth = true; - settings.useStencil = true; //we do this as the fbo and the settings object it contains could be created before the user had the chance to disable or enable arb rect. - settings.textureTarget = ofGetUsingArbTex() ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D; + settings.useDepth = false; + settings.useStencil = false; #endif allocate(settings); @@ -580,14 +582,14 @@ void ofFbo::allocate(ofFboSettings _settings) { //currently depth only works if stencil is enabled. // http://forum.openframeworks.cc/index.php/topic,6837.0.html -#ifdef TARGET_OPENGLES +#if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) if(_settings.useDepth){ - _settings.useStencil = true; + _settings.useStencil = true; + } + if( _settings.depthStencilAsTexture ){ + _settings.depthStencilAsTexture = false; + ofLogWarning("ofFbo") << "allocate(): depthStencilAsTexture is not available for iOS"; } - if( _settings.depthStencilAsTexture ){ - _settings.depthStencilAsTexture = false; - ofLogWarning("ofFbo") << "allocate(): depthStencilAsTexture is not available for iOS"; - } #endif GLenum depthAttachment = GL_DEPTH_ATTACHMENT; @@ -645,31 +647,31 @@ void ofFbo::allocate(ofFboSettings _settings) { }else{ if(_settings.useDepth || _settings.useStencil){ createAndAttachDepthStencilTexture(_settings.textureTarget,_settings.depthStencilInternalFormat,depthAttachment); - #ifdef TARGET_OPENGLES - // if there's depth and stencil the texture should be attached as - // depth and stencil attachments - // http://www.khronos.org/registry/gles/extensions/OES/OES_packed_depth_stencil.txt - if(_settings.useDepth && _settings.useStencil){ - glFramebufferTexture2D(GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, depthBufferTex.texData.textureID, 0); - } + #if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + // GLES 2.0 only: OES_packed_depth_stencil extension requires separate stencil attachment + // http://www.khronos.org/registry/gles/extensions/OES/OES_packed_depth_stencil.txt + if(_settings.useDepth && _settings.useStencil){ + glFramebufferTexture2D(GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, depthBufferTex.texData.textureID, 0); + } #endif } } - settings.useDepth = _settings.useDepth; - settings.useStencil = _settings.useStencil; - settings.depthStencilInternalFormat = _settings.depthStencilInternalFormat; - settings.depthStencilAsTexture = _settings.depthStencilAsTexture; - settings.textureTarget = _settings.textureTarget; - settings.wrapModeHorizontal = _settings.wrapModeHorizontal; - settings.wrapModeVertical = _settings.wrapModeVertical; - settings.maxFilter = _settings.maxFilter; - settings.minFilter = _settings.minFilter; + settings.useDepth = _settings.useDepth; + settings.useStencil = _settings.useStencil; + settings.depthStencilInternalFormat = _settings.depthStencilInternalFormat; + settings.depthStencilAsTexture = _settings.depthStencilAsTexture; + settings.textureTarget = _settings.textureTarget; + settings.wrapModeHorizontal = _settings.wrapModeHorizontal; + settings.wrapModeVertical = _settings.wrapModeVertical; + settings.maxFilter = _settings.maxFilter; + settings.minFilter = _settings.minFilter; // if we want MSAA, create a new fbo for textures - #ifndef TARGET_OPENGLES + // (supported on desktop + GLES 3.0+; pure GLES 2.0 does not support multisampled FBOs reliably) + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) if(_settings.numSamples){ glGenFramebuffers(1, &fboTextures); retainFB(fboTextures); @@ -679,7 +681,7 @@ void ofFbo::allocate(ofFboSettings _settings) { #else fboTextures = fbo; if(_settings.numSamples){ - ofLogWarning("ofFbo") << "allocate(): multisampling not supported in OpenGL ES"; + ofLogWarning("ofFbo") << "allocate(): multisampling not supported in OpenGL ES < 3.0"; } #endif @@ -690,11 +692,11 @@ void ofFbo::allocate(ofFboSettings _settings) { for(int i=0; i<_settings.numColorbuffers; i++) createAndAttachTexture(_settings.internalformat, i); _settings.colorFormats = settings.colorFormats; } else { -#ifndef TARGET_OPENGLES + #ifndef TARGET_OPENGLES glDrawBuffer(GL_NONE); -#else + #else ofLogWarning("ofFbo") << "allocate(): no color buffers specified for frame buffer object " << fbo; -#endif + #endif } settings.internalformat = _settings.internalformat; @@ -711,12 +713,12 @@ void ofFbo::allocate(ofFboSettings _settings) { // restore previous framebuffer id glBindFramebuffer(GL_FRAMEBUFFER, previousFboId); - /* UNCOMMENT OUTSIDE OF DOING RELEASES + /* UNCOMMENT OUTSIDE OF DOING RELEASES - // this should never happen + // this should never happen if(settings != _settings) ofLogWarning("ofFbo") << "allocation not complete, passed settings not equal to created ones, this is an internal OF bug"; - */ + */ #ifdef TARGET_ANDROID ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); #endif @@ -739,23 +741,29 @@ GLuint ofFbo::createAndAttachRenderbuffer(GLenum internalFormat, GLenum attachme GLuint buffer; glGenRenderbuffers(1, &buffer); glBindRenderbuffer(GL_RENDERBUFFER, buffer); -#ifndef TARGET_OPENGLES - if (settings.numSamples==0) { + +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + // Desktop + GLES 3.0+ support full multisampled renderbuffers + if (settings.numSamples == 0) { glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, settings.width, settings.height); } else { glRenderbufferStorageMultisample(GL_RENDERBUFFER, settings.numSamples, internalFormat, settings.width, settings.height); } #else - if(ofGLSupportsNPOTTextures()){ + // Pure GLES 2.0 — no reliable MSAA + sometimes needs power-of-two textures + if (ofGLSupportsNPOTTextures()) { glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, settings.width, settings.height); - }else{ + } else { glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, ofNextPow2(settings.width), ofNextPow2(settings.height)); } + if (settings.numSamples > 0) { + ofLogWarning("ofFbo") << "createAndAttachRenderbuffer(): multisampling not supported in OpenGL ES < 3.0"; + } #endif + glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentPoint, GL_RENDERBUFFER, buffer); return buffer; } - //---------------------------------------------------------- void ofFbo::createAndAttachTexture(GLenum internalFormat, GLenum attachmentPoint) { @@ -774,23 +782,23 @@ void ofFbo::createAndAttachTexture(GLenum internalFormat, GLenum attachmentPoint ofTexture tex; tex.allocate(texData); - attachTexture(tex, internalFormat, attachmentPoint); + attachTexture(tex, internalFormat, attachmentPoint); dirty.push_back(true); activeDrawBuffers.push_back(GL_COLOR_ATTACHMENT0 + attachmentPoint); } //---------------------------------------------------------- void ofFbo::attachTexture(ofTexture & tex, GLenum internalFormat, GLenum attachmentPoint) { - // bind fbo for textures (if using MSAA this is the newly created fbo, otherwise its the same fbo as before) + // bind fbo for textures (if using MSAA this is the newly created fbo, otherwise its the same fbo as before) GLint temp; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &temp); glBindFramebuffer(GL_FRAMEBUFFER, fboTextures); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachmentPoint, tex.texData.textureTarget, tex.texData.textureID, 0); - if(attachmentPoint >= textures.size()) { - textures.resize(attachmentPoint+1); - } - textures[attachmentPoint] = tex; + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachmentPoint, tex.texData.textureTarget, tex.texData.textureID, 0); + if(attachmentPoint >= textures.size()) { + textures.resize(attachmentPoint+1); + } + textures[attachmentPoint] = tex; settings.colorFormats.resize(attachmentPoint + 1); settings.colorFormats[attachmentPoint] = internalFormat; @@ -843,20 +851,20 @@ void ofFbo::createAndAttachDepthStencilTexture(GLenum target, GLint internalform void ofFbo::begin(bool setupScreen) const{ auto renderer = settings.renderer.lock(); if(renderer){ - if(setupScreen){ - renderer->begin(*this, OF_FBOMODE_PERSPECTIVE | OF_FBOMODE_MATRIXFLIP); - }else{ - renderer->begin(*this, OF_FBOMODE_NODEFAULTS); - } + if(setupScreen){ + renderer->begin(*this, OF_FBOMODE_PERSPECTIVE | OF_FBOMODE_MATRIXFLIP); + }else{ + renderer->begin(*this, OF_FBOMODE_NODEFAULTS); + } } } void ofFbo::begin(ofFboMode mode) const{ - auto renderer = settings.renderer.lock(); - if(renderer){ - renderer->begin(*this, mode); - } + auto renderer = settings.renderer.lock(); + if(renderer){ + renderer->begin(*this, mode); + } } @@ -942,7 +950,7 @@ int ofFbo::getNumTextures() const { //---------------------------------------------------------- void ofFbo::setActiveDrawBuffer(int i){ if(!bIsAllocated) return; -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) vector activebuffers(1, i); setActiveDrawBuffers(activebuffers); #endif @@ -951,33 +959,36 @@ void ofFbo::setActiveDrawBuffer(int i){ //---------------------------------------------------------- void ofFbo::setActiveDrawBuffers(const vector& ids){ if(!bIsAllocated) return; -#ifndef TARGET_OPENGLES - int numBuffers = activeDrawBuffers.size(); + +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + int numBuffers = activeDrawBuffers.size(); activeDrawBuffers.clear(); activeDrawBuffers.resize(numBuffers, GL_NONE); // we initialise the vector with GL_NONE, so a buffer will not be written to unless activated. - for(int i=0; i < (int)ids.size(); i++){ - int id = ids[i]; - if (id < getNumTextures()){ - GLenum e = GL_COLOR_ATTACHMENT0 + id; - activeDrawBuffers[id] = e; // activate requested buffers - dirty[id] = true; // dirty activated draw buffers. - }else{ - ofLogWarning("ofFbo") << "setActiveDrawBuffers(): fbo " << fbo << " couldn't set texture " << i << ", only " << getNumTextures() << "allocated"; - } - } - glDrawBuffers(activeDrawBuffers.size(),&activeDrawBuffers[0]); + + for(int i = 0; i < (int)ids.size(); i++){ + int id = ids[i]; + if(id < getNumTextures()){ + GLenum e = GL_COLOR_ATTACHMENT0 + id; + activeDrawBuffers[id] = e; // activate requested buffers + dirty[id] = true; // dirty activated draw buffers + }else{ + ofLogWarning("ofFbo") << "setActiveDrawBuffers(): fbo " << fbo << " couldn't set texture " << i << ", only " << getNumTextures() << " allocated"; + } + } + + glDrawBuffers(activeDrawBuffers.size(), &activeDrawBuffers[0]); #endif } //---------------------------------------------------------- void ofFbo::activateAllDrawBuffers(){ if(!bIsAllocated) return; -#ifndef TARGET_OPENGLES - vector activeBuffers(getNumTextures(),0); - for(int i=0; i < getNumTextures(); i++){ - activeBuffers[i] = i; - } - setActiveDrawBuffers(activeBuffers); +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + vector activeBuffers(getNumTextures(), 0); + for(int i = 0; i < getNumTextures(); i++){ + activeBuffers[i] = i; + } + setActiveDrawBuffers(activeBuffers); #endif } @@ -1022,7 +1033,7 @@ ofTexture& ofFbo::getTexture(){ ofTexture& ofFbo::getTexture(int attachmentPoint) { updateTexture(attachmentPoint); - return textures[attachmentPoint]; + return textures[attachmentPoint]; } //---------------------------------------------------------- @@ -1035,7 +1046,7 @@ const ofTexture& ofFbo::getTexture(int attachmentPoint) const{ ofFbo * mutThis = const_cast(this); mutThis->updateTexture(attachmentPoint); - return textures[attachmentPoint]; + return textures[attachmentPoint]; } //---------------------------------------------------------- @@ -1056,13 +1067,15 @@ void ofFbo::resetAnchor(){ //---------------------------------------------------------- void ofFbo::readToPixels(ofPixels & pixels, int attachmentPoint) const{ if(!bIsAllocated) return; -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + // Desktop + GLES 3.0+ getTexture(attachmentPoint).readToPixels(pixels); #else - pixels.allocate(settings.width,settings.height,ofGetImageTypeFromGLType(settings.internalformat)); + // GLES 2.0 — glReadPixels is still required + pixels.allocate(settings.width, settings.height, ofGetImageTypeFromGLType(settings.internalformat)); bind(); int format = ofGetGLFormatFromInternal(settings.internalformat); - glReadPixels(0,0,settings.width, settings.height, format, GL_UNSIGNED_BYTE, pixels.getData()); + glReadPixels(0, 0, settings.width, settings.height, format, GL_UNSIGNED_BYTE, pixels.getData()); unbind(); #endif } @@ -1070,13 +1083,13 @@ void ofFbo::readToPixels(ofPixels & pixels, int attachmentPoint) const{ //---------------------------------------------------------- void ofFbo::readToPixels(ofShortPixels & pixels, int attachmentPoint) const{ if(!bIsAllocated) return; -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) getTexture(attachmentPoint).readToPixels(pixels); #else - pixels.allocate(settings.width,settings.height,ofGetImageTypeFromGLType(settings.internalformat)); + pixels.allocate(settings.width, settings.height, ofGetImageTypeFromGLType(settings.internalformat)); bind(); int format = ofGetGLFormatFromInternal(settings.internalformat); - glReadPixels(0,0,settings.width, settings.height, format, GL_UNSIGNED_SHORT, pixels.getData()); + glReadPixels(0, 0, settings.width, settings.height, format, GL_UNSIGNED_SHORT, pixels.getData()); unbind(); #endif } @@ -1084,7 +1097,7 @@ void ofFbo::readToPixels(ofShortPixels & pixels, int attachmentPoint) const{ //---------------------------------------------------------- void ofFbo::readToPixels(ofFloatPixels & pixels, int attachmentPoint) const{ if(!bIsAllocated) return; -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) getTexture(attachmentPoint).readToPixels(pixels); #else pixels.allocate(settings.width,settings.height,ofGetImageTypeFromGLType(settings.internalformat)); @@ -1095,7 +1108,7 @@ void ofFbo::readToPixels(ofFloatPixels & pixels, int attachmentPoint) const{ #endif } -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) //---------------------------------------------------------- void ofFbo::copyTo(ofBufferObject & buffer) const{ if(!bIsAllocated) return; @@ -1110,34 +1123,40 @@ void ofFbo::copyTo(ofBufferObject & buffer) const{ //---------------------------------------------------------- void ofFbo::updateTexture(int attachmentPoint) { if(!bIsAllocated) return; -#ifndef TARGET_OPENGLES + +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) if(fbo != fboTextures && dirty[attachmentPoint]) { // if fbo != fboTextures, we are dealing with an MSAA enabled FBO. - // and we need to blit one fbo into another to see get the texture - // content + // we need to blit one fbo into another to update the texture content +#ifndef TARGET_OPENGLES + // glPushAttrib / glPopAttrib are desktop fixed-function only + // save current drawbuffer (fixed-function desktop only) if (!ofIsGLProgrammableRenderer()){ - // save current drawbuffer glPushAttrib(GL_COLOR_BUFFER_BIT); } +#endif auto renderer = settings.renderer.lock(); if(renderer){ GLint readBuffer; glGetIntegerv(GL_READ_BUFFER, &readBuffer); - renderer->bindForBlitting(*this,*this,attachmentPoint); + renderer->bindForBlitting(*this, *this, attachmentPoint); glBlitFramebuffer(0, 0, settings.width, settings.height, 0, 0, settings.width, settings.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); renderer->unbind(*this); glReadBuffer(readBuffer); } +#ifndef TARGET_OPENGLES if(!ofIsGLProgrammableRenderer()){ // restore current drawbuffer glPopAttrib(); } +#endif + dirty[attachmentPoint] = false; } #endif @@ -1151,7 +1170,7 @@ void ofFbo::draw(float x, float y) const{ //---------------------------------------------------------- void ofFbo::draw(float x, float y, float width, float height) const{ if(!bIsAllocated || settings.numColorbuffers==0) return; - getTexture().draw(x, y, width, height); + getTexture().draw(x, y, width, height); } //---------------------------------------------------------- @@ -1185,46 +1204,52 @@ float ofFbo::getHeight() const { bool ofFbo::checkStatus() const { GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); switch(status) { - case GL_FRAMEBUFFER_COMPLETE: - ofLogVerbose("ofFbo") << "FRAMEBUFFER_COMPLETE - OK"; - return true; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; - break; + case GL_FRAMEBUFFER_COMPLETE: + ofLogVerbose("ofFbo") << "FRAMEBUFFER_COMPLETE - OK"; + return true; + + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; + break; + #ifndef TARGET_PROGRAMMABLE_GL - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS: - ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_FORMATS"; - break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS: + ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_FORMATS"; + break; #endif - case GL_FRAMEBUFFER_UNSUPPORTED: - ofLogError("ofFbo") << "FRAMEBUFFER_UNSUPPORTED"; - break; -#ifndef TARGET_OPENGLES - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - ofLogWarning("ofFbo") << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - ofLogError("ofFbo") << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; - break; + + case GL_FRAMEBUFFER_UNSUPPORTED: + ofLogError("ofFbo") << "FRAMEBUFFER_UNSUPPORTED"; + break; + +#if !defined(TARGET_OPENGLES) + // these error codes are available on desktop + GLES 3.0+ + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + ofLogWarning("ofFbo") << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; + break; +#endif +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: + ofLogError("ofFbo") << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; + break; #endif - default: - ofLogError("ofFbo") << "UNKNOWN ERROR " << status; - break; + default: + ofLogError("ofFbo") << "UNKNOWN ERROR " << status; + break; } return false; } - //---------------------------------------------------------- ofTexture & ofFbo::getDepthTexture(){ if(!settings.depthStencilAsTexture){ @@ -1241,4 +1266,4 @@ const ofTexture & ofFbo::getDepthTexture() const{ return depthBufferTex; } -//#endif + diff --git a/libs/openFrameworks/gl/ofFbo.h b/libs/openFrameworks/gl/ofFbo.h index 67221fb4a67..9cbea2a8e41 100644 --- a/libs/openFrameworks/gl/ofFbo.h +++ b/libs/openFrameworks/gl/ofFbo.h @@ -65,7 +65,7 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { void destroy(); void clear(); -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) /// glClearBufferfv(GL_COLOR, 0...) /// /// @see: https://www.opengl.org/wiki/GLAPI/glClearBuffer @@ -122,7 +122,7 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { /// Sets up the framebuffer and binds it for rendering. /// - /// \warning This is a convenience method, and is considered unsafe + /// \warning This is a convenience method, and is considered unsafe /// in multi-window and/or multi-renderer scenarios. /// If you use more than one renderer, use each renderer's /// explicit void ofBaseGLRenderer::begin(const ofFbo & fbo, ofFboMode mode) @@ -166,7 +166,7 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { void readToPixels(ofShortPixels & pixels, int attachmentPoint = 0) const; void readToPixels(ofFloatPixels & pixels, int attachmentPoint = 0) const; -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) /// \brief Copy the fbo to an ofBufferObject. /// \param buffer the target buffer to copy to. void copyTo(ofBufferObject & buffer) const; @@ -189,7 +189,7 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { /// \sa virtual void ofBaseGLRenderer::bind(const ofFbo & fbo) void bind() const; - /// \brief Unbinds OpenGL framebuffer target and restores the OpenGL framebuffer + /// \brief Unbinds OpenGL framebuffer target and restores the OpenGL framebuffer /// render target to whatever this ofFbo stores in previousFramebufferBinding. /// \sa bind() /// \sa void setPreviousFramebufferBinding(const GLuint& previousFramebufferBinding_) const @@ -197,9 +197,9 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { void flagDirty() const; ///< check whether attached MSAA buffers need updating - /// \brief Explicityl resolve MSAA render buffers into textures - /// \note if using MSAA, we will have rendered into a colorbuffer, not directly - /// into the texture call this to blit from the colorbuffer into the texture + /// \brief Explicityl resolve MSAA render buffers into textures + /// \note if using MSAA, we will have rendered into a colorbuffer, not directly + /// into the texture call this to blit from the colorbuffer into the texture /// so we can use the results for rendering, or input to a shader etc. /// \note This will get called implicitly upon getTexture(); void updateTexture(int attachmentPoint); @@ -244,7 +244,7 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { GLuint stencilBuffer; std::vector colorBuffers; - std::vector textures; + std::vector textures; ofTexture depthBufferTex; @@ -255,9 +255,9 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { std::vector activeDrawBuffers; ///< table of currently active color draw buffers, allocate() defaults it to size(textures), with GL_COLOR_ATTACHMENT0..n as members, in order of allocation /// \brief Flags used internally to keep track of MSAA renderbuffers / textures - /// \note The dirty flags are only used when dealing if the framebuffer has MSAA + /// \note The dirty flags are only used when dealing if the framebuffer has MSAA /// enabled attachments, i.e. numSamples is > 0 and extra Textures have - /// been bound so that the multisampled renderbuffers can be resolved to + /// been bound so that the multisampled renderbuffers can be resolved to /// textures. /// The flags are read whenever an attached texture is accessed. If the texture /// is dirty, i.e. it has not yet been resolved from its associated renderbuffer @@ -267,7 +267,7 @@ class ofFbo : public ofBaseDraws, public ofBaseHasTexture { int defaultTextureIndex; //used for getTextureReference bool bIsAllocated; void reloadFbo(); -#ifdef TARGET_OPENGLES +#if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) static bool bglFunctionsInitialized; #endif diff --git a/libs/openFrameworks/gl/ofGLBaseTypes.h b/libs/openFrameworks/gl/ofGLBaseTypes.h index 5fae80f2b59..8009887e9e7 100644 --- a/libs/openFrameworks/gl/ofGLBaseTypes.h +++ b/libs/openFrameworks/gl/ofGLBaseTypes.h @@ -516,7 +516,7 @@ class ofBaseGLRenderer: public ofBaseRenderer{ /// \param fbo The frame buffer that is currently bound to this renderer. virtual void unbind(const ofFbo & fbo)=0; -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) /// \brief Bind source and destination frame buffers for blitting. /// /// \param fboSrc The source frame buffer to bind for blitting. diff --git a/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp b/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp index 9ee3712a725..8c311d6ad9e 100644 --- a/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp +++ b/libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp @@ -119,15 +119,8 @@ void ofGLProgrammableRenderer::finishRender() { void ofGLProgrammableRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode renderType, bool useColors, bool useTextures, bool useNormals) const { if (vertexData.getVertices().empty()) return; - // tig: note that for GL3+ we use glPolygonMode to draw wireframes or filled meshes, and not the primitive mode. - // the reason is not purely aesthetic, but more conformant with the behaviour of ofGLRenderer. Whereas - // gles2.0 doesn't allow for a polygonmode. - // Also gles2 still supports vertex array syntax for uploading data to attributes and it seems to be faster than - // vbo's for meshes that are updated frequently so let's use that instead - - //if (bSmoothHinted) startSmoothing(); - -#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN) +#ifdef TARGET_OPENGLES + // OpenGL ES path - use vertex attrib arrays (fast for frequently updated meshes) glEnableVertexAttribArray(ofShader::POSITION_ATTRIBUTE); glVertexAttribPointer(ofShader::POSITION_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, sizeof(typename ofMesh::VertexType), vertexData.getVerticesPointer()); @@ -155,61 +148,50 @@ void ofGLProgrammableRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode glDisableVertexAttribArray(ofShader::TEXCOORD_ATTRIBUTE); } - // const_cast(this)->setAttributes(true, useColors, useTextures, useNormals); - GLenum drawMode; switch (renderType) { - case OF_MESH_POINTS: - drawMode = GL_POINTS; - break; - case OF_MESH_WIREFRAME: - drawMode = GL_LINES; - break; - case OF_MESH_FILL: - drawMode = ofGetGLPrimitiveMode(vertexData.getMode()); - break; - default: - drawMode = ofGetGLPrimitiveMode(vertexData.getMode()); - break; + case OF_MESH_POINTS: drawMode = GL_POINTS; break; + case OF_MESH_WIREFRAME: drawMode = GL_LINES; break; + case OF_MESH_FILL: drawMode = ofGetGLPrimitiveMode(vertexData.getMode()); break; + default: drawMode = ofGetGLPrimitiveMode(vertexData.getMode()); break; } + const_cast(this)->setAttributes(true, useColors, useTextures, useNormals, drawMode); + #if defined(TARGET_EMSCRIPTEN) || defined(TARGET_OPENGLES) && defined(GL_ES_VERSION_3_0) + GLenum indexType = GL_UNSIGNED_INT; + #else + GLenum indexType = GL_UNSIGNED_SHORT; + #endif + if (vertexData.getNumIndices()) { - glDrawElements(drawMode, vertexData.getNumIndices(), GL_UNSIGNED_SHORT, vertexData.getIndexPointer()); + glDrawElements(drawMode, vertexData.getNumIndices(), indexType, vertexData.getIndexPointer()); } else { glDrawArrays(drawMode, 0, vertexData.getNumVertices()); } + #else - + // Desktop GL path - VBO + optional lines shader bundle ofVbo* vboToRender = nullptr; bool tGoingToRenderLines = false; -#ifndef TARGET_OPENGLES -// meshVbo.setMesh(vertexData, GL_STREAM_DRAW, useColors, useTextures, useNormals); + glPolygonMode(GL_FRONT_AND_BACK, ofGetGLPolyMode(renderType)); GLenum drawMode = ofGetGLPrimitiveMode(vertexData.getMode()); - // if the render type is different than the primitive mode - // ie. mesh mode is triangles but we called mesh.drawVertices() which uses GL_POINT for the render type - // however, we need GL_POINTS for rendering point sprites - if (pointSpritesEnabled && !usingCustomShader && !uniqueShader) { - if (renderType == OF_MESH_POINTS) { - drawMode = GL_POINTS; - } - } - + bool bConfigureForLinesShader = areLinesShadersEnabled() && (drawMode == GL_LINES || drawMode == GL_LINE_STRIP || drawMode == GL_LINE_LOOP); - if( usingCustomShader || usingCustomShader || currentMaterial) { + if (usingCustomShader || currentMaterial) { bConfigureForLinesShader = false; } - - if( bConfigureForLinesShader ) { + + if (bConfigureForLinesShader) { mDrawMode = drawMode; tGoingToRenderLines = true; ofGLProgrammableRenderer * mutThis = const_cast(this); - if( drawMode == GL_LINES ) { - mutThis->configureLinesBundleFromMesh( mutThis->mLinesBundleMap[GL_LINES], drawMode, vertexData); + if (drawMode == GL_LINES) { + mutThis->configureLinesBundleFromMesh(mutThis->mLinesBundleMap[GL_LINES], drawMode, vertexData); vboToRender = &mutThis->mLinesBundleMap[GL_LINES].vbo; } else { - mutThis->configureLinesBundleFromMesh( mutThis->mLinesBundleMap[GL_LINE_STRIP], drawMode, vertexData); + mutThis->configureLinesBundleFromMesh(mutThis->mLinesBundleMap[GL_LINE_STRIP], drawMode, vertexData); vboToRender = &mutThis->mLinesBundleMap[GL_LINE_STRIP].vbo; } } else { @@ -217,82 +199,29 @@ void ofGLProgrammableRenderer::draw(const ofMesh & vertexData, ofPolyRenderMode vboToRender = &meshVbo; } -#else -// meshVbo.setMesh(vertexData, GL_STATIC_DRAW, useColors, useTextures, useNormals); - GLenum drawMode; - switch (renderType) { - case OF_MESH_POINTS: - drawMode = GL_POINTS; - break; - case OF_MESH_WIREFRAME: - drawMode = GL_LINE_STRIP; - break; - case OF_MESH_FILL: - drawMode = ofGetGLPrimitiveMode(vertexData.getMode()); - break; - default: - drawMode = ofGetGLPrimitiveMode(vertexData.getMode()); - break; - } - - bool bConfigureForLinesShader = areLinesShadersEnabled() && (drawMode == GL_LINES || drawMode == GL_LINE_STRIP || drawMode == GL_LINE_LOOP); - if( usingCustomShader || usingCustomShader || currentMaterial) { - bConfigureForLinesShader = false; - } - - if(bConfigureForLinesShader) { - mDrawMode = drawMode; - tGoingToRenderLines = true; - ofGLProgrammableRenderer * mutThis = const_cast(this); - if( drawMode == GL_LINES ) { - mutThis->configureLinesBundleFromMesh( mutThis->mLinesBundleMap[GL_LINES], drawMode, vertexData); - vboToRender = &mutThis->mLinesBundleMap[GL_LINES].vbo; - } else { - mutThis->configureLinesBundleFromMesh( mutThis->mLinesBundleMap[GL_LINE_STRIP], drawMode, vertexData); - vboToRender = &mutThis->mLinesBundleMap[GL_LINE_STRIP].vbo; - } - } else { - meshVbo.setMesh(vertexData, GL_STATIC_DRAW, useColors, useTextures, useNormals); - vboToRender = &meshVbo; - } - - #endif - - if( vboToRender != nullptr ) { - if( tGoingToRenderLines ) { - // Setting a bool here so that the setAttributes function does not try to switch the shaders because - // we are going to draw the mesh as triangles and we need the lines shader - // we are rendering lines, and the meshes we constructed are made of triangles + if (vboToRender != nullptr) { + if (tGoingToRenderLines) { + // Setting a bool here so that the setAttributes function does not try to switch the shaders mBRenderingLines = true; - if( renderType == OF_MESH_FILL ) { + if (renderType == OF_MESH_FILL) { drawMode = GL_TRIANGLES; } } - + if (vboToRender->getUsingIndices()) { drawElements(*vboToRender, drawMode, vboToRender->getNumIndices()); } else { draw(*vboToRender, drawMode, 0, vboToRender->getNumVertices()); } - - if( tGoingToRenderLines ) { + + if (tGoingToRenderLines) { mBRenderingLines = false; } } - // tig: note further that we could glGet() and store the current polygon mode, but don't, since that would - // infer a massive performance hit. instead, we revert the glPolygonMode to mirror the current ofFill state - // after we're finished drawing, following the principle of least surprise. - // ideally the glPolygonMode (or the polygon draw mode) should be part of ofStyle so that we can keep track - // of its state on the client side... - - #ifndef TARGET_OPENGLES + // restore polygon mode to match current fill state glPolygonMode(GL_FRONT_AND_BACK, currentStyle.bFill ? GL_FILL : GL_LINE); - #endif - #endif - - //if (bSmoothHinted) endSmoothing(); } //---------------------------------------------------------- @@ -303,8 +232,10 @@ void ofGLProgrammableRenderer::draw(const ofVboMesh & mesh, ofPolyRenderMode ren //---------------------------------------------------------- void ofGLProgrammableRenderer::drawInstanced(const ofVboMesh & mesh, ofPolyRenderMode renderType, int primCount) const { if (mesh.getNumVertices() == 0) return; + GLuint mode = ofGetGLPrimitiveMode(mesh.getMode()); - // nh: if the render type is different than the primitive mode + + // if the render type is different than the primitive mode // ie. mesh mode is triangles but we called mesh.drawVertices() which uses GL_POINT for the render type // however, we need GL_POINTS for rendering point sprites if (pointSpritesEnabled) { @@ -312,48 +243,33 @@ void ofGLProgrammableRenderer::drawInstanced(const ofVboMesh & mesh, ofPolyRende mode = GL_POINTS; } } -#if !defined( TARGET_OPENGLES ) || defined(TARGET_EMSCRIPTEN) - #if !defined(TARGET_EMSCRIPTEN) + +#if !defined(TARGET_OPENGLES) + +#ifndef TARGET_OPENGLES glPolygonMode(GL_FRONT_AND_BACK, ofGetGLPolyMode(renderType)); - #else - // nh: glPolygonMode is not supported via emscripten, - // we can not render wire frames with vbos. - // this is not the best solution, but does provide some information - // and does not render as solid when wireframe mode is requested. - if (renderType == OF_MESH_WIREFRAME) { - if (mesh.getNumIndices()) { - drawElements(mesh.getVbo(), GL_LINES, mesh.getNumIndices()); +#endif + + if (mesh.getNumIndices() && renderType != OF_MESH_POINTS) { + if (primCount <= 1) { + drawElements(mesh.getVbo(), mode, mesh.getNumIndices()); } else { - draw(mesh.getVbo(), GL_LINES, 0, mesh.getNumVertices()); + drawElementsInstanced(mesh.getVbo(), mode, mesh.getNumIndices(), primCount); } } else { - #endif - if (mesh.getNumIndices() && renderType != OF_MESH_POINTS) { - if (primCount <= 1) { - drawElements(mesh.getVbo(), mode, mesh.getNumIndices()); - } else { - drawElementsInstanced(mesh.getVbo(), mode, mesh.getNumIndices(), primCount); - } + if (primCount <= 1) { + draw(mesh.getVbo(), mode, 0, mesh.getNumVertices()); } else { - if (primCount <= 1) { - draw(mesh.getVbo(), mode, 0, mesh.getNumVertices()); - } else { - drawInstanced(mesh.getVbo(), mode, 0, mesh.getNumVertices(), primCount); - } + drawInstanced(mesh.getVbo(), mode, 0, mesh.getNumVertices(), primCount); } - #if defined(TARGET_EMSCRIPTEN) - } // close the if for checking for wireframe - #endif + } +#ifndef TARGET_OPENGLES + // restore polygon mode to match current fill state + glPolygonMode(GL_FRONT_AND_BACK, currentStyle.bFill ? GL_FILL : GL_LINE); +#endif - // tig: note further that we could glGet() and store the current polygon mode, but don't, since that would - // infer a massive performance hit. instead, we revert the glPolygonMode to mirror the current ofFill state - // after we're finished drawing, following the principle of least surprise. - // ideally the glPolygonMode (or the polygon draw mode) should be part of ofStyle so that we can keep track - // of its state on the client side... - #if !defined(TARGET_EMSCRIPTEN) - glPolygonMode(GL_FRONT_AND_BACK, currentStyle.bFill ? GL_FILL : GL_LINE); - #endif #else + // Pure GLES 2.0 fallback — no polygon mode, no instancing if (renderType == OF_MESH_POINTS) { draw(mesh.getVbo(), GL_POINTS, 0, mesh.getNumVertices()); } else if (renderType == OF_MESH_WIREFRAME) { @@ -371,7 +287,6 @@ void ofGLProgrammableRenderer::drawInstanced(const ofVboMesh & mesh, ofPolyRende } #endif } - //---------------------------------------------------------- void ofGLProgrammableRenderer::draw(const of3dPrimitive & model, ofPolyRenderMode renderType) const { const_cast(this)->pushMatrix(); @@ -396,43 +311,32 @@ void ofGLProgrammableRenderer::draw(const ofNode & node) const { void ofGLProgrammableRenderer::draw(const ofPolyline & poly) const { if (poly.getVertices().empty()) return; - // use smoothness, if requested: - //if (bSmoothHinted) startSmoothing(); - -#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN) - +#if defined(TARGET_OPENGLES) + // OpenGL ES path - direct vertex attrib arrays (fast for frequently updated polylines) glEnableVertexAttribArray(ofShader::POSITION_ATTRIBUTE); glVertexAttribPointer(ofShader::POSITION_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, sizeof(typename ofPolyline::VertexType), &poly[0]); - // const_cast(this)->setAttributes(true, false, false, false); - GLenum drawMode = poly.isClosed() ? GL_LINE_LOOP : GL_LINE_STRIP; const_cast(this)->setAttributes(true, false, false, false, drawMode); - glDrawArrays(drawMode, 0, poly.size()); #else - -// polylineMesh.clear(); -// polylineMesh.addVertices(poly.getVertices()); - - + // Desktop GL path - use VBO mesh polylineMesh.getVertices() = poly.getVertices(); - // check if it is closed and the last point is the same as the first - if( poly.isClosed() ) { - if(polylineMesh.getNumVertices() > 1 && polylineMesh.getVertices().front() == polylineMesh.getVertices().back() ) { + if (poly.isClosed()) { + if (polylineMesh.getNumVertices() > 1 && polylineMesh.getVertices().front() == polylineMesh.getVertices().back()) { polylineMesh.getVertices().pop_back(); } } - - if( currentTextureTarget != OF_NO_TEXTURE ) { + + if (currentTextureTarget != OF_NO_TEXTURE) { // TODO: Should we be able to set tex coords on polylines somehow?? - polylineMesh.getTexCoords().resize( polylineMesh.getNumVertices(), glm::vec2(0.f, 0.f)); + polylineMesh.getTexCoords().resize(polylineMesh.getNumVertices(), glm::vec2(0.f, 0.f)); auto& tcs = polylineMesh.getTexCoords(); int numtxs = (int)polylineMesh.getNumVertices(); float numTxsF = (float)numtxs - 1.f; - if( numTxsF > 0.0f ) { - for( int ix = 0; ix < numtxs; ix++ ) { + if (numTxsF > 0.0f) { + for (int ix = 0; ix < numtxs; ix++) { tcs[ix].x = (float)ix / numTxsF; } } @@ -440,22 +344,12 @@ void ofGLProgrammableRenderer::draw(const ofPolyline & poly) const { } else { polylineMesh.disableTextures(); } - - polylineMesh.setMode( poly.isClosed() ? OF_PRIMITIVE_LINE_LOOP : OF_PRIMITIVE_LINE_STRIP ); -// draw(const ofMesh & vertexData, ofPolyRenderMode renderType, bool useColors, bool useTextures, bool useNormals) const; + polylineMesh.setMode(poly.isClosed() ? OF_PRIMITIVE_LINE_LOOP : OF_PRIMITIVE_LINE_STRIP); draw(polylineMesh, OF_MESH_FILL, false, false, false); - - -// meshVbo.setVertexData(&poly.getVertices()[0], poly.size(), GL_DYNAMIC_DRAW); -// meshVbo.draw(poly.isClosed() ? GL_LINE_LOOP : GL_LINE_STRIP, 0, poly.size()); -// meshPolylineVbo.setVertexData(&poly.getVertices()[0], poly.size(), GL_DYNAMIC_DRAW); -// meshPolylineVbo.draw(poly.isClosed() ? GL_LINE_LOOP : GL_LINE_STRIP, 0, poly.size()); - #endif - // use smoothness, if requested: - //if (bSmoothHinted) endSmoothing(); } + //---------------------------------------------------------- void ofGLProgrammableRenderer::draw(const ofPath & shape) const { ofFloatColor prevColor; @@ -555,7 +449,7 @@ void ofGLProgrammableRenderer::draw(const ofBaseVideoDraws & video, float x, flo //---------------------------------------------------------- void ofGLProgrammableRenderer::draw(const ofVbo & vbo, GLuint drawMode, int first, int total) const { - if (vbo.getUsingVerts()) { + if (vbo.getUsingVerts()) { vbo.bind(); const_cast(this)->setAttributes(vbo.getUsingVerts(), vbo.getUsingColors(), vbo.getUsingTexCoords(), vbo.getUsingNormals(), drawMode); glDrawArrays(drawMode, first, total); @@ -567,12 +461,17 @@ void ofGLProgrammableRenderer::draw(const ofVbo & vbo, GLuint drawMode, int firs void ofGLProgrammableRenderer::drawElements(const ofVbo & vbo, GLuint drawMode, int amt, int offsetelements) const { if (vbo.getUsingVerts()) { vbo.bind(); - const_cast(this)->setAttributes(vbo.getUsingVerts(), vbo.getUsingColors(), vbo.getUsingTexCoords(), vbo.getUsingNormals(), drawMode); -#ifdef TARGET_OPENGLES - glDrawElements(drawMode, amt, GL_UNSIGNED_SHORT, (void *)(sizeof(ofIndexType) * offsetelements)); -#else - glDrawElements(drawMode, amt, GL_UNSIGNED_INT, (void *)(sizeof(ofIndexType) * offsetelements)); -#endif + const_cast(this)->setAttributes( + vbo.getUsingVerts(), + vbo.getUsingColors(), + vbo.getUsingTexCoords(), + vbo.getUsingNormals(), drawMode); + + #if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + glDrawElements(drawMode, amt, GL_UNSIGNED_INT, (void *)(sizeof(ofIndexType) * offsetelements)); + #else + glDrawElements(drawMode, amt, GL_UNSIGNED_SHORT, (void *)(sizeof(ofIndexType) * offsetelements)); + #endif vbo.unbind(); } } @@ -582,12 +481,9 @@ void ofGLProgrammableRenderer::drawInstanced(const ofVbo & vbo, GLuint drawMode, if (vbo.getUsingVerts()) { vbo.bind(); const_cast(this)->setAttributes(vbo.getUsingVerts(), vbo.getUsingColors(), vbo.getUsingTexCoords(), vbo.getUsingNormals(), drawMode); -#ifdef TARGET_OPENGLES - // todo: activate instancing once OPENGL ES supports instancing, starting with version 3.0 - // unfortunately there is currently no easy way within oF to query the current OpenGL version. +#if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_1) && defined(TARGET_OPENGLES_3_1)) // https://www.khronos.org/opengles/sdk/docs/man3/xhtml/glDrawElementsInstanced.xml - ofLogWarning("ofVbo") << "drawInstanced(): hardware instancing is not supported on OpenGL ES < 3.0"; - // glDrawArraysInstanced(drawMode, first, total, primCount); + ofLogWarning("ofVbo") << "drawInstanced(): hardware instancing is not supported on OpenGL ES <= 3.1"; #else glDrawArraysInstanced(drawMode, first, total, primCount); #endif @@ -600,18 +496,11 @@ void ofGLProgrammableRenderer::drawElementsInstanced(const ofVbo & vbo, GLuint d if (vbo.getUsingVerts()) { vbo.bind(); const_cast(this)->setAttributes(vbo.getUsingVerts(), vbo.getUsingColors(), vbo.getUsingTexCoords(), vbo.getUsingNormals(), drawMode); -#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN) // TODO: Check against OPENGL_ES Version - // todo: activate instancing once OPENGL ES supports instancing, starting with version 3.0 - // unfortunately there is currently no easy way within oF to query the current OpenGL version. +#if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_1) && defined(TARGET_OPENGLES_3_1)) // https://www.khronos.org/opengles/sdk/docs/man3/xhtml/glDrawElementsInstanced.xml - ofLogWarning("ofVbo") << "drawElementsInstanced(): hardware instancing is not supported on OpenGL ES < 3.0"; - // glDrawElementsInstanced(drawMode, amt, GL_UNSIGNED_SHORT, nullptr, primCount); + ofLogWarning("ofVbo") << "drawElementsInstanced(): hardware instancing is not supported on OpenGL ES <= 3.1"; #else - #if defined(TARGET_OPENGLES) - glDrawElementsInstanced(drawMode, amt, GL_UNSIGNED_SHORT, nullptr, primCount); - #else glDrawElementsInstanced(drawMode, amt, GL_UNSIGNED_INT, nullptr, primCount); - #endif #endif vbo.unbind(); } @@ -799,7 +688,7 @@ void ofGLProgrammableRenderer::setCircleResolution(int res) { circlePolyline.arc(0, 0, 0, 1, 1, 0, 360, res); circleMesh.getVertices() = circlePolyline.getVertices(); path.setCircleResolution(res); - + // for the outline polyline, we need a closed loop // so we make another line that is closed, excluding the same start and end points circleOutlinePolyline.clear(); @@ -808,10 +697,10 @@ void ofGLProgrammableRenderer::setCircleResolution(int res) { circleOutlinePolyline.addVertex(glm::vec3(cosf(ta),sinf(ta), 0.0f)); } // circleOutlinePolyline.setClosed(true); - + circleOutlineMesh.getVertices() = circleOutlinePolyline.getVertices(); - - + + } currentStyle.circleResolution = res; } @@ -1111,14 +1000,12 @@ void ofGLProgrammableRenderer::setFillMode(ofFillFlag fill) { path.setFilled(true); path.setStrokeWidth(0); #ifndef TARGET_OPENGLES - // GLES does not support glPolygonMode glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif } else { path.setFilled(false); path.setStrokeWidth(currentStyle.lineWidth); #ifndef TARGET_OPENGLES - // GLES does not support glPolygonMode glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); #endif } @@ -1227,20 +1114,19 @@ void ofGLProgrammableRenderer::setBlendMode(ofBlendMode blendMode) { case OF_BLENDMODE_MAX: glEnable(GL_BLEND); -#ifdef TARGET_OPENGLES - ofLogWarning("ofGLProgrammableRenderer") << "OF_BLENDMODE_MAX not currently supported on OpenGL ES"; -#else +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) glBlendEquation(GL_MAX); +#else + ofLogWarning("ofGLProgrammableRenderer") << "OF_BLENDMODE_MAX not currently supported on OpenGL ES < 3.0"; #endif - break; case OF_BLENDMODE_MIN: glEnable(GL_BLEND); -#ifdef TARGET_OPENGLES - ofLogWarning("ofGLProgrammableRenderer") << "OF_BLENDMODE_MIN not currently supported on OpenGL ES"; -#else +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) glBlendEquation(GL_MIN); +#else + ofLogWarning("ofGLProgrammableRenderer") << "OF_BLENDMODE_MIN not currently supported on OpenGL ES < 3.0"; #endif break; @@ -1253,37 +1139,33 @@ void ofGLProgrammableRenderer::setBlendMode(ofBlendMode blendMode) { //---------------------------------------------------------- void ofGLProgrammableRenderer::enablePointSprites() { pointSpritesEnabled = true; -#ifdef TARGET_OPENGLES -#ifndef TARGET_PROGRAMMABLE_GL - glEnable(GL_POINT_SPRITE_OES); -#endif +#if !defined(TARGET_OPENGLES) + glEnable(GL_PROGRAM_POINT_SIZE); #else - glEnable(GL_PROGRAM_POINT_SIZE); + glEnable(GL_POINT_SPRITE_OES); #endif } //---------------------------------------------------------- void ofGLProgrammableRenderer::disablePointSprites() { -#ifdef TARGET_OPENGLES - #ifndef TARGET_PROGRAMMABLE_GL - glEnable(GL_POINT_SPRITE_OES); - #endif -#else + pointSpritesEnabled = false; +#if !defined(TARGET_OPENGLES) glDisable(GL_PROGRAM_POINT_SIZE); +#else + glDisable(GL_POINT_SPRITE_OES); #endif - pointSpritesEnabled = false; } //---------------------------------------------------------- void ofGLProgrammableRenderer::enableAntiAliasing() { -#if !defined(TARGET_PROGRAMMABLE_GL) || !defined(TARGET_OPENGLES) +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) glEnable(GL_MULTISAMPLE); #endif } //---------------------------------------------------------- void ofGLProgrammableRenderer::disableAntiAliasing() { -#if !defined(TARGET_PROGRAMMABLE_GL) || !defined(TARGET_OPENGLES) +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) glDisable(GL_MULTISAMPLE); #endif } @@ -1365,7 +1247,7 @@ void ofGLProgrammableRenderer::setStyle(const ofStyle & style) { //line width - finally! setLineWidth(style.lineWidth); - + setPointSize(style.pointSize); //ofSetDepthTest(style.depthTest); removed since it'll break old projects setting depth test through glEnable @@ -1410,14 +1292,14 @@ void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex texCoordsEnabled = tex; colorsEnabled = color; normalsEnabled = normals; - + // nh: we set a variable (mBRenderingLines) before calling set attributes() to disable // the setting of the draw mode. When rendering lines, the requested mode may be GL_LINES // but we use a shader with GL_TRIANGLES to create a mesh to render the lines of varying widths. if( !mBRenderingLines ) { mDrawMode = drawMode; } - + if( mDrawMode == GL_LINE_LOOP ) { // this uses the same line resources as GL_LINE_STRIP mDrawMode = GL_LINE_STRIP; @@ -1427,7 +1309,7 @@ void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex if( !areLinesShadersEnabled() ) { mDrawMode = GL_TRIANGLES; } - + // prevent a shader switch if we don't need it. if( mDrawMode != GL_TRIANGLES && mDrawMode != GL_POINTS && mDrawMode != GL_LINES && mDrawMode != GL_LINE_STRIP ) { mDrawMode = GL_TRIANGLES; @@ -1445,11 +1327,10 @@ void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex if (currentShader) currentShader->setUniform1f(USE_COLORS_UNIFORM, color); } - // if we switch the draw mode, lets set the textures + // if we switch the draw mode, lets set the textures if( prevDrawMode != mDrawMode ) { if (currentTextureTarget != OF_NO_TEXTURE && currentShader ) { // set all of the texture uniforms - // setUniformTexture(const string & name, int textureTarget, GLint textureID, int textureLocation) const { for (auto &texUniform : mUniformsTex ) { currentShader->setUniformTexture(texUniform.uniformName, texUniform.texData, texUniform.textureLocation); } @@ -1458,7 +1339,6 @@ void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex auto &texUniform = mUniformsTex[0]; #if !defined(TARGET_OPENGLES) if (currentTextureTarget == GL_TEXTURE_RECTANGLE_ARB) { - // set the size of the texture, since gl_PointCoord is normalized currentShader->setUniform2f("src_tex_unit0_dims", texUniform.texData.width, texUniform.texData.height); } #endif @@ -1468,7 +1348,7 @@ void ofGLProgrammableRenderer::setAttributes(bool vertices, bool color, bool tex } } } - + if (!usingCustomShader && currentShader && !uniqueShader && !currentMaterial) { if (mDrawMode == GL_POINTS && pointSpritesEnabled) { currentShader->setUniform1f("pointSize", currentStyle.pointSize ); @@ -1641,7 +1521,7 @@ void ofGLProgrammableRenderer::bind(const ofFbo & fbo) { glBindFramebuffer(GL_FRAMEBUFFER, currentFramebufferId); } -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) //---------------------------------------------------------- void ofGLProgrammableRenderer::bindForBlitting(const ofFbo & fboSrc, ofFbo & fboDst, int attachmentPoint) { if (currentFramebufferId == fboSrc.getId()) { @@ -1649,17 +1529,18 @@ void ofGLProgrammableRenderer::bindForBlitting(const ofFbo & fboSrc, ofFbo & fbo << "Most probably you forgot to end() the current framebuffer before calling getTexture()."; return; } - // this method could just as well have been placed in ofBaseGLRenderer - // and shared over both programmable and fixed function renderer. - // I'm keeping it here, so that if we want to do more fancyful - // named framebuffers with GL 4.5+, we can have - // different implementations. + framebufferIdStack.push_back(currentFramebufferId); currentFramebufferId = fboSrc.getId(); + glBindFramebuffer(GL_READ_FRAMEBUFFER, currentFramebufferId); - glReadBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboDst.getIdDrawBuffer()); + +#ifndef TARGET_OPENGLES + // glReadBuffer / glDrawBuffer are desktop-only (deprecated on iOS GLES) + glReadBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint); glDrawBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint); +#endif } #endif @@ -1767,12 +1648,15 @@ void ofGLProgrammableRenderer::bind(const ofTexture & texture, int location) { pushMatrix(); glm::mat4 m = glm::mat4(1.0); -#ifndef TARGET_OPENGLES - if (texture.texData.textureTarget == GL_TEXTURE_RECTANGLE_ARB) +#if !defined(TARGET_OPENGLES) + if (texture.texData.textureTarget == GL_TEXTURE_RECTANGLE_ARB) { m = glm::scale(m, glm::vec3(texture.texData.width, texture.texData.height, 1.0f)); + } else #endif + { m = glm::scale(m, glm::vec3(texture.texData.width / texture.texData.tex_w, texture.texData.height / texture.texData.tex_h, 1.0f)); + } loadMatrix(m); matrixMode(OF_MATRIX_MODELVIEW); @@ -1855,97 +1739,86 @@ void ofGLProgrammableRenderer::setDefaultUniforms() { //---------------------------------------------------------- void ofGLProgrammableRenderer::beginDefaultShader() { if (usingCustomShader && !currentMaterial && !currentShadow) return; - if (currentShadow && bCustomShadowShader) return; - - const ofShader * nextShader = nullptr; - - bool bUseTexture = texCoordsEnabled; - if( mDrawMode == GL_POINTS ){ - // if we are drawing points, we don't need tex coords and would like to use the texture - if (currentTextureTarget != OF_NO_TEXTURE ) { - bUseTexture = true; - } - } - - if (!uniqueShader || currentMaterial || currentShadow) - { - if (currentShadow) { - if (currentMaterial && currentMaterial->hasDepthShader()) { - nextShader = ¤tMaterial->getShadowDepthShader(*currentShadow, *this); - } else { - nextShader = ¤tShadow->getDepthShader(*this); - } - } else if (currentMaterial) { - nextShader = ¤tMaterial->getShader(currentTextureTarget, colorsEnabled, *this); - } else if (bitmapStringEnabled) { - nextShader = &bitmapStringShader; - - } else if (colorsEnabled && bUseTexture) { - auto &shaderCollection = getShaderCollectionForMode(mDrawMode); - - switch (currentTextureTarget) - { -#ifndef TARGET_OPENGLES - case GL_TEXTURE_RECTANGLE_ARB: - nextShader = &shaderCollection->texRectColor; - // nextShader = &defaultTexRectColor; - break; -#endif - case GL_TEXTURE_2D: - nextShader = &shaderCollection->tex2DColor; - // nextShader = &defaultTex2DColor; - break; - case OF_NO_TEXTURE: - nextShader = &shaderCollection->noTexColor; - // nextShader = &defaultNoTexColor; - break; -#ifdef TARGET_ANDROID - case GL_TEXTURE_EXTERNAL_OES: - nextShader = &defaultOESTexColor; - break; -#endif - } - } else if (colorsEnabled) { - nextShader = &getShaderCollectionForMode(mDrawMode)->noTexColor; - // nextShader = &defaultNoTexColor; - } else if (bUseTexture) { - auto &shaderCollection = getShaderCollectionForMode(mDrawMode); - switch (currentTextureTarget) { -#ifndef TARGET_OPENGLES - case GL_TEXTURE_RECTANGLE_ARB: - nextShader = &shaderCollection->texRectNoColor; - // nextShader = &defaultTexRectNoColor; - break; -#endif - case GL_TEXTURE_2D: - nextShader = &shaderCollection->tex2DNoColor; - // nextShader = &defaultTex2DNoColor; - break; - case OF_NO_TEXTURE: - nextShader = &shaderCollection->noTexNoColor; - // nextShader = &defaultNoTexNoColor; - break; -#ifdef TARGET_ANDROID - case GL_TEXTURE_EXTERNAL_OES: - nextShader = &defaultOESTexNoColor; - break; -#endif - } - } else { - nextShader = &getShaderCollectionForMode(mDrawMode)->noTexNoColor; - // nextShader = &defaultNoTexNoColor; - } - } else { - nextShader = &defaultUniqueShader; - } - - if (nextShader) { - if (!currentShader || *currentShader != *nextShader) { - settingDefaultShader = true; - bind(*nextShader); - settingDefaultShader = false; - } - } + if (currentShadow && bCustomShadowShader) return; + + const ofShader * nextShader = nullptr; + + bool bUseTexture = texCoordsEnabled; + if (mDrawMode == GL_POINTS) { + // if we are drawing points, we don't need tex coords and would like to use the texture + if (currentTextureTarget != OF_NO_TEXTURE) { + bUseTexture = true; + } + } + + if (!uniqueShader || currentMaterial || currentShadow) { + if (currentShadow) { + if (currentMaterial && currentMaterial->hasDepthShader()) { + nextShader = ¤tMaterial->getShadowDepthShader(*currentShadow, *this); + } else { + nextShader = ¤tShadow->getDepthShader(*this); + } + } else if (currentMaterial) { + nextShader = ¤tMaterial->getShader(currentTextureTarget, colorsEnabled, *this); + } else if (bitmapStringEnabled) { + nextShader = &bitmapStringShader; + } else if (colorsEnabled && bUseTexture) { + auto &shaderCollection = getShaderCollectionForMode(mDrawMode); + + switch (currentTextureTarget) { + #ifndef TARGET_OPENGLES + case GL_TEXTURE_RECTANGLE_ARB: + nextShader = &shaderCollection->texRectColor; + break; + #endif + case GL_TEXTURE_2D: + nextShader = &shaderCollection->tex2DColor; + break; + case OF_NO_TEXTURE: + nextShader = &shaderCollection->noTexColor; + break; + #ifdef TARGET_ANDROID + case GL_TEXTURE_EXTERNAL_OES: + nextShader = &defaultOESTexColor; + break; + #endif + } + } else if (colorsEnabled) { + nextShader = &getShaderCollectionForMode(mDrawMode)->noTexColor; + } else if (bUseTexture) { + auto &shaderCollection = getShaderCollectionForMode(mDrawMode); + switch (currentTextureTarget) { + #ifndef TARGET_OPENGLES + case GL_TEXTURE_RECTANGLE_ARB: + nextShader = &shaderCollection->texRectNoColor; + break; + #endif + case GL_TEXTURE_2D: + nextShader = &shaderCollection->tex2DNoColor; + break; + case OF_NO_TEXTURE: + nextShader = &shaderCollection->noTexNoColor; + break; + #ifdef TARGET_ANDROID + case GL_TEXTURE_EXTERNAL_OES: + nextShader = &defaultOESTexNoColor; + break; + #endif + } + } else { + nextShader = &getShaderCollectionForMode(mDrawMode)->noTexNoColor; + } + } else { + nextShader = &defaultUniqueShader; + } + + if (nextShader) { + if (!currentShader || *currentShader != *nextShader) { + settingDefaultShader = true; + bind(*nextShader); + settingDefaultShader = false; + } + } } //---------------------------------------------------------- @@ -2022,7 +1895,7 @@ void ofGLProgrammableRenderer::drawCircle(float x, float y, float z, float radiu ofGLProgrammableRenderer * mutThis = const_cast(this); // use smoothness, if requested: if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing(); - + if( !currentStyle.bFill ) { // nh: We use the circleOutlineMesh to render a closed polyline // since the lines mesh creation and shader depends on it. @@ -2060,7 +1933,7 @@ void ofGLProgrammableRenderer::drawEllipse(float x, float y, float z, float widt // use smoothness, if requested: if (currentStyle.smoothing && !currentStyle.bFill) mutThis->startSmoothing(); - + if( !currentStyle.bFill ) { // nh: We use the circleOutlineMesh to render a closed polyline // since the lines mesh creation and shader depends on it. @@ -2255,6 +2128,7 @@ void ofGLProgrammableRenderer::drawString(const ofTrueTypeFont & font, string te // tig: GLSL #150 shaders written against spec: // http://www.opengl.org/registry/doc/GLSLangSpec.1.50.09.pdf + #ifdef TARGET_OPENGLES static const string vertex_shader_header = "%extensions%\n" @@ -2288,6 +2162,8 @@ static const string fragment_shader_header = "out vec4 fragColor;\n"; #endif + + static const string defaultVertexShader = vertex_shader_header + STRINGIFY( uniform mat4 projectionMatrix; uniform mat4 modelViewMatrix; @@ -2319,16 +2195,16 @@ STRINGIFY( uniform mat4 modelViewMatrix; uniform mat4 textureMatrix; uniform mat4 modelViewProjectionMatrix; - + uniform float pointSize; - + IN vec4 position; IN vec2 texcoord; IN vec4 color; IN vec3 normal; - + OUT vec4 colorVarying; - + void main() { gl_PointSize = pointSize; @@ -2344,29 +2220,29 @@ STRINGIFY( uniform mat4 modelViewMatrix;\n uniform mat4 textureMatrix;\n uniform mat4 modelViewProjectionMatrix;\n - + uniform vec4 viewRect;\n uniform float uLineWidth;\n uniform float uUsePerspective;\n - + IN vec4 position; IN vec2 texcoord; IN vec4 color; IN vec3 normal; IN vec4 nextVertex; - + OUT vec4 colorVarying; OUT vec2 texCoordVarying; - + void main() { colorVarying = color; float pushDir = nextVertex.w; texCoordVarying = (textureMatrix*vec4(texcoord.x,texcoord.y, 0.0,1.0)).xy; - + // clip space vec4 cClipPos = modelViewProjectionMatrix * vec4(position.xyz, 1.0); vec4 nClipPos = modelViewProjectionMatrix * vec4(nextVertex.xyz, 1.0); - + vec2 cNdcPos = (cClipPos.xy / cClipPos.w); vec2 nNdcPos = (nClipPos.xy / nClipPos.w); /* @@ -2375,26 +2251,26 @@ STRINGIFY( */ cNdcPos = (cNdcPos + 1.0) * (0.5 * viewRect.zw); nNdcPos = (nNdcPos + 1.0) * (0.5 * viewRect.zw); - + float thickness = uLineWidth * 0.5; - - + + vec2 dir = normalize(cNdcPos - nNdcPos); dir = vec2(-dir.y, dir.x); dir = dir * thickness * pushDir; - + vec4 posScreen = cClipPos; posScreen.xy = cNdcPos; posScreen.xy += dir; posScreen.xy = posScreen.xy / viewRect.zw * 2.0 - 1.0; posScreen.xy *= posScreen.w; - + // perspective float vaspect = viewRect.w / viewRect.z; dir.x *= vaspect; vec4 posPersp = cClipPos; posPersp.xy += dir; - + gl_Position = mix( posScreen, posPersp, uUsePerspective ); } ); @@ -2406,21 +2282,21 @@ STRINGIFY( uniform mat4 modelViewMatrix;\n uniform mat4 textureMatrix; uniform mat4 modelViewProjectionMatrix; - + uniform vec4 viewRect; uniform float uLineWidth; uniform float uUsePerspective; - + IN vec4 position; IN vec2 texcoord; IN vec4 color; IN vec3 normal; IN vec4 prevVertex; IN vec4 nextVertex; - + OUT vec4 colorVarying; OUT vec2 texCoordVarying; - + float mapClamp( float value, float inMin, float inMax, float outMin, float outMax ) { float outVal = ( (value - inMin ) / ( inMax - inMin ) * ( outMax - outMin ) ) + outMin; if(outMax < outMin){ @@ -2432,29 +2308,29 @@ STRINGIFY( } return outVal; } - + void main() { colorVarying = color; texCoordVarying = (textureMatrix*vec4(texcoord.x, texcoord.y, 0.0,1.0)).xy; - + float thickness = uLineWidth;// * 0.5; float pushDir = nextVertex.w; float pushDirY = -prevVertex.w; - + // // clip space vec4 pClipPos = modelViewProjectionMatrix * vec4(prevVertex.xyz, 1.0); vec4 cClipPos = modelViewProjectionMatrix * vec4(position.xyz, 1.0); vec4 nClipPos = modelViewProjectionMatrix * vec4(nextVertex.xyz, 1.0); - + vec2 pNdcPos = (pClipPos.xy / pClipPos.w); vec2 cNdcPos = (cClipPos.xy / cClipPos.w); vec2 nNdcPos = (nClipPos.xy / nClipPos.w); - + // // convert to screen space pNdcPos = (pNdcPos + 1.0) * (0.5 * viewRect.zw); cNdcPos = (cNdcPos + 1.0) * (0.5 * viewRect.zw); nNdcPos = (nNdcPos + 1.0) * (0.5 * viewRect.zw); - + vec2 dir = vec2(1.0, 0.0); if( position.xyz == nextVertex.xyz ) { // this is the last point ( on a non-closed line ) @@ -2470,44 +2346,44 @@ STRINGIFY( vec2 pdir = normalize( cNdcPos-pNdcPos ); vec2 ndir = normalize( nNdcPos-cNdcPos ); vec2 tangent = normalize(pdir+ndir); - + // Miter code based on // https://blog.scottlogic.com/2019/11/18/drawing-lines-with-webgl.html // by Matt Stobbs - + vec2 miter = vec2(-tangent.y, tangent.x); vec2 normalA = vec2(-pdir.y, pdir.x); dir = miter; float miterLength = 1.0 / clamp(abs(dot(miter, normalA)), 0.01, 2.0); thickness = miterLength * thickness; - + vec2 point = normalize(pdir-ndir); float dmp = dot(miter, point); - + // float miterTooLongMix = clamp(step( 2.0, miterLength) * sign(pushDir * dmp), 0.0, 1.0); float miterTooLongMix = clamp(step( 2.0, miterLength), 0.0, 1.0); float pstr = mapClamp( miterLength, 2.0, 3.0, 0.0, 1.0 ); float thicknessL = mix( miterLength * uLineWidth, uLineWidth, pstr ); - + dir = mix( dir * pushDir, (pushDir * pushDirY) * normalA, pstr * miterTooLongMix ); thickness = mix( clamp(miterLength, 0.0, 3.0) * uLineWidth, thicknessL, miterTooLongMix ); } - + dir = dir * (thickness * 0.5 ); - + // we calculate both the screen pos and perspective to avoid an if statement vec4 posScreen = cClipPos; posScreen.xy = cNdcPos; posScreen.xy += dir;// * 0.5; posScreen.xy = posScreen.xy / viewRect.zw * 2.0 - 1.0; posScreen.xy *= posScreen.w; - + // perspective vec4 posPersp = cClipPos; float vaspect = viewRect.w / viewRect.z; dir.x *= vaspect; posPersp.xy += (dir); - + gl_Position = mix( posScreen, posPersp, uUsePerspective ); } ); @@ -2534,7 +2410,7 @@ R"( uniform vec4 globalColor; uniform float usingTexture; uniform float usingColors; - + IN vec4 colorVarying; void main(){ @@ -2542,7 +2418,7 @@ R"( float dist_sq = dot( centerPt, centerPt ); vec2 st = gl_PointCoord; - + #if defined(OF_USING_TEXTURE_RECT) st.x = gl_PointCoord.x * src_tex_unit0_dims.x; st.y = gl_PointCoord.y * src_tex_unit0_dims.y; @@ -2721,7 +2597,7 @@ static const string defaultFragmentShaderTex2DNoColor = fragment_shader_header + // ---------------------------------------------------------------------- static const string defaultFragmentShaderOESTexNoColor = fragment_shader_header + STRINGIFY( - + uniform samplerExternalOES src_tex_unit0; uniform float usingTexture; uniform float usingColors; @@ -2739,16 +2615,16 @@ static const string defaultFragmentShaderOESTexNoColor = fragment_shader_header // ---------------------------------------------------------------------- static const string defaultFragmentShaderOESTexColor = fragment_shader_header + STRINGIFY( - + uniform samplerExternalOES src_tex_unit0; uniform float usingTexture; uniform float usingColors; uniform vec4 globalColor; - + IN float depth; IN vec4 colorVarying; IN vec2 texCoordVarying; - + void main(){ FRAG_COLOR = TEXTURE(src_tex_unit0, texCoordVarying) * colorVarying; } @@ -2835,7 +2711,7 @@ static const string bitmapStringFragmentShader = fragment_shader_header + STRING // in desktop openGL these are not used but we declare it to avoid more ifdefs static const string uniqueVertexShader = vertex_shader_header + STRINGIFY( - + uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; uniform mat4 textureMatrix; @@ -2862,7 +2738,7 @@ static const string uniqueVertexShader = vertex_shader_header + STRINGIFY( // ---------------------------------------------------------------------- static const string uniqueFragmentShader = fragment_shader_header + STRINGIFY( - + uniform sampler2D src_tex_unit0; uniform float usingTexture; uniform float bitmapText; @@ -2985,15 +2861,22 @@ static const string FRAGMENT_SHADER_PLANAR_YUV = STRINGIFY( static string defaultShaderHeader(string header, GLenum textureTarget, int major, int minor) { ofStringReplace(header, "%glsl_version%", ofGLSLVersionFromGL(major, minor)); -#ifndef TARGET_OPENGLES + +#if !defined(TARGET_OPENGLES) + // Desktop only: rectangle texture extension (needed for older GL < 4.2) if (major < 4 && minor < 2) { ofStringReplace(header, "%extensions%", "#extension GL_ARB_texture_rectangle : enable"); } else { ofStringReplace(header, "%extensions%", ""); } #else + #if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) ofStringReplace(header, "%extensions%", "#extension GL_OES_standard_derivatives : enable"); + #else + ofStringReplace(header, "%extensions%", ""); + #endif #endif + if (textureTarget == GL_TEXTURE_2D) { header += "#define SAMPLER sampler2D\n"; } else { @@ -3005,15 +2888,21 @@ static string defaultShaderHeader(string header, GLenum textureTarget, int major static string shaderSource(const string & src, int major, int minor) { string shaderSrc = src; ofStringReplace(shaderSrc, "%glsl_version%", ofGLSLVersionFromGL(major, minor)); -#ifndef TARGET_OPENGLES + +#if !defined(TARGET_OPENGLES) if (major < 4 && minor < 2) { ofStringReplace(shaderSrc, "%extensions%", "#extension GL_ARB_texture_rectangle : enable"); } else { ofStringReplace(shaderSrc, "%extensions%", ""); } #else + #if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + ofStringReplace(shaderSrc, "%extensions%", "#extension GL_OES_standard_derivatives : enable"); + #else ofStringReplace(shaderSrc, "%extensions%", ""); + #endif #endif + return shaderSrc; } @@ -3141,7 +3030,7 @@ void ofGLProgrammableRenderer::LinesBundle::setMeshDataToVbo() { if( mesh.getNumVertices() > 0 ) { // void setMesh(const ofMesh & mesh, int usage, bool useColors, bool useTextures, bool useNormals); vbo.setMesh( mesh, GL_DYNAMIC_DRAW, mesh.hasColors() && mesh.usingColors(), mesh.hasTexCoords() && mesh.usingTextures(), mesh.hasNormals() && mesh.usingNormals() ); - + if( lineMeshPrevVerts.size() > 0 ) { vbo.setAttributeData(vertAttribPrev, &lineMeshPrevVerts[0].x, 4, mesh.getNumVertices(), GL_DYNAMIC_DRAW); } @@ -3174,7 +3063,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { uniqueShader = false; #endif mDefaultShadersMap.clear(); - + mLinesBundleMap.clear(); if( mLinesBundleMap.count(GL_LINES) < 1 ) { mLinesBundleMap[GL_LINES] = LinesBundle(); @@ -3196,15 +3085,15 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { defaultUniqueShader.linkProgram(); beginDefaultShader(); } else { - + mDefaultShadersMap[GL_TRIANGLES] = std::make_shared(); mDefaultShadersMap[GL_POINTS] = std::make_shared(); mDefaultShadersMap[GL_LINES] = std::make_shared(); mDefaultShadersMap[GL_LINE_STRIP] = std::make_shared(); - - + + mDefaultShadersMap[GL_TRIANGLES]->setupAllVertexShaders(shaderSource(defaultVertexShader, major, minor)); - + #ifndef TARGET_OPENGLES // defaultTexRectColor.setupShaderFromSource(GL_VERTEX_SHADER, shaderSource(defaultVertexShader, major, minor)); // defaultTexRectNoColor.setupShaderFromSource(GL_VERTEX_SHADER, shaderSource(defaultVertexShader, major, minor)); @@ -3246,7 +3135,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { // defaultTex2DNoColor.bindDefaults(); // defaultNoTexNoColor.bindDefaults(); alphaMask2DShader.bindDefaults(); - + mDefaultShadersMap[GL_TRIANGLES]->bindDefaults(); mDefaultShadersMap[GL_TRIANGLES]->linkPrograms(); @@ -3276,19 +3165,19 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { defaultOESTexColor.linkProgram(); defaultOESTexNoColor.linkProgram(); #endif - - + + // now lets start setting up the points shaders mDefaultShadersMap[GL_POINTS]->setupAllVertexShaders(shaderSource(defaultPointsVertexShader, major, minor)); - + // ok, now lets setup the lines shaders // mDefaultShadersMap[GL_LINES]->setupAllVertexShaders(shaderSource(defaultLinesVertexShader, major, minor)); - + // ok, now lets setup the line strip shaders // mDefaultShadersMap[GL_LINE_STRIP]->setupAllVertexShaders(shaderSource(defaultLineStripVertexShader, major, minor)); - + // defaultFragmentShaderLines - + string alt_frag_header = fragment_shader_header; string defines = "#define OF_USING_TEXTURE_RECT 1\n#define OF_USING_VERTEX_COLORS 1\n"; std::string header_w_defines = alt_frag_header + defines; @@ -3299,7 +3188,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); mDefaultShadersMap[GL_LINE_STRIP]->texRectColor.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); - + defines = "#define OF_USING_TEXTURE_RECT 1\n"; header_w_defines = alt_frag_header + defines; mDefaultShadersMap[GL_POINTS]->texRectNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER, @@ -3309,7 +3198,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { mDefaultShadersMap[GL_LINE_STRIP]->texRectNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); #endif - + defines = "#define OF_USING_TEXTURE_2D 1\n#define OF_USING_VERTEX_COLORS 1\n"; header_w_defines = alt_frag_header + defines; mDefaultShadersMap[GL_POINTS]->tex2DColor.setupShaderFromSource(GL_FRAGMENT_SHADER, @@ -3318,7 +3207,7 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); mDefaultShadersMap[GL_LINE_STRIP]->tex2DColor.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); - + defines = "#define OF_USING_TEXTURE_2D 1\n"; header_w_defines = alt_frag_header + defines; mDefaultShadersMap[GL_POINTS]->tex2DNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER, @@ -3345,28 +3234,28 @@ void ofGLProgrammableRenderer::setup(int _major, int _minor) { shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); mDefaultShadersMap[GL_LINE_STRIP]->noTexNoColor.setupShaderFromSource(GL_FRAGMENT_SHADER, shaderSource(header_w_defines + defaultFragmentShaderLines, major, minor)); - + mDefaultShadersMap[GL_POINTS]->bindDefaults(); mDefaultShadersMap[GL_POINTS]->linkPrograms(); - - + + mDefaultShadersMap[GL_LINES]->bindDefaults(); // now lets bind the vertex attribute for the next vertex mDefaultShadersMap[GL_LINES]->bindAttribute( mLinesBundleMap[GL_LINES].vertAttribNext, "nextVertex" ); mDefaultShadersMap[GL_LINES]->linkPrograms(); - - + + mDefaultShadersMap[GL_LINE_STRIP]->bindDefaults(); // now lets bind the vertex attribute for the previous and next vertex mDefaultShadersMap[GL_LINE_STRIP]->bindAttribute( mLinesBundleMap[GL_LINE_STRIP].vertAttribPrev, "prevVertex" ); mDefaultShadersMap[GL_LINE_STRIP]->bindAttribute( mLinesBundleMap[GL_LINE_STRIP].vertAttribNext, "nextVertex" ); mDefaultShadersMap[GL_LINE_STRIP]->linkPrograms(); - + // defaultPointsTex2DColor.bindDefaults(); // defaultPointsTex2DNoColor.bindDefaults(); // defaultPointsNoTexColor.bindDefaults(); // defaultPointsNoTexNoColor.bindDefaults(); -// +// // defaultPointsTex2DColor.linkProgram(); // defaultPointsTex2DNoColor.linkProgram(); // defaultPointsNoTexColor.linkProgram(); @@ -3644,16 +3533,16 @@ void ofGLProgrammableRenderer::configureMeshToMatchWithNewVertsAndIndices(const bool bUseColors = aSrcMesh.hasColors() && aSrcMesh.usingColors() && (aSrcMesh.getNumColors() == aSrcMesh.getNumVertices()); bool bUseNormals = aSrcMesh.hasNormals() && aSrcMesh.usingNormals() && (aSrcMesh.getNumNormals() == aSrcMesh.getNumVertices()); bool bUseTexCoords = aSrcMesh.hasTexCoords() && aSrcMesh.usingTextures() && (aSrcMesh.getNumTexCoords() == aSrcMesh.getNumVertices()); - + if (aDstMesh.getNumVertices() != aTargetNumVertices) { aDstMesh.getVertices().assign(aTargetNumVertices, glm::vec3(0.f, 0.f, 0.f)); } - + if( aDstMesh.getNumIndices() != aTargetNumIndices ) { aDstMesh.getIndices().assign(aTargetNumIndices, 0); } aDstMesh.enableIndices(); - + if (bUseColors) { if (aDstMesh.getNumColors() != aTargetNumVertices) { aDstMesh.getColors().assign(aTargetNumVertices, ofFloatColor(1.f)); @@ -3685,26 +3574,26 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB auto& polyMesh = aLinesBundle.mesh; auto& nextVerts = aLinesBundle.lineMeshNextVerts; auto& prevVerts = aLinesBundle.lineMeshPrevVerts; - + bool bClosed = (drawMode == GL_LINE_LOOP) && amesh.getNumVertices() > 2; bool srcHasIndices = amesh.getNumIndices() > 0 && amesh.usingIndices(); std::size_t srcNumVs = srcHasIndices ? amesh.getNumIndices() : amesh.getNumVertices(); - + std::size_t targetNumPs = (bClosed ? srcNumVs + 1 : srcNumVs); std::size_t numIndicesA = (targetNumPs - 1) * 6 + (targetNumPs) * 6; - + std::size_t numVertsPer = 4; - + if( drawMode == GL_LINES ) { numVertsPer = 2; std::size_t targetNumLines = srcNumVs / 2; numIndicesA = targetNumLines * 6; } std::size_t targetNumVs = targetNumPs * numVertsPer; - - + + configureMeshToMatchWithNewVertsAndIndices(amesh, polyMesh, targetNumVs, numIndicesA ); - + if( drawMode != GL_LINES ) { if( prevVerts.size() != targetNumVs ) { prevVerts.assign(targetNumVs, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); @@ -3713,61 +3602,61 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB if (nextVerts.size() != targetNumVs ) { nextVerts.assign(targetNumVs, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); } - + bool bUseColors = amesh.hasColors() && amesh.usingColors() && (amesh.getNumColors() == amesh.getNumVertices()); bool bUseNormals = amesh.hasNormals() && amesh.usingNormals() && (amesh.getNumNormals() == amesh.getNumVertices()); bool bUseTexCoords = amesh.hasTexCoords() && amesh.usingTextures() && (amesh.getNumTexCoords() == amesh.getNumVertices()); - - + + const auto *srcVerts = amesh.getVerticesPointer(); const auto *srcIndices = amesh.getIndexPointer(); const auto *srcColors = amesh.getColorsPointer(); const auto *srcNormals = amesh.getNormalsPointer(); const auto *srcTexCoords = amesh.getTexCoordsPointer(); std::size_t numPs = srcHasIndices ? amesh.getNumIndices() : amesh.getNumVertices(); - + auto &pmVerts = polyMesh.getVertices(); auto &pmIndices = polyMesh.getIndices(); auto *pmColors = polyMesh.getColorsPointer(); auto *pmNormals = polyMesh.getNormalsPointer(); auto *pmTexCoords = polyMesh.getTexCoordsPointer(); - + float texU = 1.0; if( currentTextureTarget != OF_NO_TEXTURE ) { if( mUniformsTex.size() > 0 ) { texU = mUniformsTex[0].texData.tex_u; } } - - + + glm::vec3 EPSILON_VEC3 = glm::vec3(0.00005f); - - + + if( drawMode == GL_LINES ) { std::size_t cindex1 = 0; std::size_t cindex2 = 0; std::size_t lineIndex = 0; - + std::size_t pmIndex = 0; std::size_t kindex = 0; std::size_t newIndex = 0; - + std::size_t k = 0; - + for (size_t i = 0; i < targetNumPs; i += 2) { cindex1 = (i % numPs); cindex2 = (i + 1) % numPs; - + lineIndex = i / 2; - + if (srcHasIndices) { // get the verts from the indices cindex1 = srcIndices[cindex1]; cindex2 = srcIndices[cindex2]; } - + pmIndex = i * 2; - + // duplicate the vertices // for(k = 0; k < 4; k++ ) { kindex = cindex2; @@ -3775,7 +3664,7 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB kindex = cindex1; } pmVerts[pmIndex + k] = srcVerts[kindex]; - + if (bUseColors) { pmColors[pmIndex + k] = srcColors[kindex]; } @@ -3792,23 +3681,23 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB } } } - + nextVerts[pmIndex + 0] = glm::vec4(srcVerts[cindex2], -1.0f); nextVerts[pmIndex + 1] = glm::vec4(srcVerts[cindex2], 1.0f); - + nextVerts[pmIndex + 2] = glm::vec4(srcVerts[cindex1], 1.0f); nextVerts[pmIndex + 3] = glm::vec4(srcVerts[cindex1], -1.0f); - + newIndex = lineIndex * 6; pmIndices[newIndex + 0] = pmIndex + 0; pmIndices[newIndex + 1] = pmIndex + 2; pmIndices[newIndex + 2] = pmIndex + 1; - + pmIndices[newIndex + 3] = pmIndex + 1; pmIndices[newIndex + 4] = pmIndex + 2; pmIndices[newIndex + 5] = pmIndex + 3; } - + aLinesBundle.setMeshDataToVbo(); } else { std::size_t nindex, pindex, cindex; @@ -3819,18 +3708,18 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB std::size_t k = 0; std::size_t newIndex = 0; std::size_t nextIndex = 0; - + // if we have vertices lying on top of each other, // lets create some way to store valid ones // might not be the best approach, but easier / faster than removing the vertices from the src mesh glm::vec3 cachedPrevVert = {0.f, 0.f, 0.f}; glm::vec3 cachedNextVert = {0.f, 0.f, 0.f}; - + for (size_t i = 0; i < targetNumPs; i++) { cindex = (i % numPs); nindex = (i + 1) % numPs; pindex = (i - 1) % numPs; - + if (i == 0) { if (bClosed) { cindex = 0; @@ -3844,26 +3733,26 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB nindex = numPs - 1; } } - + if (srcHasIndices) { // get the verts from the indices cindex = srcIndices[cindex]; nindex = srcIndices[nindex]; pindex = srcIndices[pindex]; } - + if( i == 0 ) { // just in case, lets init the cached verts to use cachedPrevVert = srcVerts[cindex]; cachedNextVert = srcVerts[cindex]; } - + // duplicate the vertices // pmIndex = i * numVertsPer; - + pvert = glm::vec4(srcVerts[pindex], 1.0f); nvert = glm::vec4(srcVerts[nindex], 1.0f); - + if( glm::all(glm::lessThan(glm::abs(srcVerts[cindex]-srcVerts[pindex]), EPSILON_VEC3 ))) { if( i != 0 || (i == 0 && bClosed )) { // loop through and find a good next vert // @@ -3883,9 +3772,9 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB } else { cachedPrevVert = srcVerts[pindex]; } - - - + + + if(glm::all(glm::lessThan(glm::abs(srcVerts[cindex]-srcVerts[nindex]), EPSILON_VEC3 )) ) { // nvert = glm::vec4(cachedNextVert, 1.f); if( i != targetNumPs - 1 || (i == targetNumPs - 1 && bClosed) ) { @@ -3906,7 +3795,7 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB } else { cachedNextVert = srcVerts[nindex]; } - + for(k = 0; k < numVertsPer; k++) { pmVerts[pmIndex + k] = srcVerts[cindex]; nextVerts[pmIndex + k] = nvert; @@ -3921,7 +3810,7 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB if (k < 2) { prevVerts[pmIndex + k].w = -1.0; } - + if (bUseColors) { pmColors[pmIndex + k] = srcColors[kindex]; } @@ -3933,39 +3822,39 @@ void ofGLProgrammableRenderer::configureLinesBundleFromMesh(LinesBundle& aLinesB // should be in relation to the top of the image pmTexCoords[pmIndex + k] = srcTexCoords[kindex]; } else { - // lets go down to the bottom of the texture + // lets go down to the bottom of the texture pmTexCoords[pmIndex + k] = glm::vec2(srcTexCoords[kindex].x, texU); } // pmTexCoords[pmIndex + k] = srcTexCoords[kindex]; } } - + newIndex = i * 2 * 6; pmIndices[newIndex + 0] = pmIndex + 0; pmIndices[newIndex + 1] = pmIndex + 2; pmIndices[newIndex + 2] = pmIndex + 1; - + pmIndices[newIndex + 3] = pmIndex + 1; pmIndices[newIndex + 4] = pmIndex + 2; pmIndices[newIndex + 5] = pmIndex + 3; - + nextIndex = (i+1); if( bClosed && i > targetNumPs -1 ) { nextIndex = 0; } - + if( nextIndex < targetNumPs) { std::size_t nextPmIndex = (nextIndex) * numVertsPer; pmIndices[newIndex + 6] = pmIndex + 2; pmIndices[newIndex + 7] = nextPmIndex + 0; pmIndices[newIndex + 8] = pmIndex + 3; - + pmIndices[newIndex + 9] = pmIndex + 3; pmIndices[newIndex + 10] = nextPmIndex + 0; pmIndices[newIndex + 11] = nextPmIndex + 1; } } - + aLinesBundle.setMeshDataToVbo(); } } diff --git a/libs/openFrameworks/gl/ofGLProgrammableRenderer.h b/libs/openFrameworks/gl/ofGLProgrammableRenderer.h index 4adac96f4ba..22f00e1e775 100644 --- a/libs/openFrameworks/gl/ofGLProgrammableRenderer.h +++ b/libs/openFrameworks/gl/ofGLProgrammableRenderer.h @@ -204,7 +204,7 @@ class ofGLProgrammableRenderer: public ofBaseGLRenderer{ void unbind(const ofCamera & camera); void bind(const ofFbo & fbo); -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) void bindForBlitting(const ofFbo & fboSrc, ofFbo & fboDst, int attachmentPoint); #endif void unbind(const ofFbo & fbo); diff --git a/libs/openFrameworks/gl/ofGLRenderer.cpp b/libs/openFrameworks/gl/ofGLRenderer.cpp index 293ce51ac66..5fb433691e2 100644 --- a/libs/openFrameworks/gl/ofGLRenderer.cpp +++ b/libs/openFrameworks/gl/ofGLRenderer.cpp @@ -42,21 +42,19 @@ ofGLRenderer::ofGLRenderer(const ofAppBaseWindow * _window) void ofGLRenderer::setup() { #ifdef TARGET_OPENGLES - // OpenGL ES might have set a default frame buffer for - // MSAA rendering to the window, bypassing ofFbo, so we - // can't trust ofFbo to have correctly tracked the bind - // state. Therefore, we are forced to use the slower glGet() method - // to be sure to get the correct default framebuffer. - GLint currentFrameBuffer; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFrameBuffer); - defaultFramebufferId = currentFrameBuffer; + // OpenGL ES might have set a default frame buffer for MSAA rendering to the window, + // bypassing ofFbo, so we can't trust ofFbo to have correctly tracked the bind state. + // Therefore we are forced to use the slower glGet() method to be sure. + GLint currentFramebuffer; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤tFramebuffer); + defaultFramebufferId = currentFramebuffer; currentFramebufferId = defaultFramebufferId; #endif + setupGraphicDefaults(); viewport(); setupScreenPerspective(); } - void ofGLRenderer::startRender() { currentFramebufferId = defaultFramebufferId; framebufferIdStack.push_back(defaultFramebufferId); @@ -509,7 +507,7 @@ void ofGLRenderer::bind(const ofFbo & fbo) { glBindFramebuffer(GL_FRAMEBUFFER, currentFramebufferId); } -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) //---------------------------------------------------------- void ofGLRenderer::bindForBlitting(const ofFbo & fboSrc, ofFbo & fboDst, int attachmentPoint) { if (currentFramebufferId == fboSrc.getId()) { @@ -517,17 +515,18 @@ void ofGLRenderer::bindForBlitting(const ofFbo & fboSrc, ofFbo & fboDst, int att << "Most probably you forgot to end() the current framebuffer before calling getTexture()."; return; } - // this method could just as well have been placed in ofBaseGLRenderer - // and shared over both programmable and fixed function renderer. - // I'm keeping it here, so that if we want to do more fancyful - // named framebuffers with GL 4.5+, we can have - // different implementations. + framebufferIdStack.push_back(currentFramebufferId); currentFramebufferId = fboSrc.getId(); + glBindFramebuffer(GL_READ_FRAMEBUFFER, currentFramebufferId); - glReadBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboDst.getIdDrawBuffer()); + +#ifndef TARGET_OPENGLES + // glReadBuffer / glDrawBuffer are desktop-only + glReadBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint); glDrawBuffer(GL_COLOR_ATTACHMENT0 + attachmentPoint); +#endif } #endif diff --git a/libs/openFrameworks/gl/ofGLRenderer.h b/libs/openFrameworks/gl/ofGLRenderer.h index 9371c516376..ba3e924f35d 100644 --- a/libs/openFrameworks/gl/ofGLRenderer.h +++ b/libs/openFrameworks/gl/ofGLRenderer.h @@ -211,7 +211,7 @@ class ofGLRenderer: public ofBaseGLRenderer{ void end(const ofFbo & fbo); void bind(const ofFbo & fbo); -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) void bindForBlitting(const ofFbo & fboSrc, ofFbo & fboDst, int attachmentPoint); #endif void unbind(const ofFbo & fbo); diff --git a/libs/openFrameworks/gl/ofGLUtils.cpp b/libs/openFrameworks/gl/ofGLUtils.cpp index 87ae5219443..885d21049af 100644 --- a/libs/openFrameworks/gl/ofGLUtils.cpp +++ b/libs/openFrameworks/gl/ofGLUtils.cpp @@ -89,43 +89,38 @@ int ofGetGLInternalFormat(const ofShortPixels& pixels) { //--------------------------------- int ofGetGLInternalFormat(const ofFloatPixels& pixels) { #if defined(TARGET_EMSCRIPTEN) - switch(pixels.getNumChannels()) { - case 3: return GL_RGB16F; - case 4: return GL_RGBA16F; - case 2: - ofLogWarning("ofGLUtils") << "ofGetGLInternalFormat(): two channel float textures not supported."; - return GL_RG16F; - default: - ofLogWarning("ofGLUtils") << "ofGetGLInternalFormat(): single channel float textures not supported."; - return GL_R16F; - } -#elif !defined(TARGET_OPENGLES) - switch(pixels.getNumChannels()) { - case 3: return GL_RGB32F; - case 4: return GL_RGBA32F; - case 2: - if(ofIsGLProgrammableRenderer()){ - return GL_RG32F; - }else{ - return GL_LUMINANCE_ALPHA32F_ARB; - } - default: - if(ofIsGLProgrammableRenderer()){ - return GL_R32F; - }else{ - return GL_LUMINANCE32F_ARB; - } - } + // WebGL2 has unreliable / slower support for 32F float textures + // → we force 16F for stability and performance (matches current master) + switch(pixels.getNumChannels()) { + case 3: return GL_RGB16F; + case 4: return GL_RGBA16F; + case 2: + ofLogWarning("ofGLUtils") << "ofGetGLInternalFormat(): two channel float textures not supported on Emscripten."; + return GL_RG16F; + default: + ofLogWarning("ofGLUtils") << "ofGetGLInternalFormat(): single channel float textures not supported on Emscripten."; + return GL_R16F; + } +#endif +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + // Desktop + native GLES 3.0+ → full 32F support + switch(pixels.getNumChannels()) { + case 3: return GL_RGB32F; + case 4: return GL_RGBA32F; + case 2: + return GL_RG32F; + default: + return GL_R32F; + } #else - ofLogWarning("ofGLUtils") << "ofGetGLInternalFormat(): float textures not supported in OpenGL ES"; - switch(pixels.getNumChannels()) { - case 3: return GL_RGB; - case 4: return GL_RGBA; - case 2: - return GL_LUMINANCE_ALPHA; - default: - return GL_LUMINANCE; - } + // GLES 2.0 fallback + ofLogWarning("ofGLUtils") << "ofGetGLInternalFormat(): float textures not supported in OpenGL ES < 3.0"; + switch(pixels.getNumChannels()) { + case 3: return GL_RGB; + case 4: return GL_RGBA; + case 2: return GL_LUMINANCE_ALPHA; + default: return GL_LUMINANCE; + } #endif } @@ -134,11 +129,11 @@ int ofGetGLInternalFormat(const ofFloatPixels& pixels) { string ofGetGLInternalFormatName(int glInternalFormat) { switch(glInternalFormat) { case GL_RGBA: return "GL_RGBA"; -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) case GL_RGBA8: return "GL_RGBA8"; #endif case GL_RGB: return "GL_RGB"; -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) case GL_RGB8: return "GL_RGB8"; #endif case GL_LUMINANCE: return "GL_LUMINANCE"; @@ -160,200 +155,221 @@ string ofGetGLInternalFormatName(int glInternalFormat) { } int ofGetGLFormatFromInternal(int glInternalFormat){ - switch(glInternalFormat) { - case GL_RGBA: - #if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) - case GL_RGBA8: - case GL_RGBA16: - case GL_RGBA16F: - case GL_RGBA16I: - case GL_RGBA16UI: - case GL_RGBA32F: - case GL_RGBA32I: - case GL_RGBA32UI: - #endif - return GL_RGBA; + switch(glInternalFormat) { + case GL_RGBA: + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_RGBA8: + case GL_RGBA16F: + #endif + #ifndef TARGET_OPENGLES + case GL_RGBA16: + case GL_RGBA32F_ARB: + case GL_RGBA16I: + case GL_RGBA16UI: + case GL_RGBA32I: + case GL_RGBA32UI: + #endif + return GL_RGBA; + #ifdef TARGET_OF_IOS - case GL_BGRA: - return GL_BGRA; + case GL_BGRA: + return GL_BGRA; #endif + case GL_RGB: + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_RGB8: + case GL_RGB16F: + #endif + #ifndef TARGET_OPENGLES + case GL_RGB16: + case GL_RGB32F_ARB: + #endif + return GL_RGB; - case GL_RGB: - #if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) - case GL_RGB8: - case GL_RGB16: - case GL_RGB16F: - case GL_RGB16I: - case GL_RGB16UI: - case GL_RGB32F: - case GL_RGB32I: - case GL_RGB32UI: - #endif - return GL_RGB; - - - case GL_LUMINANCE: - #if !defined(TARGET_OPENGLES) - case GL_LUMINANCE8: - case GL_LUMINANCE16: - case GL_LUMINANCE32F_ARB: + case GL_LUMINANCE: + #if !defined(TARGET_OPENGLES) + case GL_LUMINANCE8: + case GL_LUMINANCE16: + case GL_LUMINANCE32F_ARB: + #endif + return GL_LUMINANCE; + + case GL_LUMINANCE_ALPHA: + #if !defined(TARGET_OPENGLES) + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE16_ALPHA16: + case GL_LUMINANCE_ALPHA32F_ARB: + #endif + return GL_LUMINANCE_ALPHA; + + case GL_DEPTH_STENCIL: + return GL_DEPTH_STENCIL; + + case GL_DEPTH_COMPONENT: + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + #endif + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_DEPTH_COMPONENT32F: + #endif + #ifndef TARGET_OPENGLES + case GL_DEPTH_COMPONENT32: + #endif + return GL_DEPTH_COMPONENT; + + case GL_STENCIL_INDEX: + return GL_STENCIL_INDEX; + + // modern red / RG formats (used for float + half-float textures) + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_R8: + case GL_R16F: + case GL_R32F: + case GL_RG8: + case GL_RG16F: + case GL_RG32F: #endif - return GL_LUMINANCE; - - case GL_LUMINANCE_ALPHA: - #if !defined(TARGET_OPENGLES) - case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE16_ALPHA16: - case GL_LUMINANCE_ALPHA32F_ARB: + #ifndef TARGET_OPENGLES + case GL_R16: + case GL_RG16: + return (glInternalFormat == GL_R8 || glInternalFormat == GL_R16F || glInternalFormat == GL_R32F) ? GL_RED : GL_RG; #endif - return GL_LUMINANCE_ALPHA; - - case GL_DEPTH_STENCIL: - return GL_DEPTH_STENCIL; + #if !defined(TARGET_OPENGLES) && defined(GL_RGB565) + case GL_RGB565: + return GL_UNSIGNED_SHORT_5_6_5; + #endif - case GL_DEPTH_COMPONENT: -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: -#endif - return GL_DEPTH_COMPONENT; - - case GL_STENCIL_INDEX: - return GL_STENCIL_INDEX; - -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) - case GL_R8: - case GL_R16: - case GL_R16I: - case GL_R16UI: - case GL_R16F: - case GL_R32F: - case GL_R32I: - case GL_R32UI: - return GL_RED; - - case GL_RG8: - case GL_RG16: - case GL_RG16I: - case GL_RG16UI: - case GL_RG16F: - case GL_RG32F: - case GL_RG32I: - case GL_RG32UI: - return GL_RG; -#endif - -#ifndef TARGET_OPENGLES - case GL_ALPHA8: -#endif - case GL_ALPHA: - return GL_ALPHA; + #ifndef TARGET_OPENGLES + case GL_ALPHA8: + #endif + case GL_ALPHA: + return GL_ALPHA; - default: - ofLogError("ofGLUtils") << "ofGetGLFormatFromInternal(): unknown internal format " << glInternalFormat << ", returning GL_RGBA"; - return GL_RGBA; - - } + default: + ofLogError("ofGLUtils") << "ofGetGLFormatFromInternal(): unknown internal format " << glInternalFormat << ", returning GL_RGBA"; + return GL_RGBA; + } } int ofGetGLTypeFromInternal(int glInternalFormat){ - - switch(glInternalFormat) { - case GL_RGB: - case GL_RGBA: - case GL_LUMINANCE: - case GL_LUMINANCE_ALPHA: - case GL_ALPHA: -#ifndef TARGET_OPENGLES - case GL_LUMINANCE8: - case GL_LUMINANCE8_ALPHA8: - case GL_R8: - case GL_RG8: - case GL_RGB8: - case GL_RGBA8: - case GL_ALPHA8: -#endif - return GL_UNSIGNED_BYTE; - - -#if !defined(TARGET_OPENGLES) && defined(GL_RGB565) - case GL_RGB565: - return GL_UNSIGNED_SHORT_5_6_5; - break; -#endif - -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) - case GL_LUMINANCE32F_ARB: - case GL_LUMINANCE_ALPHA32F_ARB: - case GL_R32F: - case GL_RG32F: - case GL_RGB32F: - case GL_RGBA32F: - return GL_FLOAT; - - case GL_R16F: - case GL_RG16F: - case GL_RGB16F: - case GL_RGBA16F: - case GL_LUMINANCE16: - case GL_LUMINANCE16_ALPHA16: - case GL_R16: - case GL_RG16: - case GL_RGB16: - case GL_RGBA16: - return GL_HALF_FLOAT; -#endif - - case GL_DEPTH_STENCIL: - return GL_UNSIGNED_INT_24_8; - - case GL_DEPTH_COMPONENT: -#ifndef TARGET_OPENGLES - case GL_DEPTH_COMPONENT16: - case GL_R16UI: - case GL_RG16UI: - case GL_RGB16UI: - case GL_RGBA16UI: -#endif - return GL_UNSIGNED_SHORT; - -#ifndef TARGET_OPENGLES - case GL_R16I: - case GL_RG16I: - case GL_RGB16I: - case GL_RGBA16I: - return GL_SHORT; -#endif - -#ifndef TARGET_OPENGLES - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: - case GL_R32UI: - case GL_RG32UI: - case GL_RGB32UI: - case GL_RGBA32UI: - return GL_UNSIGNED_INT; -#endif - -#ifndef TARGET_OPENGLES - case GL_R32I: - case GL_RG32I: - case GL_RGB32I: - case GL_RGBA32I: - return GL_INT; -#endif - - case GL_STENCIL_INDEX: - return GL_UNSIGNED_BYTE; - - default: - ofLogError("ofGLUtils") << "ofGetGLTypeFromInternal(): unknown internal format " << glInternalFormat << ", returning GL_UNSIGNED_BYTE"; - return GL_UNSIGNED_BYTE; - - } + switch(glInternalFormat) { + // 8-bit unsigned byte formats (most common on all platforms) + case GL_RGB: + case GL_RGBA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_ALPHA: + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + #ifndef TARGET_OPENGLES + case GL_LUMINANCE8: + case GL_LUMINANCE8_ALPHA8: + case GL_ALPHA8: + #endif + case GL_R8: + case GL_RG8: + case GL_RGB8: + case GL_RGBA8: + #endif + return GL_UNSIGNED_BYTE; + + // 16-bit integer formats (desktop only) + #ifndef TARGET_OPENGLES + case GL_LUMINANCE16: + case GL_LUMINANCE16_ALPHA16: + case GL_R16: + case GL_RG16: + case GL_RGB16: + case GL_RGBA16: + return GL_UNSIGNED_SHORT; + #endif + + // 16-bit half-float formats (GLES 3.0 core + Emscripten) + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_R16F: + case GL_RG16F: + case GL_RGB16F: + case GL_RGBA16F: + #ifdef GL_HALF_FLOAT + return GL_HALF_FLOAT; // core in GLES 3.0+ + #else + return GL_HALF_FLOAT_OES; // safe fallback for older headers + #endif + #endif + + // 32-bit full float formats (native ES3 + desktop) + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_R32F: + case GL_RG32F: + case GL_RGB32F: + case GL_RGBA32F: + return GL_FLOAT; + #endif + + #ifndef TARGET_OPENGLES + // legacy desktop luminance float formats + case GL_LUMINANCE32F_ARB: + case GL_LUMINANCE_ALPHA32F_ARB: + return GL_FLOAT; + #endif + + // depth / stencil formats + case GL_DEPTH_STENCIL: + return GL_UNSIGNED_INT_24_8; + + case GL_DEPTH_COMPONENT: + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_DEPTH_COMPONENT16: + case GL_R16UI: + case GL_RG16UI: + case GL_RGB16UI: + case GL_RGBA16UI: + #endif + return GL_UNSIGNED_SHORT; + + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_DEPTH_COMPONENT24: + return GL_UNSIGNED_INT; + case GL_DEPTH_COMPONENT32F: + return GL_FLOAT; + #endif + + #ifndef TARGET_OPENGLES + case GL_DEPTH_COMPONENT32: + case GL_R32UI: + case GL_RG32UI: + case GL_RGB32UI: + case GL_RGBA32UI: + return GL_UNSIGNED_INT; + + case GL_R16I: + case GL_RG16I: + case GL_RGB16I: + case GL_RGBA16I: + return GL_SHORT; + + case GL_R32I: + case GL_RG32I: + case GL_RGB32I: + case GL_RGBA32I: + return GL_INT; + #endif + + case GL_STENCIL_INDEX: + return GL_UNSIGNED_BYTE; + + // legacy RGB565 (very old desktop/Android) + #if !defined(TARGET_OPENGLES) && defined(GL_RGB565) + case GL_RGB565: + return GL_UNSIGNED_SHORT_5_6_5; + #endif + + default: + ofLogError("ofGLUtils") << "ofGetGLTypeFromInternal(): unknown internal format " << glInternalFormat << ", returning GL_UNSIGNED_BYTE"; + return GL_UNSIGNED_BYTE; + } } //--------------------------------- @@ -381,104 +397,103 @@ int ofGetGLType(const ofFloatPixels & pixels) { //--------------------------------- ofImageType ofGetImageTypeFromGLType(int glType){ - switch(glType){ - case GL_LUMINANCE: -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) - case GL_LUMINANCE8: - case GL_LUMINANCE16: - case GL_LUMINANCE32F_ARB: - case GL_R8: - case GL_R16: - case GL_R16F: - case GL_R16I: - case GL_R16UI: - case GL_R32F: - case GL_R32I: - case GL_R32UI: - case GL_DEPTH_COMPONENT32F: - case GL_DEPTH_COMPONENT32: - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT: -#endif - return OF_IMAGE_GRAYSCALE; - - - case GL_RGB: -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) - case GL_RGB8: - case GL_RGB16: - case GL_RGB16F: - case GL_RGB16I: - case GL_RGB16UI: - case GL_RGB32F: - case GL_RGB32I: - case GL_RGB32UI: -#endif - return OF_IMAGE_COLOR; - - - case GL_RGBA: -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) - case GL_RGBA8: - case GL_RGBA16: - case GL_RGBA16F: - case GL_RGBA16I: - case GL_RGBA16UI: - case GL_RGBA32F: - case GL_RGBA32I: - case GL_RGBA32UI: -#endif - return OF_IMAGE_COLOR_ALPHA; - } - return OF_IMAGE_UNDEFINED; + switch(glType){ + case GL_LUMINANCE: + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + #ifndef TARGET_OPENGLES + case GL_LUMINANCE8: + case GL_LUMINANCE16: + case GL_LUMINANCE32F_ARB: + case GL_R8: + case GL_R16: + #endif + case GL_R16F: + case GL_R16I: + case GL_R16UI: + case GL_R32F: + case GL_R32I: + case GL_R32UI: + case GL_DEPTH_COMPONENT32F: + #ifndef TARGET_OPENGLES + case GL_DEPTH_COMPONENT32: + #endif + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT: + #endif + return OF_IMAGE_GRAYSCALE; + + case GL_RGB: + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_RGB8: + #ifndef TARGET_OPENGLES + case GL_RGB16: + #endif + case GL_RGB16F: + case GL_RGB16I: + case GL_RGB16UI: + case GL_RGB32F: + case GL_RGB32I: + case GL_RGB32UI: + #endif + return OF_IMAGE_COLOR; + + case GL_RGBA: + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_RGBA8: + #ifndef TARGET_OPENGLES + case GL_RGBA16: + #endif + case GL_RGBA16F: + case GL_RGBA16I: + case GL_RGBA16UI: + case GL_RGBA32F: + case GL_RGBA32I: + case GL_RGBA32UI: + #endif + return OF_IMAGE_COLOR_ALPHA; + } + return OF_IMAGE_UNDEFINED; } GLuint ofGetGLPolyMode(ofPolyRenderMode mode){ -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) +#if !defined(TARGET_OPENGLES) switch(mode){ - case(OF_MESH_POINTS): + case OF_MESH_POINTS: return GL_POINT; - break; - case(OF_MESH_WIREFRAME): + case OF_MESH_WIREFRAME: return GL_LINE; - break; - case(OF_MESH_FILL): + case OF_MESH_FILL: return GL_FILL; - break; default: ofLogError("ofGLUtils") << "ofGetGLPolyMode(): unknown OF poly mode " << ofToString(mode) << ", returning GL_FILL"; return GL_FILL; - break; } #else + ofLogError("ofGLUtils") << "ofGetGLPolyMode(): poly modes not supported in OpenGL ES < 3.0"; return 0; #endif } ofPolyRenderMode ofGetOFPolyMode(GLuint mode){ -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) +#if !defined(TARGET_OPENGLES) switch(mode){ - case(GL_POINT): + case GL_POINT: return OF_MESH_POINTS; - break; - case(GL_LINE): + case GL_LINE: return OF_MESH_WIREFRAME; - break; - case(GL_FILL): + case GL_FILL: return OF_MESH_FILL; - break; default: ofLogError("ofGLUtils") << "ofGetOFPolyMode(): unknown GL poly mode " << ofToString(mode) << ", returning OF_MESH_FILL"; return OF_MESH_FILL; - break; } #else + ofLogError("ofGLUtils") << "ofGetOFPolyMode(): poly modes not supported in OpenGL ES < 3.0. Returning OF_MESH_FILL"; return OF_MESH_FILL; #endif } - GLuint ofGetGLPrimitiveMode(ofPrimitiveMode mode){ switch(mode){ case OF_PRIMITIVE_TRIANGLES: @@ -578,14 +593,14 @@ int ofGetGLInternalFormatFromPixelFormat(ofPixelFormat pixelFormat){ switch(pixelFormat){ case OF_PIXELS_BGRA: case OF_PIXELS_RGBA: -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) return GL_RGBA8; #else return GL_RGBA; #endif case OF_PIXELS_RGB: case OF_PIXELS_BGR: -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) return GL_RGB8; #else return GL_RGB; @@ -636,70 +651,71 @@ int ofGetGLInternalFormatFromPixelFormat(ofPixelFormat pixelFormat){ } int ofGetGLFormatFromPixelFormat(ofPixelFormat pixelFormat){ - switch(pixelFormat){ - case OF_PIXELS_BGRA: -#ifdef TARGET_OPENGLES - return GL_BGRA_EXT; -#else + switch(pixelFormat){ + case OF_PIXELS_BGRA: + #ifdef TARGET_OPENGLES + return GL_BGRA_EXT; + #else return GL_BGRA; -#endif - case OF_PIXELS_RGB: - return GL_RGB; - case OF_PIXELS_BGR: -#ifdef TARGET_OPENGLES - return GL_RGB; -#else + #endif + + case OF_PIXELS_RGB: + return GL_RGB; + + case OF_PIXELS_BGR: + #ifdef TARGET_OPENGLES + return GL_RGB; // ES does not support GL_BGR + #else return GL_BGR; -#endif - case OF_PIXELS_RGBA: - return GL_RGBA; + #endif + + case OF_PIXELS_RGBA: + return GL_RGBA; + case OF_PIXELS_RGB565: return GL_RGB; - case OF_PIXELS_GRAY: + + case OF_PIXELS_GRAY: case OF_PIXELS_NV12: case OF_PIXELS_NV21: - case OF_PIXELS_YV12: - case OF_PIXELS_I420: - case OF_PIXELS_Y: - case OF_PIXELS_U: - case OF_PIXELS_V: -#ifndef TARGET_OPENGLES - if(ofIsGLProgrammableRenderer()){ - return GL_RED; - }else{ -#endif - return GL_LUMINANCE; -#ifndef TARGET_OPENGLES - } -#endif + case OF_PIXELS_YV12: + case OF_PIXELS_I420: + case OF_PIXELS_Y: + case OF_PIXELS_U: + case OF_PIXELS_V: + #ifndef TARGET_OPENGLES + if(ofIsGLProgrammableRenderer()){ + return GL_RED; + }else{ + #endif + return GL_LUMINANCE; + #ifndef TARGET_OPENGLES + } + #endif + case OF_PIXELS_GRAY_ALPHA: - case OF_PIXELS_YUY2: - case OF_PIXELS_UV: - case OF_PIXELS_VU: -#ifndef TARGET_OPENGLES - if(ofIsGLProgrammableRenderer()){ - return GL_RG; - }else{ -#endif - return GL_LUMINANCE_ALPHA; -#ifndef TARGET_OPENGLES - } -#endif - default: -#ifndef TARGET_OPENGLES - if(ofIsGLProgrammableRenderer()){ - ofLogError("ofGLUtils") << "ofGetGLFormatFromPixelFormat(): unknown OF pixel format " - << ofToString(pixelFormat) << ", returning GL_RED"; - return GL_RED; - }else{ -#endif - ofLogError("ofGLUtils") << "ofGetGLFormatFromPixelFormat(): unknown OF pixel format " - << ofToString(pixelFormat) << ", returning GL_LUMINANCE"; - return GL_LUMINANCE; -#ifndef TARGET_OPENGLES - } -#endif - } + case OF_PIXELS_YUY2: + case OF_PIXELS_UV: + case OF_PIXELS_VU: + #ifndef TARGET_OPENGLES + if(ofIsGLProgrammableRenderer()){ + return GL_RG; + }else{ + #endif + return GL_LUMINANCE_ALPHA; + #ifndef TARGET_OPENGLES + } + #endif + + default: + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + ofLogError("ofGLUtils") << "ofGetGLFormatFromPixelFormat(): unknown OF pixel format " << pixelFormat << ", returning GL_RED"; + return ofIsGLProgrammableRenderer() ? GL_RED : GL_LUMINANCE; + #else + ofLogError("ofGLUtils") << "ofGetGLFormatFromPixelFormat(): unknown OF pixel format " << pixelFormat << ", returning GL_LUMINANCE"; + return GL_LUMINANCE; + #endif + } } @@ -716,7 +732,7 @@ int ofGetNumChannelsFromGLFormat(int glFormat){ return 1; case GL_LUMINANCE_ALPHA: return 2; -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) case GL_RED: return 1; case GL_RG: @@ -728,44 +744,39 @@ int ofGetNumChannelsFromGLFormat(int glFormat){ } int ofGetBytesPerChannelFromGLType(int glType){ - switch(glType) { - case GL_UNSIGNED_BYTE: - return 1; - case GL_UNSIGNED_SHORT: - return 2; - -#if !defined(TARGET_OPENGLES) && defined(GL_RGB565) - case GL_UNSIGNED_SHORT_5_6_5: - return 2; + switch(glType) { + case GL_UNSIGNED_BYTE: + return 1; + case GL_UNSIGNED_SHORT: + return 2; + +#if !defined(TARGET_OPENGLES) || defined(GL_RGB565) + case GL_UNSIGNED_SHORT_5_6_5: + return 2; #endif -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) - case GL_FLOAT: - return 4; +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_FLOAT: + return 4; #endif - case GL_UNSIGNED_INT_24_8: - return 4; + case GL_UNSIGNED_INT_24_8: + return 4; -#ifndef TARGET_OPENGLES - case GL_UNSIGNED_INT: - return 4; +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_UNSIGNED_INT: + return 4; #endif - case GL_HALF_FLOAT: - return 2; - default: - ofLogError("ofGetBytesPerChannelFromGLType") << "unknown type returning 1"; - return 1; + case GL_HALF_FLOAT: + return 2; - } + default: + ofLogError("ofGetBytesPerChannelFromGLType") << "unknown type returning 1"; + return 1; + } } -// Rounds an integer value up to the next multiple of 2,4 and 8. -#define OF_ROUND_UP_2(num) (((num)+1)&~1) -#define OF_ROUND_UP_4(num) (((num)+3)&~3) -#define OF_ROUND_UP_8(num) (((num)+7)&~7) - void ofSetPixelStoreiAlignment(GLenum pname, int w, int bpc, int numChannels){ int stride = w * numChannels * bpc; ofSetPixelStoreiAlignment(pname,stride); @@ -818,47 +829,48 @@ bool ofGLCheckExtension(string searchName){ } bool ofGLSupportsNPOTTextures(){ -#ifndef TARGET_OPENGLES - return GL_ARB_texture_rectangle; -#elif !defined(TARGET_EMSCRIPTEN) +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + // Desktop + GLES 3.0+ support NPOT textures natively (core feature) + return true; +#else + // Pure GLES 2.0 — check extensions at runtime static bool npotChecked = false; static bool npotSupported = false; if(!npotChecked){ vector extensionsList = ofGLSupportedExtensions(); - std::set extensionsSet; - extensionsSet.insert(extensionsList.begin(),extensionsList.end()); - - npotSupported = extensionsSet.find("GL_OES_texture_npot")!=extensionsSet.end() || - extensionsSet.find("APPLE_texture_2D_limited_npot")!=extensionsSet.end() || - extensionsSet.find("GL_NV_texture_npot_2D_mipmap")!=extensionsSet.end() || - extensionsSet.find("GL_IMG_texture_npot")!=extensionsSet.end() || - extensionsSet.find("GL_ARB_texture_non_power_of_two")!=extensionsSet.end(); + std::set extensionsSet(extensionsList.begin(), extensionsList.end()); + + npotSupported = extensionsSet.find("GL_OES_texture_npot") != extensionsSet.end() || + extensionsSet.find("APPLE_texture_2D_limited_npot") != extensionsSet.end() || + extensionsSet.find("GL_NV_texture_npot_2D_mipmap") != extensionsSet.end() || + extensionsSet.find("GL_IMG_texture_npot") != extensionsSet.end() || + extensionsSet.find("GL_ARB_texture_non_power_of_two") != extensionsSet.end(); + npotChecked = true; } return npotSupported; -#else - return true; #endif } string ofGLSLVersionFromGL(int major, int minor){ #ifdef TARGET_OPENGLES + #ifdef TARGET_EMSCRIPTEN - if( major >= 2 ) { // for emscripten major version refers to WEBGL version - return "300 es"; - } else { - return "ES1"; - } + if(major >= 2) { // for emscripten major version refers to WEBGL version + return "300"; // WebGL2 = GLSL ES 3.00 (header adds " es") + } else { + return "100"; + } #else if(major == 1){ return "ES1"; }else if(major == 2){ - return "ES2"; + return "100"; }else if(major == 3){ - return "ES3"; + return "300"; }else { - return "ES1"; + return ofToString(major*100+minor*10); } #endif #else @@ -884,7 +896,7 @@ string ofGLSLVersionFromGL(int major, int minor){ string ofGLSLVersionFromGL(){ int major = 0; int minor = 0; - + auto glRenderer = std::dynamic_pointer_cast(ofGetCurrentRenderer()); if( glRenderer ){ major = glRenderer->getGLVersionMajor(); @@ -898,11 +910,11 @@ string ofGLSLGetDefaultHeader(){ string header = ""; auto glRenderer = std::dynamic_pointer_cast(ofGetCurrentRenderer()); - + if( glRenderer ){ string versionStr = ofGLSLVersionFromGL(glRenderer->getGLVersionMajor(), glRenderer->getGLVersionMinor()); header = "#version "+versionStr+"\n"; - + #ifdef TARGET_OPENGLES if( versionStr != "ES1" ){ header += "#extension GL_OES_standard_derivatives : enable\n"; diff --git a/libs/openFrameworks/gl/ofGLUtils.h b/libs/openFrameworks/gl/ofGLUtils.h index f777a7a32e3..b6a39e4e890 100644 --- a/libs/openFrameworks/gl/ofGLUtils.h +++ b/libs/openFrameworks/gl/ofGLUtils.h @@ -178,7 +178,7 @@ void ofDisableGLDebugLog(); #define GL_DEPTH_COMPONENT32 GL_DEPTH_COMPONENT32_OES #endif #endif - + #ifndef GL_RGBA32F #ifdef GL_RGBA32F_EXT #define GL_RGBA32F GL_RGBA32F_EXT @@ -192,16 +192,83 @@ void ofDisableGLDebugLog(); #ifndef GL_HALF_FLOAT #define GL_HALF_FLOAT GL_HALF_FLOAT_OES #endif - #ifndef GL_TEXTURE_CUBE_MAP - #ifdef GL_TEXTURE_CUBE_MAP_OES - #define GL_TEXTURE_CUBE_MAP GL_TEXTURE_CUBE_MAP_OES + #ifndef GL_TEXTURE_CUBE_MAP + #ifdef GL_TEXTURE_CUBE_MAP_OES + #define GL_TEXTURE_CUBE_MAP GL_TEXTURE_CUBE_MAP_OES + #endif #endif - #endif #endif + + #if (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + // === GLES 3.0 / 3.1 additional fallbacks === + // High-precision depth (very useful for shadows / FBOs) + #ifndef GL_DEPTH_COMPONENT32F + #ifdef GL_DEPTH_COMPONENT32F_EXT + #define GL_DEPTH_COMPONENT32F GL_DEPTH_COMPONENT32F_EXT + #endif + #endif + + // Half-float textures (16F) — core in GLES 3.0 but often exposed via EXT + #ifndef GL_R16F + #ifdef GL_R16F_EXT + #define GL_R16F GL_R16F_EXT + #endif + #endif + #ifndef GL_RG16F + #ifdef GL_RG16F_EXT + #define GL_RG16F GL_RG16F_EXT + #endif + #endif + #ifndef GL_RGB16F + #ifdef GL_RGB16F_EXT + #define GL_RGB16F GL_RGB16F_EXT + #endif + #endif + #ifndef GL_RGBA16F + #ifdef GL_RGBA16F_EXT + #define GL_RGBA16F GL_RGBA16F_EXT + #endif + #endif + + // 32-bit float textures (also core in GLES 3.0) + #ifndef GL_R32F + #ifdef GL_R32F_EXT + #define GL_R32F GL_R32F_EXT + #endif + #endif + #ifndef GL_RG32F + #ifdef GL_RG32F_EXT + #define GL_RG32F GL_RG32F_EXT + #endif + #endif + #ifndef GL_RGB32F + #ifdef GL_RGB32F_EXT + #define GL_RGB32F GL_RGB32F_EXT + #endif + #endif + #ifndef GL_RGBA32F + #ifdef GL_RGBA32F_EXT + #define GL_RGBA32F GL_RGBA32F_EXT + #endif + #endif + + // Renderbuffer storage for multisampled FBOs (GLES 3.0+) + #ifndef glRenderbufferStorageMultisample + #ifdef glRenderbufferStorageMultisampleEXT + #define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT + #endif + #endif + #endif + #ifndef glTexStorage2D #ifdef glTexStorage2DEXT #define glTexStorage2D glTexStorage2DEXT #endif #endif #endif + +// Rounds an integer value up to the next multiple of 2,4 and 8. +#define OF_ROUND_UP_2(num) (((num)+1)&~1) +#define OF_ROUND_UP_4(num) (((num)+3)&~3) +#define OF_ROUND_UP_8(num) (((num)+7)&~7) diff --git a/libs/openFrameworks/gl/ofMaterial.cpp b/libs/openFrameworks/gl/ofMaterial.cpp index 27c5a53e54d..43326c8ef4d 100644 --- a/libs/openFrameworks/gl/ofMaterial.cpp +++ b/libs/openFrameworks/gl/ofMaterial.cpp @@ -110,39 +110,34 @@ std::string ofMaterial::getTextureTypeAsString(const ofMaterialTextureType & aMa //---------------------------------------------------------- bool ofMaterial::isPBRSupported() { - #if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN) - return false; + #if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + return false; // pure GLES 2.0 does not support PBR #endif - - if( !ofIsGLProgrammableRenderer() ) { - return false; - } - return true; + return ofIsGLProgrammableRenderer(); } //---------------------------------------------------------- void ofMaterial::setPBR(bool ab) { - if( ab && !ofIsGLProgrammableRenderer() ) { - if( !bPrintedPBRRenderWarning ) { - bPrintedPBRRenderWarning=true; - ofLogWarning("ofMaterial::setPBR") << " PBR material must be used with Programmable Renderer."; + if (ab && !ofIsGLProgrammableRenderer()) { + if (!bPrintedPBRRenderWarning) { + bPrintedPBRRenderWarning = true; + ofLogWarning("ofMaterial::setPBR") << "PBR material must be used with Programmable Renderer."; } data.isPbr = false; return; } - - #if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN) - if( ab ) { - if( !bPrintedPBRRenderWarning ) { - bPrintedPBRRenderWarning=true; - ofLogWarning("ofMaterial::setPBR") << " PBR material is not supported on this OPENGL ES platform."; + + #if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + if (ab) { + if (!bPrintedPBRRenderWarning) { + bPrintedPBRRenderWarning = true; + ofLogWarning("ofMaterial::setPBR") << "PBR material is not supported on OpenGL ES < 3.0."; } data.isPbr = false; return; } #endif - - + data.isPbr = ab; } @@ -156,8 +151,8 @@ void ofMaterial::setColors(ofFloatColor oDiffuse, ofFloatColor oAmbient, ofFloat //---------------------------------------------------------- void ofMaterial::setup(const ofMaterialSettings & settings){ - if(settings.customUniforms != data.customUniforms || settings.postFragment != data.postFragment || - settings.mainVertexKey != data.mainVertexKey || settings.mainFragmentKey != data.mainFragmentKey || + if(settings.customUniforms != data.customUniforms || settings.postFragment != data.postFragment || + settings.mainVertexKey != data.mainVertexKey || settings.mainFragmentKey != data.mainFragmentKey || settings.isPbr != data.isPbr){ shaders.clear(); uniforms1f.clear(); @@ -182,9 +177,9 @@ void ofMaterial::setShaderMain(std::string aShaderSrc, GLenum atype, std::string ofLogWarning("ofMaterial::setShaderMain") << "only available on PBR materials."; return; } - + if(atype == GL_VERTEX_SHADER) { - // we would like to replace the current shader at key + // we would like to replace the current shader at key // using a skey instead of shadersrc as key so we can easily overwrite if( data.mainVertexKey == skey) { // delete previous shader here, whether frag shader has same key or not @@ -288,13 +283,13 @@ bool ofMaterial::loadTexture( const ofMaterialTextureType& aMaterialTextureType, //---------------------------------------------------------- bool ofMaterial::loadTexture( const ofMaterialTextureType& aMaterialTextureType, std::string apath, bool bTex2d, bool mirrorY ) { - + bool bWasUsingArb = ofGetUsingArbTex(); bTex2d ? ofDisableArbTex() : ofEnableArbTex(); - + auto tex { std::make_shared() }; bool bLoadOk = ofLoadImage(*tex, apath, mirrorY ); - + if( bLoadOk ) { // if there was a previous instance, then erase it, then replace it if( mLocalTextures.find(aMaterialTextureType) != mLocalTextures.end() ) { @@ -308,7 +303,7 @@ bool ofMaterial::loadTexture( const ofMaterialTextureType& aMaterialTextureType, } else { ofLogError("ofMaterial") << "loadTexture(): FAILED for " << getUniformName(aMaterialTextureType) << " at path: " << apath; } - + bWasUsingArb ? ofEnableArbTex() : ofDisableArbTex(); return bLoadOk; } @@ -348,8 +343,8 @@ void ofMaterial::setTexture(const ofMaterialTextureType& aMaterialTextureType,co setPBR(true); } } - - + + if(aMaterialTextureType == OF_MATERIAL_TEXTURE_CLEARCOAT || aMaterialTextureType == OF_MATERIAL_TEXTURE_CLEARCOAT_ROUGHNESS || @@ -439,7 +434,7 @@ void ofMaterial::setClearCoatTexture( const ofTexture& aTex ) { //---------------------------------------------------- void ofMaterial::setMetallic( const float& ametallic ) { data.metallic = ametallic; - + if( isBound() && isPBR() && currentRenderShader) { currentRenderShader->setUniform1f("mat_metallic", data.metallic ); } @@ -649,12 +644,12 @@ void ofMaterial::mergeCustomUniformTextures() { OF_MATERIAL_TEXTURE_ROUGHNESS, OF_MATERIAL_TEXTURE_METALLIC } ); - + mergeCustomUniformTextures(OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC, { OF_MATERIAL_TEXTURE_OCCLUSION, OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC } ); - + mergeCustomUniformTextures(OF_MATERIAL_TEXTURE_AO_ROUGHNESS_METALLIC, { OF_MATERIAL_TEXTURE_OCCLUSION, OF_MATERIAL_TEXTURE_ROUGHNESS, @@ -671,7 +666,7 @@ void ofMaterial::mergeCustomUniformTextures(ofMaterialTextureType mainType, std: int texTarget; bool bMatchingTextures = true; int minTexLocation = 99999; - + for(size_t i = 0; i < mtsSize; i++ ) { if(!hasTexture(mergeTypes[i])){ bHasAllMergeTypes = false; @@ -693,7 +688,7 @@ void ofMaterial::mergeCustomUniformTextures(ofMaterialTextureType mainType, std: } } } - + if(bHasAllMergeTypes && bMatchingTextures && minTexLocation < 1000){ for(size_t i = 0; i < mtsSize; i++ ) { removeCustomUniformTexture(mergeTypes[i]); @@ -757,9 +752,9 @@ void ofMaterial::initDepthShaders(ofGLProgrammableRenderer & renderer) const { depthShadersMap[&renderer].erase(sids.first); } } - + ofLogVerbose("ofMaterial :: initShaders : depth shaders: " ) << depthShadersMap.size() << " | " << ofGetFrameNum(); - + auto trendererShaders = mDepthShaders.find(&renderer); if( trendererShaders != mDepthShaders.end() ) { if(trendererShaders->second) { @@ -770,12 +765,12 @@ void ofMaterial::initDepthShaders(ofGLProgrammableRenderer & renderer) const { mDepthShaderIdsToRemove.clear(); } } - + // now lets check the depth shaders if( getDepthShaderStringId() != "" ) { auto depthShaders = mDepthShaders.find(&renderer); const std::string shaderId = getDepthShaderStringId(); - + if(depthShaders == mDepthShaders.end() || depthShaders->second->shaderId != shaderId ){ if(depthShadersMap[&renderer].find(shaderId) != depthShadersMap[&renderer].end()){ @@ -791,17 +786,17 @@ void ofMaterial::initDepthShaders(ofGLProgrammableRenderer & renderer) const { mDepthShaders[&renderer] = nullptr; } } - + if(mDepthShaders[&renderer] == nullptr){ ofLogVerbose("ofMaterial") << "initDepthShaders : allocating depth shaders | " << ofGetFrameNum(); - + mDepthShaders[&renderer].reset(new DepthShaders); mDepthShaders[&renderer]->shaderId = shaderId; - + depthShadersMap[&renderer][shaderId] = mDepthShaders[&renderer]; } } - + } //----------------------------------------------------------- @@ -810,28 +805,28 @@ const ofShader& ofMaterial::getShadowDepthShader( const ofShadow& ashadow, ofGLP // std::string shadowId = ofToString(ashadow.getData()->lightType, 0)+"_"+ofToString(ashadow.getNumShadowDepthPasses(), 0); unsigned int shadowShaderId = ashadow.getData()->lightType + ((ashadow.getNumShadowDepthPasses()+1)*100); auto shadowShader = mDepthShaders[&renderer]->shaders.find(shadowShaderId); - + if(shadowShader == mDepthShaders[&renderer]->shaders.end() || !mDepthShaders[&renderer]->shaders[shadowShaderId] ) { auto nDepthShader { std::make_shared() }; - + auto customUniforms = data.customUniforms; for( auto & custom : mCustomUniforms ){ customUniforms += custom.second + " " + custom.first + ";\n"; } - + std::string definesString = getDefinesString(); definesString += "#define SAMPLER sampler2D\n"; definesString += "#define TEXTURE texture\n"; std::string extraVertString = definesString; extraVertString += customUniforms; - + std::string srcMain = extraVertString+shaderDepthVertexSource(data); ofLogVerbose("--ofMaterial::getShadowDepthShader--"); if(!ashadow.setupShadowDepthShader( *nDepthShader, srcMain )) { ofLogError("ofMaterial :: getShadowDepthShader() : error loading depth shader: ") << data.mainDepthVertexKey; } ofLogVerbose(nDepthShader->getShaderSource(GL_VERTEX_SHADER)); - + mDepthShaders[&renderer]->shaders[shadowShaderId] = nDepthShader; } return *mDepthShaders[&renderer]->shaders[shadowShaderId]; @@ -839,139 +834,80 @@ const ofShader& ofMaterial::getShadowDepthShader( const ofShadow& ashadow, ofGLP //----------------------------------------------------------- void ofMaterial::initShaders(ofGLProgrammableRenderer & renderer) const{ - // remove any shaders that have their main source remove - { - if( mShaderIdsToRemove.size() ) { - for( auto& sids : mShaderIdsToRemove ) { - if(shadersMap[&renderer].find(sids.first)!=shadersMap[&renderer].end()){ - auto newShaders = shadersMap[&renderer][sids.first].lock(); - if( newShaders ) { - newShaders.reset(); - } - shadersMap[&renderer].erase(sids.first); - } - } - - ofLogVerbose("ofMaterial :: initShaders") << shadersMap.size() << " | " << ofGetFrameNum(); - - auto trendererShaders = shaders.find(&renderer); - if( trendererShaders != shaders.end() ) { - if(trendererShaders->second) { - trendererShaders->second.reset(); - } - shaders.erase(&renderer); - } - mShaderIdsToRemove.clear(); - } - } - + // remove any shaders that have their main source removed + { + if( mShaderIdsToRemove.size() ) { + for( auto& sids : mShaderIdsToRemove ) { + if(shadersMap[&renderer].find(sids.first)!=shadersMap[&renderer].end()){ + auto newShaders = shadersMap[&renderer][sids.first].lock(); + if( newShaders ) { + newShaders.reset(); + } + shadersMap[&renderer].erase(sids.first); + } + } + ofLogVerbose("ofMaterial :: initShaders") << shadersMap.size() << " | " << ofGetFrameNum(); + auto trendererShaders = shaders.find(&renderer); + if( trendererShaders != shaders.end() ) { + if(trendererShaders->second) { + trendererShaders->second.reset(); + } + shaders.erase(&renderer); + } + mShaderIdsToRemove.clear(); + } + } auto rendererShaders = shaders.find(&renderer); - - size_t numLights = ofLightsData().size(); - // only support for a single cube map at a time - size_t numCubeMaps = ofCubeMap::getCubeMapsData().size() > 0 ? 1 : 0; - const std::string shaderId = getShaderStringId(); - - if(rendererShaders == shaders.end() || - rendererShaders->second->numLights != numLights || - rendererShaders->second->numCubeMaps != numCubeMaps || - rendererShaders->second->shaderId != shaderId ){ - if(shadersMap[&renderer].find(shaderId)!=shadersMap[&renderer].end()){ - auto newShaders = shadersMap[&renderer][shaderId].lock(); - if(newShaders == nullptr || newShaders->numLights != numLights || newShaders->numCubeMaps != numCubeMaps ){ - shadersMap[&renderer].erase(shaderId); - shaders[&renderer] = nullptr; - }else{ - ofLogVerbose("ofMaterial") << "initShaders : swapping shaders | " << ofGetFrameNum(); - shaders[&renderer] = newShaders; - } - } else { - shaders[&renderer] = nullptr; - } - } + size_t numLights = ofLightsData().size(); + // only support for a single cube map at a time + size_t numCubeMaps = ofCubeMap::getCubeMapsData().size() > 0 ? 1 : 0; + const std::string shaderId = getShaderStringId(); + + if(rendererShaders == shaders.end() || + rendererShaders->second->numLights != numLights || + rendererShaders->second->numCubeMaps != numCubeMaps || + rendererShaders->second->shaderId != shaderId ){ + + if(shadersMap[&renderer].find(shaderId)!=shadersMap[&renderer].end()){ + auto newShaders = shadersMap[&renderer][shaderId].lock(); + if(newShaders == nullptr || newShaders->numLights != numLights || newShaders->numCubeMaps != numCubeMaps ){ + shadersMap[&renderer].erase(shaderId); + shaders[&renderer] = nullptr; + }else{ + ofLogVerbose("ofMaterial") << "initShaders : swapping shaders | " << ofGetFrameNum(); + shaders[&renderer] = newShaders; + } + } else { + shaders[&renderer] = nullptr; + } + } if(shaders[&renderer] == nullptr){ - ofLogVerbose("ofMaterial") << "initShaders : allocating shaders again | " << ofGetFrameNum(); + ofLogVerbose("ofMaterial") << "initShaders : allocating shaders again | " << ofGetFrameNum(); + //add the custom uniforms to the shader header auto customUniforms = data.customUniforms; for( auto & custom : mCustomUniforms ){ - customUniforms += custom.second + " " + custom.first + ";\n"; + customUniforms += custom.second + " " + custom.first + ";\n"; } + std::string definesString = getDefinesString(); + + std::string extraVertString = definesString; + extraVertString += customUniforms; - std::string definesString = getDefinesString(); - - ofLogVerbose("ofMaterial") << " defines--------------- " << std::endl; - ofLogVerbose("ofMaterial") << definesString; - ofLogVerbose("ofMaterial") << "textures --------------- " << uniformstex.size(); - for (auto & uniform : uniformstex) { - ofLogVerbose() << uniform.first << ", " << uniform.second.textureTarget <<", " << uniform.second.textureID << ", " << uniform.second.textureLocation << std::endl; - } - - std::string extraVertString = definesString; -// if( hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) { -// extraVertString += "\nuniform SAMPLER "+getUniformName(OF_MATERIAL_TEXTURE_DISPLACEMENT)+";\n"; -// } - extraVertString += customUniforms; - ofLogVerbose( "ofMaterial" ) << " extraVertString------------------- "; - ofLogVerbose() << extraVertString; - ofLogVerbose( "ofMaterial" ) << "! extraVertString !------------------- " << std::endl; - #ifndef TARGET_OPENGLES - string vertexRectHeader = renderer.defaultVertexShaderHeader(GL_TEXTURE_RECTANGLE); - string fragmentRectHeader = renderer.defaultFragmentShaderHeader(GL_TEXTURE_RECTANGLE); + string vertexRectHeader = renderer.defaultVertexShaderHeader(GL_TEXTURE_RECTANGLE); + string fragmentRectHeader = renderer.defaultFragmentShaderHeader(GL_TEXTURE_RECTANGLE); #endif string vertex2DHeader = renderer.defaultVertexShaderHeader(GL_TEXTURE_2D); string fragment2DHeader = renderer.defaultFragmentShaderHeader(GL_TEXTURE_2D); - - #if defined(TARGET_OPENGLES) && defined(TARGET_EMSCRIPTEN) - // TODO: Should this be in programmable renderer? - if(ofIsGLProgrammableRenderer()) { -// if(isPBR()) { -// header = "#version 300 es\n";// + header; - vertex2DHeader = "#version "+ofGLSLVersionFromGL(renderer.getGLVersionMajor(), renderer.getGLVersionMinor())+"\n"; - vertex2DHeader += "precision highp float;\n"; - vertex2DHeader += "precision highp int;\n"; - vertex2DHeader += "#define TARGET_OPENGLES\n"; - vertex2DHeader += "#define IN in\n"; - vertex2DHeader += "#define OUT out\n"; - vertex2DHeader += "#define TEXTURE texture\n"; - vertex2DHeader += "#define SAMPLER sampler2D\n"; - - fragment2DHeader = "#version "+ofGLSLVersionFromGL(renderer.getGLVersionMajor(), renderer.getGLVersionMinor())+"\n"; - fragment2DHeader += "precision highp float;\n"; - fragment2DHeader += "precision highp int;\n"; - fragment2DHeader += "#define TARGET_OPENGLES\n"; - fragment2DHeader += "#define IN in\n"; - fragment2DHeader += "#define OUT out\n"; - fragment2DHeader += "#define TEXTURE texture\n"; - fragment2DHeader += "#define FRAG_COLOR fragColor\n"; - fragment2DHeader += "out vec4 fragColor;\n"; - fragment2DHeader += "#define SAMPLER sampler2D\n"; - fragment2DHeader += "precision highp sampler2D;\n"; - fragment2DHeader += "precision highp samplerCube;\n"; - // we don't use any samplerCubeShadows - //fragment2DHeader += "precision highp samplerCubeShadow;\n"; - fragment2DHeader += "precision mediump sampler2DShadow;\n"; - #if defined( GL_TEXTURE_2D_ARRAY ) && defined(glTexImage3D) - fragment2DHeader += "precision mediump sampler2DArrayShadow;\n"; - #endif -// fragment2DHeader += "precision highp samplerCubeShadow;\n"; -// fragment2DHeader += "precision highp sampler2DShadow;\n"; -// fragment2DHeader += "precision highp sampler2DArrayShadow;\n"; -// } - } - #endif - - ofLogVerbose( "ofMaterial" ) << " fragment2DHeader------------------- "; - ofLogVerbose() << fragment2DHeader; - ofLogVerbose( "ofMaterial" ) << " fragment2DHeader "; shaders[&renderer].reset(new Shaders); shaders[&renderer]->numLights = numLights; - shaders[&renderer]->numCubeMaps = numCubeMaps; - shaders[&renderer]->shaderId = shaderId; - + shaders[&renderer]->numCubeMaps = numCubeMaps; + shaders[&renderer]->shaderId = shaderId; + shaders[&renderer]->noTexture.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertex2DHeader,numLights,false,false,extraVertString,data)); shaders[&renderer]->noTexture.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragment2DHeader, customUniforms, data,numLights,false,false, definesString)); shaders[&renderer]->noTexture.bindDefaults(); @@ -994,7 +930,6 @@ void ofMaterial::initShaders(ofGLProgrammableRenderer & renderer) const{ shaders[&renderer]->color.bindDefaults(); shaders[&renderer]->color.linkProgram(); - shaders[&renderer]->texture2DColor.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertex2DHeader,numLights,true,true,extraVertString,data)); shaders[&renderer]->texture2DColor.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragment2DHeader, customUniforms, data,numLights,true,true,definesString)); shaders[&renderer]->texture2DColor.bindDefaults(); @@ -1007,18 +942,17 @@ void ofMaterial::initShaders(ofGLProgrammableRenderer & renderer) const{ shaders[&renderer]->textureRectColor.linkProgram(); #endif - shadersMap[&renderer][shaderId] = shaders[&renderer]; + shadersMap[&renderer][shaderId] = shaders[&renderer]; } - } const ofShader & ofMaterial::getShader(int textureTarget, bool geometryHasColor, ofGLProgrammableRenderer & renderer) const{ initShaders(renderer); - + if(bHasCustomShader && customShader){ return *customShader; } - + // override the textureTarget argument coming from the programmable renderer // the renderer is passing the textureTarget based on if there is a texture that is bound // if there is no texture bound, then go ahead and switch to the diffuse texture @@ -1027,7 +961,7 @@ const ofShader & ofMaterial::getShader(int textureTarget, bool geometryHasColor, const auto& dt = uniformstex.at(loc); textureTarget = dt.textureTarget; } - + switch(textureTarget){ case OF_NO_TEXTURE: if(geometryHasColor){ @@ -1055,10 +989,10 @@ const ofShader & ofMaterial::getShader(int textureTarget, bool geometryHasColor, void ofMaterial::updateMaterial(const ofShader & shader,ofGLProgrammableRenderer & renderer) const{ currentRenderShader = &shader; - + shader.setUniform4fv("mat_emissive", &data.emissive.r); shader.setUniform2f("mat_texcoord_scale", data.texCoordScale ); - + if( isPBR() ) { shader.setUniform3f("uCameraPos", renderer.getCurrentEyePosition()); shader.setUniform4fv("mat_diffuse", &data.diffuse.r ); @@ -1068,7 +1002,7 @@ void ofMaterial::updateMaterial(const ofShader & shader,ofGLProgrammableRenderer if( isClearCoatEnabled() ) { shader.setUniform2f("mat_clearcoat", data.clearCoatStrength, data.clearCoatRoughness ); } - + if( hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) { shader.setUniform1f("mat_displacement_strength", data.displacementStrength ); shader.setUniform1f("mat_displacement_normals_strength", data.displacementNormalsStrength ); @@ -1076,7 +1010,7 @@ void ofMaterial::updateMaterial(const ofShader & shader,ofGLProgrammableRenderer if( hasTexture(OF_MATERIAL_TEXTURE_NORMAL) || hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) { shader.setUniform1f("mat_normal_mix", data.normalGeomToNormalMapMix ); } - + auto cubeMapData = ofCubeMap::getActiveData(); if( cubeMapData ) { shader.setUniform1f("mat_ibl_exposure", cubeMapData->exposure ); @@ -1087,7 +1021,7 @@ void ofMaterial::updateMaterial(const ofShader & shader,ofGLProgrammableRenderer shader.setUniform1f("uCubeMapEnabled", 0.0f ); shader.setUniform1f("uEnvMapMaxMips", 1.0f ); } - + } else { shader.setUniform4fv("mat_ambient", &data.ambient.r); shader.setUniform4fv("mat_diffuse", &data.diffuse.r); @@ -1208,7 +1142,7 @@ void ofMaterial::updateLights(const ofShader & shader,ofGLProgrammableRenderer & direction = direction - glm::vec3(lightEyePosition); shader.setUniform3f("lights["+idx+"].spotDirection", glm::normalize(direction)); } - + auto right = light->right; auto up = light->up; if( !isPBR() ) { @@ -1300,7 +1234,7 @@ void ofMaterial::setCustomUniformTexture(const std::string & name, const ofTextu //-------------------------------------------------------- void ofMaterial::setCustomUniformTexture(const std::string & name, int textureTarget, GLint textureID){ - + int textureLocation = -1; // if the texture uniform name is not registered, then try to find a new location // if( uniformstex.count(name) < 1 ) { @@ -1330,7 +1264,7 @@ void ofMaterial::setCustomUniformTexture(const std::string & name, int textureTa } else { textureLocation = uniformstex[name].textureLocation; } - + if( textureLocation > -1 ) { setCustomUniformTexture(name, textureTarget, textureID, textureLocation); } @@ -1397,7 +1331,7 @@ void ofMaterial::addShaderDefine( const std::string & aDefineName ) { //-------------------------------------------------------- void ofMaterial::addShaderDefine( const std::string & aDefineName, const std::string & aDefineValue ) { if( aDefineName.empty() ) return; - + bool bUpdateDefines = false; if( mDefines.count(aDefineName) < 1 ) { bUpdateDefines = true; @@ -1416,16 +1350,16 @@ void ofMaterial::addShaderDefine( const std::string & aDefineName, const std::st //-------------------------------------------------------- bool ofMaterial::removeShaderDefine( const std::string & aDefineName ) { if( aDefineName.empty() ) return false; - + if(mDefines.count(aDefineName) > 0 ) { mDefines.erase(aDefineName); - + // update the unique id using uniqueIdString string // data.uniqueIdString = ""; for( auto& def : mDefines ) { data.uniqueIdString += def.first; } - + return true; } return false; @@ -1437,7 +1371,7 @@ const std::string ofMaterial::getDefinesString() const { for( auto& diter : mDefines ) { definesString += "#define "+diter.first+" "+diter.second+"\n"; } - + if( isPBR() ) { #ifdef TARGET_OPENGLES definesString += "#define PBR_QUALITY_LEVEL_LOW 1 \n"; @@ -1445,12 +1379,12 @@ const std::string ofMaterial::getDefinesString() const { definesString += "#define PBR_QUALITY_LEVEL_HIGH 1\n"; #endif } - + if(isPBR() && ofCubeMap::getCubeMapsData().size() > 0 && ofIsGLProgrammableRenderer() ) { // const auto& cubeMapData = ofCubeMap::getActiveData(); - + definesString += "#define HAS_CUBE_MAP 1\n"; - + bool bHasIrradiance = false; bool bPreFilteredMap = false; bool bBrdfLutTex = false; @@ -1467,7 +1401,7 @@ const std::string ofMaterial::getDefinesString() const { bBrdfLutTex=true; } } - + if(bHasIrradiance) { definesString += "#define HAS_TEX_ENV_IRRADIANCE 1\n"; } @@ -1479,9 +1413,9 @@ const std::string ofMaterial::getDefinesString() const { } // need to add .0 to be read as a float in the shader for gl es //definesString += "#define ENV_MAP_MAX_MIPS "+ofToString(ofCubeMap::getNumMipMaps(),0)+".0\n"; - + } - + definesString += ofShadow::getShaderDefinesAsString(); return definesString; } @@ -1506,7 +1440,7 @@ namespace{ string shaderHeader(string header, int maxLights, bool hasTexture, bool hasColor){ // header += "#define MAX_LIGHTS " + ofToString(std::max(1,maxLights)) + "\n"; header += "#define MAX_LIGHTS " + ofToString(maxLights) + "\n"; - + if(hasTexture){ header += "#define HAS_TEXTURE 1\n"; } else { @@ -1517,7 +1451,7 @@ namespace{ } else { header += "#define HAS_COLOR 0\n"; } - + return header; } @@ -1544,7 +1478,7 @@ namespace{ string fragmentSource(bool bPBR, string defaultHeader, string customUniforms, const ofMaterialSettings& adata, int maxLights, bool hasTexture, bool hasColor, string definesString){ // string fragmentSource(bool bPBR, string defaultHeader, string customUniforms, string postFragment, int maxLights, bool hasTexture, bool hasColor, string definesString){ auto source = bPBR ? shader_pbr_frag : fragmentShader; - + string postFragment = adata.postFragment; if(postFragment.empty()){ postFragment = "vec4 postFragment(vec4 localColor){ return localColor; }"; @@ -1561,7 +1495,7 @@ namespace{ } ofStringReplace(source, "%mainFragment%", mainFrag); } - + if(bPBR) { string addIncludes = shader_utils; addIncludes += shader_pbr_material; @@ -1572,22 +1506,19 @@ namespace{ // set PBR includes here ofStringReplace(source, "%additional_includes%", addIncludes); } - - - if( ofIsGLProgrammableRenderer() ) { - #if defined(TARGET_OPENGLES) - #if defined(TARGET_EMSCRIPTEN) - ofStringReplace(source, "%shader_shadow_include%", shadow_shader_include ); - #else - ofStringReplace(source, "%shader_shadow_include%", "" ); - #endif + + + if (ofIsGLProgrammableRenderer()) { + // Shadows require programmable renderer + GLES 3.0+ (or desktop) + #if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + ofStringReplace(source, "%shader_shadow_include%", shadow_shader_include); #else - ofStringReplace(source, "%shader_shadow_include%", shadow_shader_include ); + ofStringReplace(source, "%shader_shadow_include%", ""); #endif } else { - ofStringReplace(source, "%shader_shadow_include%", "" ); + ofStringReplace(source, "%shader_shadow_include%", ""); } - + source = shaderHeader(defaultHeader, maxLights, hasTexture, hasColor) + definesString + source; return source; } @@ -1596,14 +1527,14 @@ namespace{ // auto source = bPBR ? shader_pbr_vert : vertexShader; string header = "#define IN in\n"; auto source = shader_pbr_vert; - + string mainVertex = adata.mainDepthVertex; if( mainVertex.empty() ) { mainVertex = shader_pbr_main_depth_vert; } ofStringReplace(source, "%mainVertex%", mainVertex); ofStringReplace(source, "%additional_includes%", ""); - + // if( bPBR ) { // ofStringReplace(source, "%additional_includes%", addShaderSrc); // } else { diff --git a/libs/openFrameworks/gl/ofShader.cpp b/libs/openFrameworks/gl/ofShader.cpp index 9fc24210f4d..23bfd406f00 100644 --- a/libs/openFrameworks/gl/ofShader.cpp +++ b/libs/openFrameworks/gl/ofShader.cpp @@ -83,7 +83,7 @@ static void releaseProgram(GLuint id) { } } -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) //-------------------------------------------------------------- ofShader::TransformFeedbackRangeBinding::TransformFeedbackRangeBinding(const ofBufferObject & buffer, GLuint offset, GLuint size) : offset(offset) @@ -213,7 +213,7 @@ bool ofShader::load(const of::filesystem::path & vertName, const of::filesystem: return linkProgram(); } -#if !defined(TARGET_OPENGLES) && defined(glDispatchCompute) +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_1) && defined(TARGET_OPENGLES_3) && defined(glDispatchCompute)) //-------------------------------------------------------------- bool ofShader::loadCompute(const of::filesystem::path & shaderName) { return setupShaderFromFile(GL_COMPUTE_SHADER, shaderName) && linkProgram(); @@ -251,7 +251,7 @@ bool ofShader::setup(const ofShaderSettings & settings) { return linkProgram(); } -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) //-------------------------------------------------------------- bool ofShader::setup(const TransformFeedbackSettings & settings) { for (auto shader : settings.shaderFiles) { @@ -851,7 +851,7 @@ void ofShader::end() const { ofGetGLRenderer()->unbind(*this); } -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) //-------------------------------------------------------------- void ofShader::beginTransformFeedback(GLenum mode) const { begin(); @@ -923,7 +923,7 @@ void ofShader::endTransformFeedback(const std::vector shaderFiles; std::unordered_map shaderSources; @@ -119,7 +119,7 @@ class ofShader { #endif bool setup(const ofShaderSettings & settings); -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) bool setup(const TransformFeedbackSettings & settings); #endif @@ -138,7 +138,8 @@ class ofShader { void begin() const; void end() const; -#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN) + +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) void beginTransformFeedback(GLenum mode) const; void beginTransformFeedback(GLenum mode, const TransformFeedbackRangeBinding & binding) const; void beginTransformFeedback(GLenum mode, const std::vector & binding) const; @@ -151,7 +152,7 @@ class ofShader { void endTransformFeedback(const std::vector & binding) const; #endif -#if !defined(TARGET_OPENGLES) && defined(glDispatchCompute) +#if !defined(TARGET_OPENGLES) || (defined(TARGET_OPENGLES_3) && defined(glDispatchCompute) && defined(GL_ES_VERSION_3_1)) void dispatchCompute(GLuint x, GLuint y, GLuint z) const; #endif @@ -200,11 +201,11 @@ class ofShader { // set attributes that vary per vertex (look up the location before glBegin) GLint getAttributeLocation(const std::string & name) const; -#ifndef TARGET_OPENGLES +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) #ifdef GLEW_ARB_uniform_buffer_object GLint getUniformBlockIndex(const std::string & name) const; GLint getUniformBlockBinding(const std::string & name) const; - void bindUniformBlock(GLuint bindind, const std::string & name) const; + void bindUniformBlock(GLuint binding, const std::string & name) const; void printActiveUniformBlocks() const; #endif #endif diff --git a/libs/openFrameworks/gl/ofShadow.cpp b/libs/openFrameworks/gl/ofShadow.cpp index 6b1445804fb..54a6aecb526 100644 --- a/libs/openFrameworks/gl/ofShadow.cpp +++ b/libs/openFrameworks/gl/ofShadow.cpp @@ -341,14 +341,11 @@ std::string ofShadow::getShaderDefinesAsString() { //-------------------------------------------------------------- bool ofShadow::areShadowsSupported() { - #if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN) - return false; + #if defined(TARGET_OPENGLES) && !(defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + return false; // GLES 2.0 does not support shadows #endif - - if(!ofIsGLProgrammableRenderer() ) { - return false; - } - return true; + + return ofIsGLProgrammableRenderer(); } //-------------------------------------------------------------- @@ -987,15 +984,12 @@ void ofShadow::_allocateFbo() { GLenum gl_read_status = GL_FRAMEBUFFER_UNSUPPORTED; GLenum textureTarget = getTextureTarget(data->lightType); -#if !defined(TARGET_OPENGLES) - int depthComponent = GL_DEPTH_COMPONENT32F; - int glType = GL_FLOAT; -#elif defined(TARGET_EMSCRIPTEN) - int depthComponent = GL_DEPTH_COMPONENT24; - int glType = GL_UNSIGNED_INT; +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + GLenum depthComponent = GL_DEPTH_COMPONENT32F; + GLenum glType = GL_FLOAT; #else - int depthComponent = GL_DEPTH_COMPONENT; - int glType = GL_UNSIGNED_SHORT; + GLenum depthComponent = GL_DEPTH_COMPONENT; + GLenum glType = GL_UNSIGNED_SHORT; #endif glBindTexture(textureTarget, getDepthMapTexId() ); diff --git a/libs/openFrameworks/gl/ofTexture.cpp b/libs/openFrameworks/gl/ofTexture.cpp index 0c526bb7ab3..f878e86e01a 100644 --- a/libs/openFrameworks/gl/ofTexture.cpp +++ b/libs/openFrameworks/gl/ofTexture.cpp @@ -722,12 +722,16 @@ void ofTexture::generateMipmap(){ switch (texData.textureTarget) { /// OpenGL ES only supports mipmap for the following two texture targets: case GL_TEXTURE_2D: +#if defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_2_0) && defined(TARGET_OPENGLES_2)) case GL_TEXTURE_CUBE_MAP: +#endif #ifndef TARGET_OPENGLES /// OpenGL supports mipmaps for additional texture targets: case GL_TEXTURE_1D: - case GL_TEXTURE_3D: case GL_TEXTURE_1D_ARRAY: +#endif +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) + case GL_TEXTURE_3D: case GL_TEXTURE_2D_ARRAY: #endif { @@ -839,7 +843,7 @@ void ofTexture::unbind(int textureLocation) const{ ofGetGLRenderer()->unbind(*this,textureLocation); } -#if !defined(TARGET_OPENGLES) && defined(glBindImageTexture) +#if (!defined(TARGET_OPENGLES) && defined(glBindImageTexture)) || defined(GL_ES_VERSION_3_1) //---------------------------------------------------------- void ofTexture::bindAsImage(GLuint unit, GLenum access, GLint level, GLboolean layered, GLint layer){ glBindImageTexture(unit,texData.textureID,level,layered,layer,access,texData.glInternalFormat); diff --git a/libs/openFrameworks/gl/ofTexture.h b/libs/openFrameworks/gl/ofTexture.h index e0ec974ce7e..d9f10cd2978 100644 --- a/libs/openFrameworks/gl/ofTexture.h +++ b/libs/openFrameworks/gl/ofTexture.h @@ -555,6 +555,7 @@ class ofTexture : public ofBaseDraws { /// \param glFormat GL pixel type: GL_RGBA, GL_LUMINANCE, etc. void loadData(const ofFloatPixels & pix, int glFormat); + /// \brief Load byte pixel data. /// /// glFormat can be different to the internal format of the texture on each @@ -567,8 +568,8 @@ class ofTexture : public ofBaseDraws { /// \param glFormat GL pixel type: GL_RGBA, GL_LUMINANCE, etc. /// \param glType the OpenGL type of the data. void loadData(const void * data, int w, int h, int glFormat, int glType); - -#ifndef TARGET_OPENGLES + +#if !defined(TARGET_OPENGLES) || (defined(GL_ES_VERSION_3_0) && defined(TARGET_OPENGLES_3)) /// \brief Load pixels from an ofBufferObject /// /// This is different to allocate(ofBufferObject,internal). That @@ -725,7 +726,10 @@ class ofTexture : public ofBaseDraws { /// void unbind(int textureLocation=0) const; -#if !defined(TARGET_OPENGLES) && defined(glBindImageTexture) +#if !defined(TARGET_OPENGLES) || defined(GL_ES_VERSION_3_1) +// TODO: check for availability of glBindImageTexture in a valid way +// defined(glBindImageTexture) does not actually work! +// there is no reliable way to check for a function being defined just with the preprocessor /// Calls glBindImageTexture on the texture /// /// Binds the texture as an read or write image, only available since OpenGL 4.2 @@ -952,7 +956,7 @@ class ofTexture : public ofBaseDraws { /// \sa generateMipmap() /// \sa enableMipmap() bool hasMipmap() const; - + /// \internal ofTextureData texData; ///< Internal texture data access. ///< For backwards compatibility. diff --git a/libs/openFrameworks/gl/ofVbo.cpp b/libs/openFrameworks/gl/ofVbo.cpp index b9743c13505..2f0b21d2ccb 100644 --- a/libs/openFrameworks/gl/ofVbo.cpp +++ b/libs/openFrameworks/gl/ofVbo.cpp @@ -837,110 +837,121 @@ const ofBufferObject & ofVbo::getIndexBuffer() const{ } //-------------------------------------------------------------- -void ofVbo::bind() const{ +void ofVbo::bind() const { bool programmable = ofIsGLProgrammableRenderer(); - if(programmable && (vaoSupported || !vaoChecked)){ - if(vaoID==0){ - #if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN) - if(glGenVertexArrays==0 && !vaoChecked){ + + // VAO handling + if (programmable && (vaoSupported || !vaoChecked)) { + if (vaoID == 0) { +#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN) + // Pure GLES 2.0 — try to load VAO extension via dlsym + if (glGenVertexArrays == 0 && !vaoChecked) { glGenVertexArrays = (glGenVertexArraysType)dlsym(RTLD_DEFAULT, "glGenVertexArrays"); glDeleteVertexArrays = (glDeleteVertexArraysType)dlsym(RTLD_DEFAULT, "glDeleteVertexArrays"); glBindVertexArray = (glBindVertexArrayType)dlsym(RTLD_DEFAULT, "glBindVertexArray"); vaoChecked = true; - vaoSupported = glGenVertexArrays; + vaoSupported = glGenVertexArrays != nullptr; } - #elif defined(TARGET_EMSCRIPTEN) - vaoChecked = true; +#elif defined(TARGET_EMSCRIPTEN) + // Emscripten (WebGL2) does not reliably support VAOs in this context + vaoChecked = true; + vaoSupported = false; +#else + // Desktop + GLES 3.0+ — VAOs are core + vaoChecked = true; + vaoSupported = true; +#endif + + if (vaoSupported && glGenVertexArrays != nullptr) { + glGenVertexArrays(1, &const_cast(this)->vaoID); + } else if (vaoSupported && glGenVertexArrays == nullptr) { vaoSupported = false; - #else - vaoChecked = true; - vaoSupported = true; - #endif - if(vaoSupported) glGenVertexArrays(1, &const_cast(this)->vaoID); - if(vaoID!=0){ + } + + if (vaoID != 0) { retainVAO(vaoID); vaoChanged = true; } } - if(vaoSupported) glBindVertexArray(vaoID); - }else{ + + if (vaoSupported && glBindVertexArray != nullptr) { + glBindVertexArray(vaoID); + } + } else { vaoSupported = false; } - if(vaoChanged || !vaoSupported){ - if(bUsingVerts){ - if(!programmable){ - positionAttribute.bind(); - #ifndef TARGET_PROGRAMMABLE_GL + // attribute setup + if (vaoChanged || !vaoSupported) { + if (bUsingVerts) { + positionAttribute.bind(); + if (programmable) { + positionAttribute.enable(); + } else { +#ifndef TARGET_PROGRAMMABLE_GL glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(positionAttribute.numCoords, GL_FLOAT, - positionAttribute.stride, - (void*)positionAttribute.offset); - #endif - }else{ - positionAttribute.enable(); + positionAttribute.stride, (void*)positionAttribute.offset); +#endif } - }else if(programmable){ + } else if (programmable) { positionAttribute.disable(); } - if(bUsingColors) { - if(!programmable){ - colorAttribute.bind(); - #ifndef TARGET_PROGRAMMABLE_GL + if (bUsingColors) { + colorAttribute.bind(); + if (programmable) { + colorAttribute.enable(); + } else { +#ifndef TARGET_PROGRAMMABLE_GL glEnableClientState(GL_COLOR_ARRAY); glColorPointer(colorAttribute.numCoords, GL_FLOAT, - colorAttribute.stride, - (void*)colorAttribute.offset); - #endif - }else{ - colorAttribute.enable(); + colorAttribute.stride, (void*)colorAttribute.offset); +#endif } - }else if(programmable){ + } else if (programmable) { colorAttribute.disable(); } - if(bUsingNormals) { - if(!programmable){ - normalAttribute.bind(); - #ifndef TARGET_PROGRAMMABLE_GL + if (bUsingNormals) { + normalAttribute.bind(); + if (programmable) { + normalAttribute.enable(); + } else { +#ifndef TARGET_PROGRAMMABLE_GL glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, normalAttribute.stride, (void*)normalAttribute.offset); - #endif - }else{ - normalAttribute.enable(); +#endif } - }else if(programmable){ + } else if (programmable) { normalAttribute.disable(); } - if(bUsingTexCoords) { - if(!programmable){ - texCoordAttribute.bind(); - #ifndef TARGET_PROGRAMMABLE_GL - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(texCoordAttribute.numCoords, - GL_FLOAT, texCoordAttribute.stride, - (void*)texCoordAttribute.offset); - #endif - }else{ + if (bUsingTexCoords) { + texCoordAttribute.bind(); + if (programmable) { texCoordAttribute.enable(); + } else { +#ifndef TARGET_PROGRAMMABLE_GL + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(texCoordAttribute.numCoords, GL_FLOAT, + texCoordAttribute.stride, (void*)texCoordAttribute.offset); +#endif } - }else if(programmable){ + } else if (programmable) { texCoordAttribute.disable(); } - if (bUsingIndices) { - indexAttribute.bind(); - } + if (bUsingIndices) { + indexAttribute.bind(); + } - unordered_map::const_iterator it; - for(it = customAttributes.begin();it!=customAttributes.end();it++){ - it->second.enable(); + for (auto& it : customAttributes) { + it.second.enable(); } - vaoChanged=false; + vaoChanged = false; } } diff --git a/libs/openFrameworks/graphics/ofGraphics.cpp b/libs/openFrameworks/graphics/ofGraphics.cpp index b7e45922cd5..3bdfbbbdbd9 100644 --- a/libs/openFrameworks/graphics/ofGraphics.cpp +++ b/libs/openFrameworks/graphics/ofGraphics.cpp @@ -412,12 +412,14 @@ void ofBackgroundGradient(const ofFloatColor& start, const ofFloatColor& end, of float w = ofGetViewportWidth(), h = ofGetViewportHeight(); gradientMesh.clear(); gradientMesh.setMode(OF_PRIMITIVE_TRIANGLE_FAN); -#ifndef TARGET_EMSCRIPTEN - #ifdef TARGET_OPENGLES - if (ofIsGLProgrammableRenderer()) gradientMesh.setUsage(GL_STREAM_DRAW); - #else - gradientMesh.setUsage(GL_STREAM_DRAW); - #endif +#ifdef GL_STREAM_DRAW + #ifdef TARGET_OPENGLES + if(ofIsGLProgrammableRenderer()) { + gradientMesh.setUsage(GL_STREAM_DRAW); + } + #else + gradientMesh.setUsage(GL_STREAM_DRAW); + #endif #endif if (mode == OF_GRADIENT_CIRCULAR) { // this could be optimized by building a single mesh once, then copying diff --git a/libs/openFrameworks/utils/ofConstants.h b/libs/openFrameworks/utils/ofConstants.h index 83d903aaf9d..b9745071d2d 100644 --- a/libs/openFrameworks/utils/ofConstants.h +++ b/libs/openFrameworks/utils/ofConstants.h @@ -230,6 +230,12 @@ enum ofTargetPlatform{ #include #include + #if defined(GL_ES_VERSION_3_0) + #include + #endif + #if defined(GL_ES_VERSION_3_1) + #include "GLES3/gl31.h" + #endif #include #include @@ -280,13 +286,21 @@ enum ofTargetPlatform{ #ifdef TARGET_ANDROID #include + #include #include - #define GL_GLEXT_PROTOTYPES + #define GL_GLEXT_PROTOTYPES #include - + #if __ANDROID_API__ >= 21 + #if defined(GL_ES_VERSION_3_0) + #include "GLES3/gl3.h" + #include "GLES3/gl31.h" // only works on Android-21+ + #include "GLES3/gl3ext.h" + #endif + #endif + #ifndef __gl3_h_ #include #include - + #endif #define TARGET_LITTLE_ENDIAN #endif @@ -294,14 +308,17 @@ enum ofTargetPlatform{ #define GL_GLEXT_PROTOTYPES #include #include + #if defined(GL_ES_VERSION_3_0) + #include + #endif + #if defined(GL_ES_VERSION_3_1) + #include "GLES3/gl31.h" + #endif #include #include - #include #include - #include "EGL/egl.h" #include "EGL/eglext.h" - #define TARGET_LITTLE_ENDIAN #endif @@ -322,6 +339,28 @@ typedef TESSindex ofIndexType; #include // intrinsics SIMD on https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics?view=msvc-170 #endif +#ifdef TARGET_OPENGLES + #if !defined(TARGET_OPENGLES_3) + #if defined(GL_ES_VERSION_3_0) || \ + (defined(TARGET_EMSCRIPTEN) && defined(USE_WEBGL2)) || \ + defined(TARGET_OPENGLES_3_1) || defined(TARGET_OPENGLES_3_2) + #define TARGET_OPENGLES_3 + #if defined(GL_ES_VERSION_3_1) + #define TARGET_OPENGLES_3_1 + #endif + #if defined(GL_ES_VERSION_3_2) + #define TARGET_OPENGLES_3_2 + #endif + #endif + #endif + // User can force-disable GLES3 + #if defined(TARGET_FORCE_GLES_2) || defined(TARGET_FORCE_GLES_1) + #undef TARGET_OPENGLES_3 + #undef TARGET_OPENGLES_3_1 + #undef TARGET_OPENGLES_3_2 + #endif +#endif + //------------------------------------------------ soundplayer //MAC_OS and IOS uncomment to enable AVEnginePlayer #ifdef OF_NO_FMOD