bool ofImage_<PixelType>::load(const string& fileName){ #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture); ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update); #endif bool bLoadedOk = ofLoadImage(pixels, fileName); if (!bLoadedOk) { ofLogError("ofImage") << "loadImage(): couldn't load image from \"" << fileName << "\""; clear(); return false; } update(); return bLoadedOk; }
bool ofImage_<PixelType>::load(const ofBuffer & buffer, const ofImageLoadSettings &settings){ #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture); ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update); #endif bool bLoadedOk = ofLoadImage(pixels, buffer, settings); if (!bLoadedOk) { ofLogError("ofImage") << "loadImage(): couldn't load image from ofBuffer"; clear(); return false; } update(); return bLoadedOk; }
void ofImage_<PixelType>::clear(){ #if defined(TARGET_ANDROID) ofRemoveListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture); ofRemoveListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update); #endif pixels.clear(); if(bUseTexture) tex.clear(); width = 0; height = 0; bpp = 0; type = OF_IMAGE_UNDEFINED; bUseTexture = true; // the default is, yes, use a texture }
//-------------------------------------------------------------- void ofFbo::clear() { if(fbo){ releaseFB(fbo); fbo=0; } if(depthBuffer){ releaseRB(depthBuffer); depthBuffer = 0; } if(depthBufferTex.isAllocated()){ depthBufferTex.clear(); } if(stencilBuffer){ releaseRB(stencilBuffer); stencilBuffer = 0; } if(settings.numSamples && fboTextures){ releaseFB(fboTextures); fboTextures = 0; } textures.clear(); for (int i=0; i < (int)colorBuffers.size(); i++) { releaseRB(colorBuffers[i]); } colorBuffers.clear(); activeDrawBuffers.clear(); bIsAllocated = false; #ifdef TARGET_ANDROID ofRemoveListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo); #endif }
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; }
//-------------------------------------------------------------- ofFbo::ofFbo(const ofFbo & mom){ settings = mom.settings; bIsAllocated = mom.bIsAllocated; fbo = mom.fbo; retainFB(fbo); fboTextures = mom.fboTextures; if(settings.numSamples){ retainFB(fboTextures); } if(mom.settings.depthStencilAsTexture){ depthBufferTex = mom.depthBufferTex; }else{ depthBuffer = mom.depthBuffer; retainRB(depthBuffer); } stencilBuffer = mom.stencilBuffer; retainRB(stencilBuffer); colorBuffers = mom.colorBuffers; for(int i=0;i<(int)colorBuffers.size();i++){ retainRB(colorBuffers[i]); } 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 } }
void ofMainLoop::exit(){ for(auto i: windowsApps){ shared_ptr<ofAppBaseWindow> window = i.first; shared_ptr<ofBaseApp> app = i.second; if(window == nullptr) { continue; } if(app == nullptr) { continue; } ofRemoveListener(window->events().setup,app.get(),&ofBaseApp::setup,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().update,app.get(),&ofBaseApp::update,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().draw,app.get(),&ofBaseApp::draw,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().exit,app.get(),&ofBaseApp::exit,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().keyPressed,app.get(),&ofBaseApp::keyPressed,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().keyReleased,app.get(),&ofBaseApp::keyReleased,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().mouseMoved,app.get(),&ofBaseApp::mouseMoved,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().mouseDragged,app.get(),&ofBaseApp::mouseDragged,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().mousePressed,app.get(),&ofBaseApp::mousePressed,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().mouseReleased,app.get(),&ofBaseApp::mouseReleased,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().mouseScrolled,app.get(),&ofBaseApp::mouseScrolled,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().mouseEntered,app.get(),&ofBaseApp::mouseEntered,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().mouseExited,app.get(),&ofBaseApp::mouseExited,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().windowResized,app.get(),&ofBaseApp::windowResized,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().messageEvent,app.get(),&ofBaseApp::messageReceived,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().fileDragEvent,app.get(),&ofBaseApp::dragged,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().touchCancelled,app.get(),&ofBaseApp::touchCancelled,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().touchDoubleTap,app.get(),&ofBaseApp::touchDoubleTap,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().touchDown,app.get(),&ofBaseApp::touchDown,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().touchMoved,app.get(),&ofBaseApp::touchMoved,OF_EVENT_ORDER_APP); ofRemoveListener(window->events().touchUp,app.get(),&ofBaseApp::touchUp,OF_EVENT_ORDER_APP); #ifdef TARGET_ANDROID auto androidApp = dynamic_cast<ofxAndroidApp*>(app.get()); if(androidApp){ ofRemoveListener(ofxAndroidEvents().okPressed,androidApp,&ofxAndroidApp::okPressed,OF_EVENT_ORDER_APP); ofRemoveListener(ofxAndroidEvents().cancelPressed,androidApp,&ofxAndroidApp::cancelPressed,OF_EVENT_ORDER_APP); ofRemoveListener(ofxAndroidEvents().backPressed,androidApp,&ofxAndroidApp::backPressed,OF_EVENT_ORDER_APP); ofRemoveListener(ofxAndroidEvents().networkConnected,androidApp,&ofxAndroidApp::networkConnectedEvent,OF_EVENT_ORDER_APP); ofRemoveListener(ofxAndroidEvents().pause,androidApp,&ofxAndroidApp::pause,OF_EVENT_ORDER_APP); ofRemoveListener(ofxAndroidEvents().resume,androidApp,&ofxAndroidApp::resume,OF_EVENT_ORDER_APP); ofRemoveListener(ofxAndroidEvents().unloadGL,androidApp,&ofxAndroidApp::unloadGL,OF_EVENT_ORDER_APP); ofRemoveListener(ofxAndroidEvents().reloadGL,androidApp,&ofxAndroidApp::reloadGL,OF_EVENT_ORDER_APP); ofRemoveListener(ofxAndroidEvents().swipe,androidApp,&ofxAndroidApp::swipe,OF_EVENT_ORDER_APP); } #endif } exitEvent.notify(this); windowsApps.clear(); }
ofImage_<PixelType>::ofImage_(ofImage_<PixelType>&& mom){ pixels = std::move(mom.pixels); tex = std::move(mom.tex); bUseTexture = mom.bUseTexture; width = mom.width; height = mom.height; bpp = mom.bpp; type = mom.type; mom.clear(); //clear remaining flags and sizes from the mom #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture); ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update); #endif }
void ofImage_<PixelType>::allocate(int w, int h, ofImageType newType){ if (width == w && height == h && newType == type){ return; } #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture); ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update); #endif pixels.allocate(w, h, newType); // take care of texture allocation -- if (pixels.isAllocated() && bUseTexture){ tex.allocate(pixels); } width = pixels.getWidth(); height = pixels.getHeight(); bpp = pixels.getBitsPerPixel(); type = pixels.getImageType(); }
void ofMainLoop::run(shared_ptr<ofAppBaseWindow> window, shared_ptr<ofBaseApp> app){ windowsApps[window] = app; if(app){ ofAddListener(window->events().setup,app.get(),&ofBaseApp::setup,OF_EVENT_ORDER_APP); ofAddListener(window->events().update,app.get(),&ofBaseApp::update,OF_EVENT_ORDER_APP); ofAddListener(window->events().draw,app.get(),&ofBaseApp::draw,OF_EVENT_ORDER_APP); ofAddListener(window->events().exit,app.get(),&ofBaseApp::exit,OF_EVENT_ORDER_APP); ofAddListener(window->events().keyPressed,app.get(),&ofBaseApp::keyPressed,OF_EVENT_ORDER_APP); ofAddListener(window->events().keyReleased,app.get(),&ofBaseApp::keyReleased,OF_EVENT_ORDER_APP); ofAddListener(window->events().mouseMoved,app.get(),&ofBaseApp::mouseMoved,OF_EVENT_ORDER_APP); ofAddListener(window->events().mouseDragged,app.get(),&ofBaseApp::mouseDragged,OF_EVENT_ORDER_APP); ofAddListener(window->events().mousePressed,app.get(),&ofBaseApp::mousePressed,OF_EVENT_ORDER_APP); ofAddListener(window->events().mouseReleased,app.get(),&ofBaseApp::mouseReleased,OF_EVENT_ORDER_APP); ofAddListener(window->events().mouseScrolled,app.get(),&ofBaseApp::mouseScrolled,OF_EVENT_ORDER_APP); ofAddListener(window->events().mouseEntered,app.get(),&ofBaseApp::mouseEntered,OF_EVENT_ORDER_APP); ofAddListener(window->events().mouseExited,app.get(),&ofBaseApp::mouseExited,OF_EVENT_ORDER_APP); ofAddListener(window->events().windowResized,app.get(),&ofBaseApp::windowResized,OF_EVENT_ORDER_APP); ofAddListener(window->events().messageEvent,app.get(),&ofBaseApp::messageReceived,OF_EVENT_ORDER_APP); ofAddListener(window->events().fileDragEvent,app.get(),&ofBaseApp::dragged,OF_EVENT_ORDER_APP); ofAddListener(window->events().touchCancelled,app.get(),&ofBaseApp::touchCancelled,OF_EVENT_ORDER_APP); ofAddListener(window->events().touchDoubleTap,app.get(),&ofBaseApp::touchDoubleTap,OF_EVENT_ORDER_APP); ofAddListener(window->events().touchDown,app.get(),&ofBaseApp::touchDown,OF_EVENT_ORDER_APP); ofAddListener(window->events().touchMoved,app.get(),&ofBaseApp::touchMoved,OF_EVENT_ORDER_APP); ofAddListener(window->events().touchUp,app.get(),&ofBaseApp::touchUp,OF_EVENT_ORDER_APP); #ifdef TARGET_ANDROID auto androidApp = dynamic_cast<ofxAndroidApp*>(app.get()); if(androidApp){ ofAddListener(ofxAndroidEvents().okPressed,androidApp,&ofxAndroidApp::okPressed,OF_EVENT_ORDER_APP); ofAddListener(ofxAndroidEvents().cancelPressed,androidApp,&ofxAndroidApp::cancelPressed,OF_EVENT_ORDER_APP); ofAddListener(ofxAndroidEvents().backPressed,androidApp,&ofxAndroidApp::backPressed,OF_EVENT_ORDER_APP); ofAddListener(ofxAndroidEvents().networkConnected,androidApp,&ofxAndroidApp::networkConnectedEvent,OF_EVENT_ORDER_APP); ofAddListener(ofxAndroidEvents().pause,androidApp,&ofxAndroidApp::pause,OF_EVENT_ORDER_APP); ofAddListener(ofxAndroidEvents().resume,androidApp,&ofxAndroidApp::resume,OF_EVENT_ORDER_APP); ofAddListener(ofxAndroidEvents().unloadGL,androidApp,&ofxAndroidApp::unloadGL,OF_EVENT_ORDER_APP); ofAddListener(ofxAndroidEvents().reloadGL,androidApp,&ofxAndroidApp::reloadGL,OF_EVENT_ORDER_APP); ofAddListener(ofxAndroidEvents().swipe,androidApp,&ofxAndroidApp::swipe,OF_EVENT_ORDER_APP); } #endif } currentWindow = window; window->makeCurrent(); if(!windowLoop){ window->events().notifySetup(); } }
//-------------------------------------------------------------- void ofApp::setup(){ ofSetFrameRate(60); ofSetVerticalSync(true); ofEnableSmoothing(); ofSetWindowTitle("Orbital Tracker"); ofEnableLighting(); ofSetFullscreen(true); Tweenzor::init(); //earth sphere rot = 0; scaler = 300 / ofx::Geo::GeoUtils::EARTH_RADIUS_KM; if(colorMap.load("images/color_map_1024.jpg")) ofLogVerbose() << "earth image loaded!"; else ofLogError() << "failed to load earth image!"; earthSphere.set(ofx::Geo::GeoUtils::EARTH_RADIUS_KM, 36); ofQuaternion quat; quat.makeRotate(180, 0, 1, 0); earthSphere.rotate(quat); earthSphere.mapTexCoords(0, colorMap.getTexture().getTextureData().tex_u, colorMap.getTexture().getTextureData().tex_t, 0); //background sphere if(backgroundMap.load("images/starbackground.png")) ofLogVerbose() << "background image loaded!"; else ofLogError() << "failed to load background image!"; backgroundSphere.set(ofx::Geo::GeoUtils::EARTH_RADIUS_KM*30, 36); backgroundSphere.mapTexCoords(0, backgroundMap.getTexture().getTextureData().tex_u, backgroundMap.getTexture().getTextureData().tex_t, 0); //cam and 3d settings cam.setRotationSensitivity(0.3,0.3,0.3); cam.setTranslationSensitivity(0.2,0.2,0.2); cam.setPosition(0, 0, 0); cam.setFarClip(100000); ofSetDrawBitmapMode(OF_BITMAPMODE_MODEL_BILLBOARD); //initialize manager Manager.setup(); //zoom #ifdef TARGET_ANDROID ofAddListener(ofxAndroidEvents().scaleBegin ,this,&ofApp::scale); #endif previousDistance = 0; zoomDistance = 1000; //sun sun.setup(); sun.setSpotlight(40, 5); sunTimer = ofGetElapsedTimeMillis()+500; //UI interface.setup(&Manager); }
void ofImage_<PixelType>::allocate(int w, int h, ofImageType newType){ if (width == w && height == h && newType == type){ return; } #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture); ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update); #endif pixels.allocate(w, h, newType); // take care of texture allocation -- if (pixels.isAllocated() && bUseTexture){ tex.allocate(pixels.getWidth(), pixels.getHeight(), ofGetGlInternalFormat(pixels)); if(ofIsGLProgrammableRenderer() && (pixels.getPixelFormat()==OF_PIXELS_GRAY || pixels.getPixelFormat()==OF_PIXELS_GRAY_ALPHA)){ tex.setRGToRGBASwizzles(true); } } width = pixels.getWidth(); height = pixels.getHeight(); bpp = pixels.getBitsPerPixel(); type = pixels.getImageType(); }
ofFbo::ofFbo(ofFbo && mom) :settings(std::move(mom.settings)) ,fbo(mom.fbo) ,fboTextures(mom.fboTextures) ,depthBuffer(mom.depthBuffer) ,stencilBuffer(mom.stencilBuffer) ,colorBuffers(std::move(mom.colorBuffers)) ,textures(std::move(mom.textures)) ,depthBufferTex(std::move(mom.depthBufferTex)) ,activeDrawBuffers(std::move(mom.activeDrawBuffers)) ,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; }
//------------------------------------------------------------------ ofTrueTypeFont::~ofTrueTypeFont(){ #if defined(TARGET_ANDROID) ofRemoveListener(ofxAndroidEvents().unloadGL,this,&ofTrueTypeFont::unloadTextures); ofRemoveListener(ofxAndroidEvents().reloadGL,this,&ofTrueTypeFont::reloadTextures); #endif }
//-------------------------------------------------------------- void ofFbo::allocate(Settings _settings) { if(!checkGLSupport()) return; clear(); auto renderer = _settings.renderer.lock(); if(renderer){ settings.renderer = renderer; }else{ settings.renderer = ofGetGLRenderer(); } // check that passed values are correct if(_settings.width <= 0 || _settings.height <= 0){ ofLogError("ofFbo") << "width and height have to be more than 0"; } if(_settings.numSamples > maxSamples() && maxSamples() > -1) { ofLogWarning("ofFbo") << "allocate(): clamping numSamples " << _settings.numSamples << " to maxSamples " << maxSamples() << " for frame buffer object" << fbo; _settings.numSamples = maxSamples(); } if(_settings.depthStencilAsTexture && _settings.numSamples){ ofLogWarning("ofFbo") << "allocate(): multisampling not supported with depthStencilAsTexture, setting 0 samples for frame buffer object " << fbo; _settings.numSamples = 0; } //currently depth only works if stencil is enabled. // http://forum.openframeworks.cc/index.php/topic,6837.0.html #ifdef TARGET_OPENGLES if(_settings.useDepth){ _settings.useStencil = true; } if( _settings.depthStencilAsTexture ){ _settings.depthStencilAsTexture = false; ofLogWarning("ofFbo") << "allocate(): depthStencilAsTexture is not available for iOS"; } #endif GLenum depthAttachment = GL_DEPTH_ATTACHMENT; if( _settings.useDepth && _settings.useStencil ){ _settings.depthStencilInternalFormat = GL_DEPTH_STENCIL; #ifdef TARGET_OPENGLES depthAttachment = GL_DEPTH_ATTACHMENT; #else depthAttachment = GL_DEPTH_STENCIL_ATTACHMENT; #endif }else if(_settings.useDepth){ depthAttachment = GL_DEPTH_ATTACHMENT; }else if(_settings.useStencil){ depthAttachment = GL_STENCIL_ATTACHMENT; _settings.depthStencilInternalFormat = GL_STENCIL_INDEX; } // set needed values for allocation on instance settings // the rest will be set by the corresponding methods during allocation settings.width = _settings.width; settings.height = _settings.height; settings.numSamples = _settings.numSamples; // create main fbo // this is the main one we bind for drawing into // all the renderbuffers are attached to this (whether MSAA is enabled or not) glGenFramebuffers(1, &fbo); retainFB(fbo); GLint previousFboId = 0; // note that we are using a glGetInteger method here, which may stall the pipeline. // in the allocate() method, this is not that tragic since this will not be called // within the draw() loop. Here, we need not optimise for performance, but for // simplicity and readability . glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previousFboId); glBindFramebuffer(GL_FRAMEBUFFER, fbo); //- USE REGULAR RENDER BUFFER if(!_settings.depthStencilAsTexture){ if(_settings.useDepth && _settings.useStencil){ stencilBuffer = depthBuffer = createAndAttachRenderbuffer(_settings.depthStencilInternalFormat, depthAttachment); retainRB(stencilBuffer); retainRB(depthBuffer); }else if(_settings.useDepth){ depthBuffer = createAndAttachRenderbuffer(_settings.depthStencilInternalFormat, depthAttachment); retainRB(depthBuffer); }else if(_settings.useStencil){ stencilBuffer = createAndAttachRenderbuffer(_settings.depthStencilInternalFormat, depthAttachment); retainRB(stencilBuffer); } //- INSTEAD USE TEXTURE }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); } #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; // if we want MSAA, create a new fbo for textures #ifndef TARGET_OPENGLES if(_settings.numSamples){ glGenFramebuffers(1, &fboTextures); retainFB(fboTextures); }else{ fboTextures = fbo; } #else fboTextures = fbo; if(_settings.numSamples){ ofLogWarning("ofFbo") << "allocate(): multisampling not supported in OpenGL ES"; } #endif // now create all textures and color buffers if(_settings.colorFormats.size() > 0) { for(int i=0; i<(int)_settings.colorFormats.size(); i++) createAndAttachTexture(_settings.colorFormats[i], i); } else if(_settings.numColorbuffers > 0) { for(int i=0; i<_settings.numColorbuffers; i++) createAndAttachTexture(_settings.internalformat, i); _settings.colorFormats = settings.colorFormats; } else { ofLogWarning("ofFbo") << "allocate(): no color buffers specified for frame buffer object " << fbo; } settings.internalformat = _settings.internalformat; dirty.resize(_settings.colorFormats.size(), true); // we start with all color buffers dirty. // if textures are attached to a different fbo (e.g. if using MSAA) check it's status if(fbo != fboTextures) { glBindFramebuffer(GL_FRAMEBUFFER, fboTextures); } // check everything is ok with this fbo bIsAllocated = checkStatus(); // restore previous framebuffer id glBindFramebuffer(GL_FRAMEBUFFER, previousFboId); /* UNCOMMENT OUTSIDE OF DOING RELEASES // 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 }
ofBitmapFont::~ofBitmapFont(){ #ifdef TARGET_ANDROID ofRemoveListener(ofxAndroidEvents().unloadGL,this,&ofBitmapFont::unloadTexture); #endif }
bool ofTrueTypeFont::load(const ofTtfSettings & _settings){ #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofTrueTypeFont::unloadTextures); ofAddListener(ofxAndroidEvents().reloadGL,this,&ofTrueTypeFont::reloadTextures); #endif initLibraries(); settings = _settings; if( settings.dpi == 0 ){ settings.dpi = ttfGlobalDpi; } bLoadedOk = false; //--------------- load the library and typeface FT_Face loadFace; if(!loadFontFace(settings.fontName,settings.fontSize,loadFace,settings.fontName)){ return false; } face = std::shared_ptr<struct FT_FaceRec_>(loadFace,FT_Done_Face); if(settings.ranges.empty()){ settings.ranges.push_back(ofUnicode::Latin1Supplement); } int border = 1; FT_Set_Char_Size( face.get(), settings.fontSize << 6, settings.fontSize << 6, settings.dpi, settings.dpi); fontUnitScale = (float(settings.fontSize * settings.dpi)) / (72 * face->units_per_EM); lineHeight = face->height * fontUnitScale; ascenderHeight = face->ascender * fontUnitScale; descenderHeight = face->descender * fontUnitScale; glyphBBox.set(face->bbox.xMin * fontUnitScale, face->bbox.yMin * fontUnitScale, (face->bbox.xMax - face->bbox.xMin) * fontUnitScale, (face->bbox.yMax - face->bbox.yMin) * fontUnitScale); //--------------- initialize character info and textures auto nGlyphs = std::accumulate(settings.ranges.begin(), settings.ranges.end(), 0u, [](uint32_t acc, ofUnicode::range range){ return acc + range.getNumGlyphs(); }); cps.resize(nGlyphs); if(settings.contours){ charOutlines.resize(nGlyphs); charOutlinesNonVFlipped.resize(nGlyphs); charOutlinesContour.resize(nGlyphs); charOutlinesNonVFlippedContour.resize(nGlyphs); }else{ charOutlines.resize(1); } vector<ofTrueTypeFont::glyph> all_glyphs; uint32_t areaSum=0; //--------------------- load each char ----------------------- auto i = 0u; for(auto & range: settings.ranges){ for (uint32_t g = range.begin; g <= range.end; g++, i++){ all_glyphs.push_back(loadGlyph(g)); all_glyphs[i].props.characterIndex = i; glyphIndexMap[g] = i; cps[i] = all_glyphs[i].props; areaSum += (cps[i].tW+border*2)*(cps[i].tH+border*2); if(settings.contours){ if(printVectorInfo){ std::string str; ofAppendUTF8(str,g); ofLogNotice("ofTrueTypeFont") << "character " << str; } //int character = i + NUM_CHARACTER_TO_START; charOutlines[i] = makeContoursForCharacter( face.get() ); charOutlinesContour[i] = charOutlines[i]; charOutlinesContour[i].setFilled(false); charOutlinesContour[i].setStrokeWidth(1); charOutlinesNonVFlipped[i] = charOutlines[i]; charOutlinesNonVFlipped[i].translate(ofVec3f(0,cps[i].height)); charOutlinesNonVFlipped[i].scale(1,-1); charOutlinesNonVFlippedContour[i] = charOutlines[i]; charOutlinesNonVFlippedContour[i].setFilled(false); charOutlinesNonVFlippedContour[i].setStrokeWidth(1); if(settings.simplifyAmt>0){ charOutlines[i].simplify(settings.simplifyAmt); charOutlinesNonVFlipped[i].simplify(settings.simplifyAmt); charOutlinesContour[i].simplify(settings.simplifyAmt); charOutlinesNonVFlippedContour[i].simplify(settings.simplifyAmt); } } } } vector<ofTrueTypeFont::glyphProps> sortedCopy = cps; sort(sortedCopy.begin(),sortedCopy.end(),[](const ofTrueTypeFont::glyphProps & c1, const ofTrueTypeFont::glyphProps & c2){ if(c1.tH == c2.tH) return c1.tW > c2.tW; else return c1.tH > c2.tH; }); // pack in a texture, algorithm to calculate min w/h from // http://upcommons.upc.edu/pfc/bitstream/2099.1/7720/1/TesiMasterJonas.pdf //ofLogNotice("ofTrueTypeFont") << "loadFont(): areaSum: " << areaSum bool packed = false; float alpha = logf(areaSum)*1.44269f; int w; int h; while(!packed){ w = pow(2,floor((alpha/2.f) + 0.5f)); // there doesn't seem to be a round in cmath for windows. //w = pow(2,round(alpha/2.f)); h = w;//pow(2,round(alpha - round(alpha/2.f))); int x=0; int y=0; auto maxRowHeight = sortedCopy[0].tH + border*2; packed = true; for(auto & glyph: sortedCopy){ if(x+glyph.tW + border*2>w){ x = 0; y += maxRowHeight; maxRowHeight = glyph.tH + border*2; if(y + maxRowHeight > h){ alpha++; packed = false; break; } } x+= glyph.tW + border*2; } } ofPixels atlasPixelsLuminanceAlpha; atlasPixelsLuminanceAlpha.allocate(w,h,OF_PIXELS_GRAY_ALPHA); atlasPixelsLuminanceAlpha.set(0,255); atlasPixelsLuminanceAlpha.set(1,0); int x=0; int y=0; auto maxRowHeight = sortedCopy[0].tH + border*2; for(auto & glyph: sortedCopy){ ofPixels & charPixels = all_glyphs[glyph.characterIndex].pixels; if(x+glyph.tW + border*2>w){ x = 0; y += maxRowHeight; maxRowHeight = glyph.tH + border*2; } cps[glyph.characterIndex].t1 = float(x + border)/float(w); cps[glyph.characterIndex].v1 = float(y + border)/float(h); cps[glyph.characterIndex].t2 = float(cps[glyph.characterIndex].tW + x + border)/float(w); cps[glyph.characterIndex].v2 = float(cps[glyph.characterIndex].tH + y + border)/float(h); charPixels.pasteInto(atlasPixelsLuminanceAlpha,x+border,y+border); x+= glyph.tW + border*2; } texAtlas.allocate(atlasPixelsLuminanceAlpha,false); texAtlas.setRGToRGBASwizzles(true); if(settings.antialiased && settings.fontSize>20){ texAtlas.setTextureMinMagFilter(GL_LINEAR,GL_LINEAR); }else{ texAtlas.setTextureMinMagFilter(GL_NEAREST,GL_NEAREST); } texAtlas.loadData(atlasPixelsLuminanceAlpha); bLoadedOk = true; return true; }
void Java_cc_openframeworks_OFAndroid_networkConnected( JNIEnv* env, jobject thiz, jboolean connected){ bool bConnected = (bool)connected; if(androidApp) androidApp->networkConnected(bConnected); ofNotifyEvent(ofxAndroidEvents().networkConnected,bConnected); }
//----------------------------------------------------------- bool ofTrueTypeFont::load(string _filename, int _fontSize, bool _bAntiAliased, bool _bFullCharacterSet, bool _makeContours, float _simplifyAmt, int _dpi) { #if defined(TARGET_ANDROID) ofAddListener(ofxAndroidEvents().unloadGL,this,&ofTrueTypeFont::unloadTextures); ofAddListener(ofxAndroidEvents().reloadGL,this,&ofTrueTypeFont::reloadTextures); #endif int border = 1; initLibraries(); // if we've already been loaded, try to clean up : unloadTextures(); if( _dpi == 0 ){ _dpi = ttfGlobalDpi; } bLoadedOk = false; bAntiAliased = _bAntiAliased; bFullCharacterSet = _bFullCharacterSet; fontSize = _fontSize; bMakeContours = _makeContours; simplifyAmt = _simplifyAmt; dpi = _dpi; //--------------- load the library and typeface if(!loadFontFace(_filename,_fontSize,face,filename)){ return false; } FT_Set_Char_Size( face, fontSize << 6, fontSize << 6, dpi, dpi); float fontUnitScale = ((float)fontSize * dpi) / (72 * face->units_per_EM); lineHeight = face->height * fontUnitScale; ascenderHeight = face->ascender * fontUnitScale; descenderHeight = face->descender * fontUnitScale; glyphBBox.set(face->bbox.xMin * fontUnitScale, face->bbox.yMin * fontUnitScale, (face->bbox.xMax - face->bbox.xMin) * fontUnitScale, (face->bbox.yMax - face->bbox.yMin) * fontUnitScale); //------------------------------------------------------ //kerning would be great to support: //ofLogNotice("ofTrueTypeFont") << "FT_HAS_KERNING ? " << FT_HAS_KERNING(face); //------------------------------------------------------ nCharacters = (bFullCharacterSet ? 256 : 128) - NUM_CHARACTER_TO_START; //--------------- initialize character info and textures cps.resize(nCharacters); if(bMakeContours){ charOutlines.assign(nCharacters, ofTTFCharacter()); charOutlinesNonVFlipped.assign(nCharacters, ofTTFCharacter()); charOutlinesContour.assign(nCharacters, ofTTFCharacter()); charOutlinesNonVFlippedContour.assign(nCharacters, ofTTFCharacter()); }else{ charOutlines.resize(1); } vector<ofPixels> expanded_data(nCharacters); long areaSum=0; FT_Error err; //--------------------- load each char ----------------------- for (int i = 0 ; i < nCharacters; i++){ //------------------------------------------ anti aliased or not: int glyph = (unsigned char)(i+NUM_CHARACTER_TO_START); if (glyph == 0xA4) glyph = 0x20AC; // hack to load the euro sign, all codes in 8859-15 match with utf-32 except for this one err = FT_Load_Glyph( face, FT_Get_Char_Index( face, glyph ), bAntiAliased ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT ); if(err){ ofLogError("ofTrueTypeFont") << "loadFont(): FT_Load_Glyph failed for char " << i << ": FT_Error " << err; } if (bAntiAliased == true) FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); else FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); //------------------------------------------ if(bMakeContours){ if(printVectorInfo){ ofLogNotice("ofTrueTypeFont") << "character " << char(i+NUM_CHARACTER_TO_START); } //int character = i + NUM_CHARACTER_TO_START; charOutlines[i] = makeContoursForCharacter( face ); charOutlinesContour[i] = charOutlines[i]; charOutlinesContour[i].setFilled(false); charOutlinesContour[i].setStrokeWidth(1); charOutlinesNonVFlipped[i] = charOutlines[i]; charOutlinesNonVFlipped[i].translate(ofVec3f(0,cps[i].height)); charOutlinesNonVFlipped[i].scale(1,-1); charOutlinesNonVFlippedContour[i] = charOutlines[i]; charOutlinesNonVFlippedContour[i].setFilled(false); charOutlinesNonVFlippedContour[i].setStrokeWidth(1); if(simplifyAmt>0){ charOutlines[i].simplify(simplifyAmt); charOutlinesNonVFlipped[i].simplify(simplifyAmt); charOutlinesContour[i].simplify(simplifyAmt); charOutlinesNonVFlippedContour[i].simplify(simplifyAmt); } } // ------------------------- // info about the character: FT_Bitmap& bitmap= face->glyph->bitmap; int width = bitmap.width; int height = bitmap.rows; cps[i].characterIndex = i; cps[i].glyph = glyph; cps[i].height = face->glyph->metrics.height>>6; cps[i].width = face->glyph->metrics.width>>6; cps[i].bearingX = face->glyph->metrics.horiBearingX>>6; cps[i].bearingY = face->glyph->metrics.horiBearingY>>6; cps[i].xmin = face->glyph->bitmap_left; cps[i].xmax = cps[i].xmin + cps[i].width; cps[i].ymin = -face->glyph->bitmap_top; cps[i].ymax = cps[i].ymin + cps[i].height; cps[i].advance = face->glyph->metrics.horiAdvance>>6; cps[i].tW = cps[i].width; cps[i].tH = cps[i].height; areaSum += (cps[i].tW+border*2)*(cps[i].tH+border*2); if(width==0 || height==0) continue; // Allocate Memory For The Texture Data. expanded_data[i].allocate(width, height, OF_PIXELS_GRAY_ALPHA); //-------------------------------- clear data: expanded_data[i].set(0,255); // every luminance pixel = 255 expanded_data[i].set(1,0); if (bAntiAliased == true){ ofPixels bitmapPixels; bitmapPixels.setFromExternalPixels(bitmap.buffer,bitmap.width,bitmap.rows,OF_PIXELS_GRAY); expanded_data[i].setChannel(1,bitmapPixels); } else { //----------------------------------- // true type packs monochrome info in a // 1-bit format, hella funky // here we unpack it: unsigned char *src = bitmap.buffer; for(unsigned int j=0; j <bitmap.rows;j++) { unsigned char b=0; unsigned char *bptr = src; for(unsigned int k=0; k < bitmap.width ; k++){ expanded_data[i][2*(k+j*width)] = 255; if (k%8==0){ b = (*bptr++); } expanded_data[i][2*(k+j*width) + 1] = b&0x80 ? 255 : 0; b <<= 1; } src += bitmap.pitch; } //----------------------------------- } } vector<charProps> sortedCopy = cps; sort(sortedCopy.begin(),sortedCopy.end(),&compare_cps); // pack in a texture, algorithm to calculate min w/h from // http://upcommons.upc.edu/pfc/bitstream/2099.1/7720/1/TesiMasterJonas.pdf //ofLogNotice("ofTrueTypeFont") << "loadFont(): areaSum: " << areaSum bool packed = false; float alpha = logf(areaSum)*1.44269; int w; int h; while(!packed){ w = pow(2,floor((alpha/2.f) + 0.5)); // there doesn't seem to be a round in cmath for windows. //w = pow(2,round(alpha/2.f)); h = w;//pow(2,round(alpha - round(alpha/2.f))); int x=0; int y=0; int maxRowHeight = sortedCopy[0].tH + border*2; for(int i=0;i<(int)cps.size();i++){ if(x+sortedCopy[i].tW + border*2>w){ x = 0; y += maxRowHeight; maxRowHeight = sortedCopy[i].tH + border*2; if(y + maxRowHeight > h){ alpha++; break; } } x+= sortedCopy[i].tW + border*2; if(i==(int)cps.size()-1) packed = true; } } ofPixels atlasPixelsLuminanceAlpha; atlasPixelsLuminanceAlpha.allocate(w,h,OF_PIXELS_GRAY_ALPHA); atlasPixelsLuminanceAlpha.set(0,255); atlasPixelsLuminanceAlpha.set(1,0); int x=0; int y=0; int maxRowHeight = sortedCopy[0].tH + border*2; for(int i=0;i<(int)cps.size();i++){ ofPixels & charPixels = expanded_data[sortedCopy[i].characterIndex]; if(x+sortedCopy[i].tW + border*2>w){ x = 0; y += maxRowHeight; maxRowHeight = sortedCopy[i].tH + border*2; } cps[sortedCopy[i].characterIndex].t1 = float(x + border)/float(w); cps[sortedCopy[i].characterIndex].v1 = float(y + border)/float(h); cps[sortedCopy[i].characterIndex].t2 = float(cps[sortedCopy[i].characterIndex].tW + x + border)/float(w); cps[sortedCopy[i].characterIndex].v2 = float(cps[sortedCopy[i].characterIndex].tH + y + border)/float(h); charPixels.pasteInto(atlasPixelsLuminanceAlpha,x+border,y+border); x+= sortedCopy[i].tW + border*2; } texAtlas.allocate(atlasPixelsLuminanceAlpha,false); texAtlas.setRGToRGBASwizzles(true); if(bAntiAliased && fontSize>20){ texAtlas.setTextureMinMagFilter(GL_LINEAR,GL_LINEAR); }else{ texAtlas.setTextureMinMagFilter(GL_NEAREST,GL_NEAREST); } texAtlas.loadData(atlasPixelsLuminanceAlpha); // ------------- close the library and typeface bLoadedOk = true; return true; }
void Java_cc_openframeworks_OFAndroid_cancelPressed( JNIEnv* env, jobject thiz ){ if(androidApp) androidApp->cancelPressed(); bool yes = true; ofNotifyEvent(ofxAndroidEvents().cancelPressed,yes); }