framework2
1354 строки · 40.4 Кб
1//
2// ofCubeMap.cpp
3//
4// Created by Nick Hardeman on 10/16/22.
5//
6
7#include "ofShader.h"8#include "ofCubeMap.h"9#include "ofImage.h"10#include "of3dUtils.h"11#include "ofGLBaseTypes.h"12#include "ofGLUtils.h"13#include "ofGLProgrammableRenderer.h"14#include "ofCubeMapShaders.h"15#include "ofFbo.h"16#include "ofConstants.h"17
18#define GLM_FORCE_CTOR_INIT19#include "glm/gtx/transform.hpp"20#include "glm/gtc/quaternion.hpp"21#include <map>22
23#ifdef TARGET_ANDROID24#include "ofAppAndroidWindow.h"25#endif26
27using std::weak_ptr;28using std::vector;29using std::shared_ptr;30
31ofVboMesh ofCubeMap::sCubeMesh;32ofShader ofCubeMap::shaderBrdfLUT;33ofTexture ofCubeMap::sBrdfLutTex;34
35void ofCubeMap::setExposure(float aExposure) {36data->exposure=ofClamp(aExposure, 0.0f, 1.0f);37}
38
39// texture management copied from ofTexture
40static std::map<GLuint,int> & getTexturesIndex(){41static std::map<GLuint,int> * textureReferences = new std::map<GLuint,int>;42return *textureReferences;43}
44
45static void retain(GLuint id){46if(id!=0){47if(getTexturesIndex().find(id)!=getTexturesIndex().end()){48getTexturesIndex()[id]++;49}else{50getTexturesIndex()[id]=1;51}52}53}
54
55static void release(GLuint id){56// try to free up the texture memory so we don't reallocate57// http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/deletetextures.html58if (id != 0){59if(getTexturesIndex().find(id)!=getTexturesIndex().end()){60getTexturesIndex()[id]--;61if(getTexturesIndex()[id]==0){62
63#ifdef TARGET_ANDROID64if (!ofAppAndroidWindow::isSurfaceDestroyed())65#endif66glDeleteTextures(1, (GLuint *)&id);67
68getTexturesIndex().erase(id);69}70}else{71ofLogError("ofCubeMap") << "release(): something's wrong here, releasing unknown texture id " << id;72
73#ifdef TARGET_ANDROID74if (!ofAppAndroidWindow::isSurfaceDestroyed())75#endif76glDeleteTextures(1, (GLuint *)&id);77}78}79}
80
81//----------------------------------------
82#ifdef TARGET_ANDROID83// TODO: Hook this up to an event
84void ofCubeMap::regenerateAllTextures() {85for(size_t i=0; i<ofCubeMapsData().size(); i++) {86if(!ofCubeMapsData()[i].expired()) {87std::shared_ptr<ofCubeMap::Data> cubeMap = ofCubeMapsData()[i].lock();88ofCubeMap::clearTextureData(cubeMap);89}90}91sBrdfLutTex.clear();92}
93#endif94
95
96
97//----------------------------------------
98vector<weak_ptr<ofCubeMap::Data> > & ofCubeMapsData(){99static vector<weak_ptr<ofCubeMap::Data> > * cubeMapsActive = new vector<weak_ptr<ofCubeMap::Data> >;100return *cubeMapsActive;101}
102
103//--------------------------------------------------------------
104bool ofCubeMap::hasActiveCubeMap() {105for(size_t i=0;i< ofCubeMapsData().size();i++){106std::shared_ptr<ofCubeMap::Data> cubeMap = ofCubeMapsData()[i].lock();107if(cubeMap && cubeMap->isEnabled && cubeMap->index > -1 ){108return true;109break;110}111}112return false;113}
114
115//--------------------------------------------------------------
116std::shared_ptr<ofCubeMap::Data> ofCubeMap::getActiveData() {117for(size_t i=0;i< ofCubeMapsData().size();i++){118std::shared_ptr<ofCubeMap::Data> cubeMap = ofCubeMapsData()[i].lock();119if(cubeMap && cubeMap->isEnabled && cubeMap->index > -1 ){120return cubeMap;121}122}123return std::shared_ptr<ofCubeMap::Data>();124}
125
126//--------------------------------------------------------------
127void ofCubeMap::clearTextureData(std::shared_ptr<ofCubeMap::Data> adata) {128if( adata ) {129if( adata->bPreFilteredMapAllocated ) {130adata->bPreFilteredMapAllocated=false;131release(adata->preFilteredMapId);132}133
134if( adata->bIrradianceAllocated ) {135adata->bIrradianceAllocated = false;136release(adata->irradianceMapId);137}138if( adata->bCubeMapAllocated ) {139adata->bCubeMapAllocated = false;140release(adata->cubeMapId);141}142}143}
144
145//--------------------------------------------------------------
146void ofCubeMap::_checkSetup() {147if( data->index < 0 ) {148bool bFound = false;149// search for the first free block150for(size_t i=0; i<ofCubeMapsData().size(); i++) {151if(ofCubeMapsData()[i].expired()) {152data->index = i;153ofCubeMapsData()[i] = data;154bFound = true;155break;156}157}158if(!bFound && ofIsGLProgrammableRenderer()){159ofCubeMapsData().push_back(data);160data->index = ofCubeMapsData().size() - 1;161bFound = true;162}163}164// we should remove empty slots //165}
166
167//----------------------------------------
168const ofTexture& ofCubeMap::getBrdfLutTexture() {169return sBrdfLutTex;170}
171
172//----------------------------------------
173ofCubeMap::ofCubeMap() {174data = std::make_shared<ofCubeMap::Data>();175_checkSetup();176projectionMat = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f );177}
178
179//----------------------------------------
180ofCubeMap::ofCubeMap(const ofCubeMap & mom) {181clear();182
183if(data) {184data.reset();185}186if( mom.data ) {187data = std::make_shared<ofCubeMap::Data>(*mom.data);188if( data->bCubeMapAllocated ) {189retain(data->cubeMapId);190}191if( data->bIrradianceAllocated ) {192retain(data->irradianceMapId);193}194if( data->bPreFilteredMapAllocated ) {195retain(data->preFilteredMapId);196}197}198if( !data ) {199data = std::make_shared<ofCubeMap::Data>();200}201data->index = -1;202if( mom.data ) {203data->settings = mom.data->settings;204}205_checkSetup(); // grab a new slot in ofCubeMapsData206texFormat = mom.texFormat;207}
208
209//----------------------------------------
210ofCubeMap::ofCubeMap(ofCubeMap && mom) {211clear();212// taking ownership of the data shared_ptr213data = mom.data;214texFormat = mom.texFormat;215}
216
217//----------------------------------------
218ofCubeMap::~ofCubeMap() {219clear();220}
221
222//--------------------------------------------------------------
223ofCubeMap & ofCubeMap::operator=(const ofCubeMap & mom){224if(&mom==this) return *this;225clear();226
227if(data) {228data.reset();229}230if( mom.data ) {231data = std::make_shared<ofCubeMap::Data>(*mom.data);232if( data->bCubeMapAllocated ) {233retain(data->cubeMapId);234}235if( data->bIrradianceAllocated ) {236retain(data->irradianceMapId);237}238if( data->bPreFilteredMapAllocated ) {239retain(data->preFilteredMapId);240}241}242if( !data ) {243data = std::make_shared<ofCubeMap::Data>();244}245if( mom.data ) {246data->settings = mom.data->settings;247}248data->index = -1;249_checkSetup(); // grab a new slot in ofCubeMapsData250texFormat = mom.texFormat;251
252return *this;253}
254
255//--------------------------------------------------------------
256ofCubeMap& ofCubeMap::operator=(ofCubeMap && mom) {257clear();258data = mom.data;259texFormat = mom.texFormat;260return *this;261}
262
263//----------------------------------------
264GLenum ofCubeMap::getTextureTarget() {265return GL_TEXTURE_CUBE_MAP;266}
267
268//----------------------------------------
269bool isPowerOfTwo(int x) {270/* First x in the below expression is for the case when271* x is 0 */
272return x && (!(x & (x - 1)));273}
274
275//----------------------------------------
276bool ofCubeMap::load( const of::filesystem::path & apath, int aFaceResolution, bool aBFlipY ) {277return load(apath, aFaceResolution, aBFlipY, 32, 128 );278}
279
280//----------------------------------------
281bool ofCubeMap::load( const of::filesystem::path & apath, int aFaceResolution, bool aBFlipY, int aIrradianceRes, int aPreFilterRes ) {282
283ofCubeMapSettings settings;284settings.flipVertically = aBFlipY;285settings.filePath = apath;286
287settings.resolution = aFaceResolution;288settings.irradianceRes = aIrradianceRes;289settings.preFilterRes = aPreFilterRes;290
291return load(settings);292}
293
294//----------------------------------------
295bool ofCubeMap::load( ofCubeMapSettings aSettings ) {296if( !ofIsGLProgrammableRenderer() ) {297ofLogError("ofCubeMap::load") << " cube maps only supported with programmable renderer.";298return false;299}300// if( aSettings.resolution > 512 ) {
301// ofLogWarning("ofCubeMap :: load : a face resolution larger than 512 can cause issues.");
302// }
303
304if( aSettings.filePath.empty() ) {305ofLogError("ofCubeMap :: load : must set file path");306return false;307}308
309clear();310
311std::string ext = ofToLower(aSettings.filePath.extension().string());312bool hdr = (ext == ".hdr" || ext == ".exr");313
314#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN)315if( hdr ) {316ofLogError("ofCubeMap :: load : hdr and exr not supported on OPENGL_ES");317return false;318}319#endif320
321bool bLoadOk = false;322data->settings = aSettings;323
324ofTexture srcTex;325
326bool bArbTexEnabled = ofGetUsingArbTex();327ofDisableArbTex();328if( hdr ) {329ofFloatPixels fpix;330if( ofLoadImage(fpix, data->settings.filePath) ) {331ofLogNotice("ofCubeMap::load : loaded ") << ext << " image.";332bLoadOk = true;333#if defined(TARGET_EMSCRIPTEN)334// GL_RGB32F GL_RGB16F && is not supported in Emscripten opengl es, so we need to set to GL_RGBA16F or GL_RGBA32F335// ofFloatPixels uses 32F and is supported via Emscripten, so we switch to that in the _load functions.336texFormat = GL_RGBA16F;337// just in case, we need to make sure that it's 4 channels338if( fpix.getNumChannels() != 4 ) {339fpix.setImageType( OF_IMAGE_COLOR_ALPHA );340}341#elif !defined(TARGET_OPENGLES)342if( fpix.getNumChannels() != 3 ) {343fpix.setImageType( OF_IMAGE_COLOR );344}345texFormat = GL_RGB32F;346#endif347srcTex.loadData(fpix);348}349} else {350ofPixels ipix;351if( ofLoadImage(ipix, data->settings.filePath) ) {352bLoadOk = true;353texFormat = GL_RGB;354srcTex.loadData(ipix);355}356}357if( !bLoadOk ) {358ofLogWarning("ofCubeMap :: failed to load image from ") << data->settings.filePath;359} else {360srcTex.setTextureWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);361srcTex.setTextureMinMagFilter(GL_LINEAR, GL_LINEAR);362#if !defined(TARGET_OPENGLES) && defined(GL_TEXTURE_CUBE_MAP_SEAMLESS)363glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);364#endif365
366if( !isPowerOfTwo(data->settings.resolution) ) {367ofLogNotice("ofCubeMap :: load : changing resolution " ) << data->settings.resolution << " to next power of 2: " << ofNextPow2(data->settings.resolution);368data->settings.resolution = ofNextPow2(data->settings.resolution);369}370if( !isPowerOfTwo(data->settings.irradianceRes) ) {371ofLogNotice("ofCubeMap :: load : changing resolution " ) << data->settings.irradianceRes << " to next power of 2: " << ofNextPow2(data->settings.irradianceRes);372data->settings.irradianceRes = ofNextPow2(data->settings.irradianceRes);373}374if( !isPowerOfTwo(data->settings.preFilterRes) ) {375ofLogNotice("ofCubeMap :: load : changing resolution " ) << data->settings.preFilterRes << " to next power of 2: " << ofNextPow2(data->settings.preFilterRes);376data->settings.preFilterRes = ofNextPow2(data->settings.preFilterRes);377}378
379_createCubeMap(srcTex);380if( isHdr() ) {381
382int srcCubeFSize = std::max(256, data->settings.preFilterRes);383GLuint cubeFid = _createFloatCubeMap(srcTex, srcCubeFSize );384
385// figure out the number of mip maps //386data->maxMipLevels = log2(data->settings.preFilterRes) + 1;387
388auto encFolder = data->settings.cacheDirectory;389if( !encFolder.empty() ) {390if( !ofDirectory::doesDirectoryExist( data->settings.cacheDirectory )) {391#if !defined(TARGET_OPENGLES)392if(!ofDirectory::createDirectory( data->settings.cacheDirectory )) {393ofLogWarning("ofCubeMap :: load : unable to create directory: ") << data->settings.cacheDirectory;394}395#endif396} else {397
398}399encFolder = data->settings.cacheDirectory;400}401of::filesystem::path baseName = data->settings.filePath.stem(); // equivalent to getBaseName402of::filesystem::path cacheIrrName { baseName };403cacheIrrName += ("_irr_"+ofToString(data->settings.irradianceRes,0)+".exr");404of::filesystem::path cachePrefilterName { baseName };405cachePrefilterName += ("_pre_"+ofToString(data->settings.preFilterRes,0)+".exr");406
407bool bHasCachedIrr = false;408bool bHasCachedPre = false;409if( data->settings.useCache && !data->settings.overwriteCache ) {410bHasCachedIrr = _loadIrradianceMap(encFolder / cacheIrrName);411ofLogVerbose("ofCubeMap :: _loadIrradianceMap: ") << bHasCachedIrr;412bHasCachedPre = _loadPrefilterMap(encFolder / cachePrefilterName);413ofLogVerbose("ofCubeMap :: _loadPrefilterMap: ") << bHasCachedPre;414}415
416bool bMakeCache = data->settings.useCache;417#if defined(TARGET_EMSCRIPTEN)418// not supporting making caches on Emscripten.419bMakeCache = false;420#endif421
422if( !bHasCachedIrr ) {423ofLogVerbose("ofCubeMap :: going to create irradiance map");424_createIrradianceMap(cubeFid,bMakeCache, encFolder / cacheIrrName);425}426
427if( !bHasCachedPre ) {428ofLogVerbose("ofCubeMap :: going to create pre filtered cube map");429_createPrefilteredCubeMap(cubeFid, srcCubeFSize,bMakeCache,encFolder / cachePrefilterName );430}431
432glDeleteTextures(1, &cubeFid );433}434}435
436if( bArbTexEnabled ) {437ofEnableArbTex();438}439
440return bLoadOk;441}
442
443
444//----------------------------------------
445void ofCubeMap::clear() {446clearTextureData(data);447}
448
449//--------------------------------------------------------------
450void ofCubeMap::draw() {451drawCubeMap();452}
453
454//--------------------------------------------------------------
455void ofCubeMap::drawCubeMap() {456if( !data->bCubeMapAllocated ) {457ofLogWarning("ofCubeMap::drawCubeMap() : textures not allocated, not drawing");458return;459}460
461_drawCubeStart(data->cubeMapId);462shaderRender.setUniform1f("uExposure", getExposure() );463shaderRender.setUniform1f("uRoughness", 0.0f );464shaderRender.setUniform1f("uMaxMips", 1.0f );465shaderRender.setUniform1f("uIsHDR", 0.0f );466_drawCubeEnd();467}
468
469//--------------------------------------------------------------
470void ofCubeMap::drawIrradiance() {471if( !data->bIrradianceAllocated ) {472ofLogWarning("ofCubeMap::drawIrradiance() : textures not allocated, not drawing");473return;474}475
476_drawCubeStart(data->irradianceMapId);477shaderRender.setUniform1f("uExposure", getExposure() );478shaderRender.setUniform1f("uRoughness", 0.0f );479shaderRender.setUniform1f("uMaxMips", 1.0f );480shaderRender.setUniform1f("uIsHDR", 1.0f );481_drawCubeEnd();482}
483
484//--------------------------------------------------------------
485void ofCubeMap::drawPrefilteredCube(float aRoughness) {486if( !data->bPreFilteredMapAllocated ) {487ofLogWarning("ofCubeMap::drawPrefilteredCube() : textures not allocated, not drawing");488return;489}490
491_drawCubeStart(data->preFilteredMapId);492shaderRender.setUniform1f("uIsHDR", 1.0f );493shaderRender.setUniform1f("uExposure", getExposure() );494shaderRender.setUniform1f("uRoughness", aRoughness );495shaderRender.setUniform1f("uMaxMips", (float)data->maxMipLevels );496_drawCubeEnd();497}
498
499//--------------------------------------------------------------
500void ofCubeMap::_drawCubeStart(GLuint aCubeMapId) {501_allocateCubeMesh();502
503if( !shaderRender.isLoaded() ) {504_loadRenderShader();505}506if( shaderRender.isLoaded() ) {507glDepthFunc(GL_LEQUAL);508shaderRender.begin();509shaderRender.setUniformTexture("uCubeMap", getTextureTarget(), aCubeMapId, 0 ); }510}
511
512//--------------------------------------------------------------
513void ofCubeMap::_drawCubeEnd() {514sCubeMesh.draw();515shaderRender.end();516glDepthFunc(GL_LESS); // set depth function back to default517}
518
519//--------------------------------------------------------------
520bool ofCubeMap::hasCubeMap() {521if( !data ) return false;522return data->bCubeMapAllocated;523}
524
525//--------------------------------------------------------------
526bool ofCubeMap::hasPrefilteredMap() {527if( !data ) return false;528return data->bPreFilteredMapAllocated;529}
530
531//--------------------------------------------------------------
532bool ofCubeMap::hasIrradianceMap() {533if( !data ) return false;534return data->bIrradianceAllocated;535}
536
537//--------------------------------------------------------------
538GLuint ofCubeMap::getTextureId() {539if( !data ) return 0;540return data->cubeMapId;541}
542
543//--------------------------------------------------------------
544bool ofCubeMap::isHdr() {545#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN)546return false;547#else548#ifdef GL_RGBA32F_EXT549if( texFormat == GL_RGBA32F_EXT ) {550return true;551}552#endif553#ifdef GL_RGB32F_EXT554if( texFormat == GL_RGB32F_EXT ) {555return true;556}557#endif558#ifdef GL_RGBA16F559if( texFormat == GL_RGBA16F ) {560return true;561}562#endif563return (texFormat == GL_RGBA32F || texFormat == GL_RGB32F);564#endif565}
566
567//--------------------------------------------------------------
568void ofCubeMap::setUseBrdfLutTexture( bool ab ) {569#ifdef TARGET_OPENGLES570data->settings.useLutTex = false;571ofLogWarning("ofCubeMap::setUseBrdfLutTexture") << " brdf lut texture not supported on GLES.";572return;573#else574data->settings.useLutTex = ab;575if(ab && !sBrdfLutTex.isAllocated() ) {576_createBrdfLUT();577}578#endif579}
580
581//--------------------------------------------------------------
582void ofCubeMap::_createCubeMap(ofTexture& aSrcTex) {583
584if( !data->bCubeMapAllocated ) {585data->bCubeMapAllocated = true;586glGenTextures(1, &data->cubeMapId );587retain(data->cubeMapId);588}589
590GLuint internalFormat = ofGetGLInternalFormatFromPixelFormat(OF_PIXELS_RGB);591#ifdef TARGET_OPENGLES592internalFormat = ofGetGLInternalFormatFromPixelFormat(OF_PIXELS_RGBA);593#endif594
595GLuint texStorageFormat = GL_UNSIGNED_BYTE;596GLuint gFormat = GL_RGB;597#ifdef TARGET_OPENGLES598gFormat = GL_RGBA;599#endif600
601glBindTexture(GL_TEXTURE_CUBE_MAP, data->cubeMapId);602
603for (GLint i = 0 ; i < 6 ; i++) {604glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormat, data->settings.resolution, data->settings.resolution, 0, gFormat, texStorageFormat, NULL);605}606
607glBindTexture(GL_TEXTURE_CUBE_MAP, 0);608
609_configureCubeTextures( data->cubeMapId, true );610
611
612_equiRectToCubeMap( data->cubeMapId, aSrcTex, data->settings.resolution, true );613
614
615glBindTexture(GL_TEXTURE_CUBE_MAP, data->cubeMapId);616glGenerateMipmap(GL_TEXTURE_CUBE_MAP);617glBindTexture(GL_TEXTURE_CUBE_MAP, 0);618
619}
620
621//--------------------------------------------------------------
622void ofCubeMap::_configureCubeTextures(GLuint aCubeMapId, bool abLinearMipLinear) {623
624GLenum textureTarget = getTextureTarget();625glBindTexture(textureTarget, aCubeMapId );626
627if(abLinearMipLinear) {628glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);629} else {630glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);631}632glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);633glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);634glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);635#ifdef GL_TEXTURE_WRAP_R636glTexParameteri(textureTarget, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);637#endif638glBindTexture(getTextureTarget(), 0);639}
640
641//--------------------------------------------------------------
642void ofCubeMap::_initEmptyTextures(GLuint aCubeMapId, int aSize) {643
644GLenum textureTarget = getTextureTarget();645glBindTexture(textureTarget, aCubeMapId );646GLuint texStorageFormat = getTexStorageFormat();647GLuint gFormat = getGlTypeFromInternalFormat();648
649for (unsigned int i = 0; i < 6; i++) {650glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, texFormat, aSize, aSize, 0, gFormat, texStorageFormat, nullptr );651}652
653glBindTexture(getTextureTarget(), 0);654}
655
656//--------------------------------------------------------------
657void ofCubeMap::_initEmptyTextures(GLuint aCubeMapId, GLuint aInternalFormat, int aSize, int aNumMipMaps ) {658GLenum textureTarget = getTextureTarget();659glBindTexture(textureTarget, aCubeMapId );660GLuint texStorageFormat = getTexStorageFormat(aInternalFormat);661GLuint gFormat = getGlTypeFromInternalFormat(aInternalFormat);662
663for (int mip = 0; mip < data->maxMipLevels; mip++) {664// reisze framebuffer according to mip-level size.665unsigned int mipWidth = static_cast<unsigned int>(data->settings.preFilterRes * std::pow(0.5, mip));666if(mipWidth < 1 ) {667mipWidth = 1;668}669for (unsigned int i = 0; i < 6; i++) {670glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, mip, aInternalFormat, mipWidth, mipWidth, 0, gFormat, texStorageFormat, nullptr );671}672}673
674glBindTexture(getTextureTarget(), 0);675}
676
677//--------------------------------------------------------------
678GLuint ofCubeMap::_createFloatCubeMap(ofTexture& aSrcTex, int aSrcRes) {679GLuint cubeTexF;680glGenTextures(1, &cubeTexF );681
682GLuint texStorageFormat = getTexStorageFormat();683GLuint gFormat = getGlTypeFromInternalFormat();684
685glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexF );686
687for (GLint i = 0 ; i < 6 ; i++) {688glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, texFormat, aSrcRes, aSrcRes, 0, gFormat, texStorageFormat, NULL);689}690
691glBindTexture(GL_TEXTURE_CUBE_MAP, 0);692
693_configureCubeTextures( cubeTexF, true );694_equiRectToCubeMap( cubeTexF, aSrcTex, aSrcRes, false );695
696glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexF);697glGenerateMipmap(GL_TEXTURE_CUBE_MAP);698glBindTexture(GL_TEXTURE_CUBE_MAP, 0);699
700return cubeTexF;701}
702
703//--------------------------------------------------------------
704void ofCubeMap::_equiRectToCubeMap( GLuint& aCubeTexId, ofTexture& aSrcTex, int aSrcRes, bool aBConvertToNonFloat ) {705bool bShaderLoaded = _loadEquiRectToCubeMapShader();706if( !bShaderLoaded ) {707ofLogError("ofCubeMap::_equiRectToCubeMap : error loading shader");708return;709}710
711_allocateCubeMesh();712std::vector<glm::mat4> views = _getViewMatrices( glm::vec3(0,0,0) );713
714unsigned int captureFBO;715glGenFramebuffers(1, &captureFBO);716glBindFramebuffer(GL_FRAMEBUFFER, captureFBO );717
718ofSetColor( 255 );719
720ofPushView();721ofViewport(0, 0, aSrcRes, aSrcRes, false);722
723shaderEquiRectToCubeMap.begin();724shaderEquiRectToCubeMap.setUniformTexture("uEquirectangularTex", aSrcTex, 0 );725shaderEquiRectToCubeMap.setUniformMatrix4f("uProjection", projectionMat );726shaderEquiRectToCubeMap.setUniform1f("uFlipY", data->settings.flipVertically ? 1.0f : 0.0f );727shaderEquiRectToCubeMap.setUniform1f("uConvertToNonFloat", aBConvertToNonFloat ? 1.0f : 0.0f );728
729for (unsigned int i = 0; i < 6; i++) {730shaderEquiRectToCubeMap.setUniformMatrix4f("uView", views[i]);731glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, aCubeTexId, 0);732glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);733sCubeMesh.draw();734}735shaderEquiRectToCubeMap.end();736ofPopView();737
738glBindFramebuffer(GL_FRAMEBUFFER, 0);739glDeleteFramebuffers(1, &captureFBO);740}
741
742//--------------------------------------------------------------
743void ofCubeMap::_createIrradianceMap(GLuint aSrcCubeFid, bool aBMakeCache, const of::filesystem::path & aCachePath) {744if(data->bIrradianceAllocated) {745return;746}747if( !data->bIrradianceAllocated ) {748data->bIrradianceAllocated = true;749glGenTextures(1, &data->irradianceMapId );750retain(data->irradianceMapId);751}752
753_allocateCubeMesh();754
755std::vector<glm::mat4> views = _getViewMatrices( glm::vec3(0,0,0) );756
757if( !shaderIrradianceMap.isLoaded() ) {758auto isource = ofCubeMapShaders::irriadianceCubeMap();759shaderIrradianceMap.setupShaderFromSource(GL_VERTEX_SHADER, isource.vertShader );760shaderIrradianceMap.setupShaderFromSource(GL_FRAGMENT_SHADER, isource.fragShader );761shaderIrradianceMap.bindDefaults();762shaderIrradianceMap.linkProgram();763}764
765if( aBMakeCache ) {766
767ofLogNotice("ofCubeMap :: _createIrradianceMap : making cache");768
769ofFbo tfbo;770// fbo.clear();771ofFboSettings fboSettings;772fboSettings.width = data->settings.irradianceRes;773fboSettings.height = data->settings.irradianceRes;774fboSettings.numSamples = 0;775// fboSettings.numColorbuffers = 6;776fboSettings.useDepth = false;777// fboSettings.textureTarget = GL_TEXTURE_2D;
778fboSettings.internalformat = texFormat;779tfbo.allocate(fboSettings);780
781ofSetColor( 255 );782
783vector<ofFloatPixels> fpixels;784fpixels.assign(6, ofFloatPixels());785bool bAllPixelsCreated = true;786
787for( unsigned int i = 0; i < 6; i++ ) {788tfbo.begin();789ofClear(0, 0, 0);790shaderIrradianceMap.begin();791shaderIrradianceMap.setUniformTexture("environmentMap", getTextureTarget(), aSrcCubeFid, 0 );792shaderIrradianceMap.setUniformMatrix4f("uProjection", projectionMat );793shaderIrradianceMap.setUniformMatrix4f("uView", views[i]);794sCubeMesh.draw();795shaderIrradianceMap.end();796
797tfbo.end();798tfbo.updateTexture(0);799tfbo.readToPixels(fpixels[i]);800if( fpixels[i].getWidth() < 1 || fpixels[i].getHeight() < 1 ) {801bAllPixelsCreated = false;802}803}804
805if(bAllPixelsCreated) {806GLenum textureTarget = getTextureTarget();807glBindTexture(textureTarget, data->irradianceMapId );808GLuint texStorageFormat = getTexStorageFormat();809GLuint gFormat = getGlTypeFromInternalFormat();810// we need to create a single image //811for (unsigned int i = 0; i < 6; i++) {812glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, texFormat, fpixels[i].getWidth(), fpixels[i].getHeight(), 0, gFormat, texStorageFormat, fpixels[i].getData() );813}814glBindTexture(textureTarget, 0 );815
816_configureCubeTextures(data->irradianceMapId, false);817
818// ok, now lets make a single fbo819int fullWidth = data->settings.irradianceRes * 3;820fboSettings.width = fullWidth;821fboSettings.height = data->settings.irradianceRes * 2;822
823int texSize = data->settings.irradianceRes;824
825tfbo.clear();826tfbo.allocate( fboSettings );827ofSetColor(255);828tfbo.begin(); {829ofClear(0);830ofTexture ftex;831for (unsigned int j = 0; j < 6; j++) {832ftex.loadData( fpixels[j] );833ftex.draw((j % 3) * texSize, floor(j / 3) * texSize, texSize, texSize);834}835} tfbo.end();836
837ofFloatPixels fpix;838tfbo.updateTexture(0);839tfbo.readToPixels(fpix);840if( fpix.getNumChannels() != 3 ) {841fpix.setNumChannels(3);842}843if(!ofSaveImage(fpix, aCachePath)) {844ofLogError("ofCubeMap :: _createIrradianceMap : ") << aCachePath;845}846}847
848
849} else {850
851_initEmptyTextures(data->irradianceMapId, data->settings.irradianceRes );852_configureCubeTextures(data->irradianceMapId, false);853
854unsigned int captureFBO;855
856glGenFramebuffers(1, &captureFBO);857glBindFramebuffer(GL_FRAMEBUFFER, captureFBO );858
859ofPushView();860ofViewport(0, 0, data->settings.irradianceRes, data->settings.irradianceRes, false);861
862ofSetColor( 255 );863shaderIrradianceMap.begin();864shaderIrradianceMap.setUniformTexture("environmentMap", getTextureTarget(), aSrcCubeFid, 0 );865shaderIrradianceMap.setUniformMatrix4f("uProjection", projectionMat );866
867for( unsigned int i = 0; i < 6; i++ ) {868shaderIrradianceMap.setUniformMatrix4f("uView", views[i]);869glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, data->irradianceMapId, 0);870ofClear(0, 0, 0, 255);871sCubeMesh.draw();872}873
874shaderIrradianceMap.end();875
876glBindFramebuffer(GL_FRAMEBUFFER, 0);877glDeleteFramebuffers(1, &captureFBO);878ofPopView();879}880
881}
882
883//--------------------------------------------------------------
884bool ofCubeMap::_loadIrradianceMap(const of::filesystem::path & aCachePath) {885
886if(data->bIrradianceAllocated) {887return false;888}889
890ofLogVerbose("ofCubeMap :: _loadIrradianceMap : does file exist: ") << ofFile::doesFileExist(aCachePath);891if( !ofFile::doesFileExist(aCachePath) ) {892return false;893}894
895ofFloatPixels fullPix;896if( !ofLoadImage( fullPix, aCachePath )) {897ofLogError("ofCubeMap :: _loadIrradianceMap : unable to load from ") << aCachePath;898return false;899}900
901if( !data->bIrradianceAllocated ) {902data->bIrradianceAllocated = true;903glGenTextures(1, &data->irradianceMapId );904retain(data->irradianceMapId);905}906
907// _configureCubeTextures(data->irradianceMapId, false);
908
909int texSize = fullPix.getWidth() / 3;910
911ofFloatPixels fpix;912size_t numChannels = getNumPixelChannels();913GLenum textureTarget = getTextureTarget();914
915ofLogVerbose() << "ofCubeMap :: _loadIrradianceMap : num channels: " << numChannels;916
917glBindTexture(textureTarget, data->irradianceMapId );918
919GLuint loadTexFormat = texFormat;920#if defined(TARGET_EMSCRIPTEN)921loadTexFormat = GL_RGBA32F;922#endif923
924GLuint texStorageFormat = getTexStorageFormat(loadTexFormat);925GLuint gFormat = getGlTypeFromInternalFormat(loadTexFormat);926
927for(unsigned int j = 0; j < 6; j++ ) {928//cropTo(ofPixels_<PixelType> &toPix, size_t x, size_t y, size_t _width, size_t _height)929fullPix.cropTo( fpix, (j % 3) * texSize, floor(j / 3) * texSize, texSize, texSize );930if( fpix.getNumChannels() != numChannels ) {931fpix.setNumChannels(numChannels);932}933glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, 0, loadTexFormat, fpix.getWidth(), fpix.getHeight(), 0, gFormat, texStorageFormat, fpix.getData() );934}935glBindTexture(textureTarget, 0 );936
937_configureCubeTextures(data->irradianceMapId, false);938
939return true;940}
941
942//--------------------------------------------------------------
943void ofCubeMap::_createPrefilteredCubeMap(GLuint aSrcCubeFid, int aSrcRes, bool aBMakeCache, const of::filesystem::path & aCachePath) {944if(data->bPreFilteredMapAllocated) {945return;946}947
948_allocateCubeMesh();949data->bPreFilteredMapAllocated = true;950glGenTextures(1, &data->preFilteredMapId );951retain(data->preFilteredMapId);952
953glBindTexture(GL_TEXTURE_CUBE_MAP, data->preFilteredMapId);954
955GLuint texStorageFormat = getTexStorageFormat();956GLuint gFormat = getGlTypeFromInternalFormat();957
958// generate all of the textures and mip maps at once ...959//glTexStorage2D(GL_TEXTURE_CUBE_MAP, data->maxMipLevels, texFormat, data->settings.preFilterRes, data->settings.preFilterRes);960// create all of the textures with mip maps //961
962glBindTexture(GL_TEXTURE_CUBE_MAP, 0);963
964_initEmptyTextures( data->preFilteredMapId, texFormat, data->settings.preFilterRes, data->maxMipLevels );965
966_configureCubeTextures(data->preFilteredMapId, true);967
968if( !shaderPreFilterMap.isLoaded() ) {969auto psource = ofCubeMapShaders::prefilter();970shaderPreFilterMap.setupShaderFromSource(GL_VERTEX_SHADER, psource.vertShader );971shaderPreFilterMap.setupShaderFromSource(GL_FRAGMENT_SHADER, psource.fragShader );972shaderPreFilterMap.bindDefaults();973shaderPreFilterMap.linkProgram();974}975
976std::vector<glm::mat4> views = _getViewMatrices( glm::vec3(0,0,0) );977
978if( aBMakeCache ) {979ofLogVerbose("ofCubeMap :: _createPrefilteredCubeMap : making cache");980ofFboSettings fboSettings;981ofFbo cacheFbo;982fboSettings.width = data->settings.preFilterRes * 3;983fboSettings.height = fboSettings.width;984fboSettings.numSamples = 0;985fboSettings.useDepth = false;986fboSettings.internalformat = texFormat;987
988cacheFbo.allocate(fboSettings);989cacheFbo.begin(); {990ofClear(255, 0, 0);991} cacheFbo.end();992
993ofFbo tfbo;994
995vector<ofFloatPixels> fpixels;996fpixels.assign(6, ofFloatPixels() );997// bool bAllPixelsCreated = true;998
999int shiftX = 0;1000int shiftY = 0;1001
1002for (int mip = 0; mip < data->maxMipLevels; mip++) {1003// reisze framebuffer according to mip-level size.1004unsigned int mipWidth = static_cast<unsigned int>(data->settings.preFilterRes * std::pow(0.5, mip));1005if(mipWidth < 1 ) {1006mipWidth = 1;1007}1008fboSettings.width = mipWidth;1009fboSettings.height = fboSettings.width;1010tfbo.clear();1011tfbo.allocate(fboSettings);1012
1013float roughness = (float)mip / (float)(data->maxMipLevels - 1);1014
1015if( mip > 0 ) {1016shiftY = data->settings.preFilterRes * 2;1017}1018
1019for (unsigned int i = 0; i < 6; ++i) {1020tfbo.begin();1021ofClear(0);1022shaderPreFilterMap.begin();1023shaderPreFilterMap.setUniformTexture("environmentMap", getTextureTarget(), aSrcCubeFid, 0 );1024shaderPreFilterMap.setUniformMatrix4f("uProjection", projectionMat );1025shaderPreFilterMap.setUniform1f("resolution", (float)aSrcRes );1026shaderPreFilterMap.setUniform1f("uroughness", roughness);1027shaderPreFilterMap.setUniformMatrix4f( "uView", views[i] );1028sCubeMesh.draw();1029shaderPreFilterMap.end();1030tfbo.end();1031
1032tfbo.readToPixels(fpixels[i]);1033if( fpixels[i].getWidth() < 1 || fpixels[i].getHeight() < 1 ) {1034// bAllPixelsCreated = false;1035} else {1036cacheFbo.begin();1037tfbo.getTexture().draw( (i%3) * mipWidth + shiftX, floor(i/3) * mipWidth + shiftY, mipWidth, mipWidth );1038cacheFbo.end();1039}1040}1041
1042if( mip > 0 ) {1043shiftX += mipWidth * 3;1044}1045
1046glBindTexture(GL_TEXTURE_CUBE_MAP, data->preFilteredMapId);1047for (unsigned int i = 0; i < 6; ++i) {1048if( fpixels[i].getWidth() > 0 && fpixels[i].getHeight() > 0 ) {1049// // must use glTexSubImage with glTexStorage2D
1050glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, mip, 0, 0, mipWidth, mipWidth, gFormat, texStorageFormat,fpixels[i].getData());1051
1052}1053}1054glBindTexture(GL_TEXTURE_CUBE_MAP, 0);1055}1056
1057ofFloatPixels cachePix;1058cacheFbo.readToPixels(cachePix);1059if( cachePix.getWidth() > 0 ) {1060if( !ofSaveImage(cachePix, aCachePath) ) {1061ofLogError("ofCubeMap :: _createPrefilteredCubeMap: ") << aCachePath;1062}1063}1064
1065} else {1066
1067unsigned int captureFBO;1068glGenFramebuffers(1, &captureFBO);1069glBindFramebuffer(GL_FRAMEBUFFER, captureFBO );1070
1071for (int mip = 0; mip < data->maxMipLevels; mip++) {1072// reisze framebuffer according to mip-level size.1073unsigned int mipWidth = static_cast<unsigned int>(data->settings.preFilterRes * std::pow(0.5, mip));1074ofPushView();1075ofViewport(0, 0, mipWidth, mipWidth, false);1076shaderPreFilterMap.begin();1077shaderPreFilterMap.setUniformTexture("environmentMap", getTextureTarget(), aSrcCubeFid, 0 );1078shaderPreFilterMap.setUniformMatrix4f("uProjection", projectionMat );1079shaderPreFilterMap.setUniform1f("resolution", (float)aSrcRes );1080
1081float roughness = (float)mip / (float)(data->maxMipLevels - 1);1082shaderPreFilterMap.setUniform1f("uroughness", roughness);1083for (unsigned int i = 0; i < 6; ++i) {1084shaderPreFilterMap.setUniformMatrix4f( "uView", views[i] );1085glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, data->preFilteredMapId, mip);1086ofClear(0, 0, 0);1087sCubeMesh.draw();1088}1089shaderPreFilterMap.end();1090ofPopView();1091}1092
1093glBindFramebuffer(GL_FRAMEBUFFER, 0);1094glDeleteFramebuffers(1, &captureFBO);1095}1096
1097glBindTexture(GL_TEXTURE_CUBE_MAP, 0);1098}
1099
1100//--------------------------------------------------------------
1101bool ofCubeMap::_loadPrefilterMap( const of::filesystem::path & aCachePath ) {1102if(data->bPreFilteredMapAllocated) {1103return false;1104}1105
1106ofLogVerbose("ofCubeMap :: _loadPrefilterMap : does file exist: ") << ofFile::doesFileExist(aCachePath);1107if( !ofFile::doesFileExist(aCachePath) ) {1108return false;1109}1110
1111ofFloatPixels fullPix;1112if( !ofLoadImage( fullPix, aCachePath )) {1113ofLogError("ofCubeMap :: _loadPrefilterMap : unable to load from ") << aCachePath;1114return false;1115}1116
1117_allocateCubeMesh();1118data->bPreFilteredMapAllocated = true;1119glGenTextures(1, &data->preFilteredMapId );1120retain(data->preFilteredMapId);1121
1122
1123GLuint loadTexFormat = texFormat;1124#if defined(TARGET_EMSCRIPTEN)1125loadTexFormat = GL_RGBA32F;1126#endif1127
1128GLuint texStorageFormat = getTexStorageFormat(loadTexFormat);1129GLuint gFormat = getGlTypeFromInternalFormat(loadTexFormat);1130
1131_initEmptyTextures( data->preFilteredMapId, loadTexFormat, data->settings.preFilterRes, data->maxMipLevels );1132
1133//glBindTexture(GL_TEXTURE_CUBE_MAP, data->preFilteredMapId);1134//glTexStorage2D(GL_TEXTURE_CUBE_MAP, data->maxMipLevels, loadTexFormat, data->settings.preFilterRes, data->settings.preFilterRes);1135//glBindTexture(GL_TEXTURE_CUBE_MAP, 0);1136
1137_configureCubeTextures(data->preFilteredMapId, true);1138
1139ofFloatPixels fpix;1140size_t numChannels = getNumPixelChannels();1141
1142float shiftX = 0.0f;1143float shiftY = 0.0f;1144
1145glBindTexture(GL_TEXTURE_CUBE_MAP, data->preFilteredMapId );1146for (int mip = 0; mip < data->maxMipLevels; mip++) {1147// reisze framebuffer according to mip-level size.1148unsigned int mipWidth = static_cast<unsigned int>(data->settings.preFilterRes * std::pow(0.5, mip));1149if(mipWidth < 1 ) {mipWidth = 1;}1150
1151if( mip > 0 ) {1152shiftY = data->settings.preFilterRes * 2;1153}1154
1155for (unsigned int i = 0; i < 6; ++i) {1156fullPix.cropTo( fpix, (i % 3) * mipWidth + shiftX, floor(i / 3) * mipWidth + shiftY, mipWidth, mipWidth );1157if( fpix.getNumChannels() != numChannels ) {1158fpix.setNumChannels(numChannels);1159}1160glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, mip, 0, 0, mipWidth, mipWidth, gFormat, texStorageFormat,fpix.getData());1161}1162
1163if( mip > 0 ) {1164shiftX += mipWidth * 3;1165}1166}1167glBindTexture(GL_TEXTURE_CUBE_MAP, 0);1168return true;1169}
1170
1171//--------------------------------------------------------------
1172void ofCubeMap::_createBrdfLUT() {1173#ifndef TARGET_OPENGLES1174int lutWidth = 512;1175int lutHeight = 512;1176
1177ofFbo lutFbo;1178
1179if( !shaderBrdfLUT.isLoaded() ) {1180auto bsource = ofCubeMapShaders::brdfLUT();1181shaderBrdfLUT.setupShaderFromSource(GL_VERTEX_SHADER, bsource.vertShader );1182shaderBrdfLUT.setupShaderFromSource(GL_FRAGMENT_SHADER, bsource.fragShader );1183shaderBrdfLUT.bindDefaults();1184shaderBrdfLUT.linkProgram();1185}1186
1187ofMesh quadMesh;1188quadMesh.setMode(OF_PRIMITIVE_TRIANGLES);1189quadMesh.addVertices({1190glm::vec3(0,0,0),1191glm::vec3(lutWidth, 0.0, 0.0),1192glm::vec3(lutWidth, lutHeight, 0.0),1193glm::vec3(0, lutHeight, 0.0f)1194
1195});1196
1197quadMesh.addTexCoords( {1198glm::vec2(0.0f, 1.0f),1199glm::vec2(1.0f, 1.0f),1200glm::vec2(1.0f, 0.0f),1201glm::vec2(0.0f, 0.0f)1202});1203
1204quadMesh.addIndices({12050, 1, 3,12061, 2, 31207});1208quadMesh.disableColors();1209quadMesh.disableNormals();1210lutFbo.allocate(lutWidth, lutHeight, GL_RG32F );1211
1212ofSetColor(255);1213ofPushView();1214lutFbo.begin();1215ofClear(0, 0, 0);1216shaderBrdfLUT.begin();1217quadMesh.draw();1218ofSetColor(255);1219shaderBrdfLUT.end();1220lutFbo.end();1221ofPopView();1222
1223lutFbo.updateTexture(0);1224sBrdfLutTex = lutFbo.getTexture(0);1225lutFbo.clear();1226
1227glBindTexture(GL_TEXTURE_2D, 0);1228#else1229ofLogWarning("ofCubeMap::_createBrdfLUT") << " brdf lut texture not supported on GLES";1230#endif1231}
1232
1233//--------------------------------------------------------------
1234void ofCubeMap::_allocateCubeMesh() {1235if( sCubeMesh.getNumVertices() > 0 ) {1236return;1237}1238sCubeMesh = ofMesh::box( 1, 1, 1, 4, 4, 4);1239sCubeMesh.disableColors();1240sCubeMesh.disableTextures();1241sCubeMesh.disableNormals();1242sCubeMesh.getTexCoords().clear();1243}
1244
1245//--------------------------------------------------------------
1246std::vector<glm::mat4> ofCubeMap::_getViewMatrices(const glm::vec3& apos ) {1247// eye, target and up vector1248// +x, -x, +y, -y, +z and -z direction1249vector<glm::mat4> views = {1250glm::lookAt( apos, apos+glm::vec3(1,0,0), glm::vec3(0, -1, 0) ),1251glm::lookAt( apos, apos+glm::vec3(-1,0,0), glm::vec3(0, -1, 0) ),1252glm::lookAt( apos, apos+glm::vec3(0,1,0), glm::vec3(0, 0, 1) ),1253glm::lookAt( apos, apos+glm::vec3(0,-1,0), glm::vec3(0, 0, -1) ),1254glm::lookAt( apos, apos+glm::vec3(0,0,1), glm::vec3(0, -1, 0) ),1255glm::lookAt( apos, apos+glm::vec3(0,0,-1), glm::vec3(0, -1, 0) )1256};1257return views;1258}
1259
1260//--------------------------------------------------------------
1261GLuint ofCubeMap::getTexStorageFormat() {1262return getTexStorageFormat(texFormat);1263}
1264
1265//--------------------------------------------------------------
1266GLuint ofCubeMap::getTexStorageFormat(GLuint aInternalFormat) {1267#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN)1268if( aInternalFormat == GL_RGB32F ) {1269return GL_FLOAT;1270} else if( aInternalFormat == GL_RGBA32F ) {1271return GL_FLOAT;1272} else if( aInternalFormat == GL_RGBA16F ) {1273return GL_HALF_FLOAT;1274}1275#ifdef GL_RGBA32F_EXT1276if( aInternalFormat == GL_RGBA32F_EXT ) {1277return GL_FLOAT;1278}1279#endif1280#ifdef GL_RGB32F_EXT1281if( aInternalFormat == GL_RGB32F_EXT ) {1282return GL_FLOAT;1283}1284#endif1285#endif1286return GL_UNSIGNED_BYTE;1287}
1288
1289//--------------------------------------------------------------
1290GLuint ofCubeMap::getGlTypeFromInternalFormat() {1291return getGlTypeFromInternalFormat(texFormat);1292}
1293
1294//--------------------------------------------------------------
1295GLuint ofCubeMap::getGlTypeFromInternalFormat(GLuint aInternalFormat) {1296#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN)1297if( aInternalFormat == GL_RGBA32F ) {1298return GL_RGBA;1299}1300if( aInternalFormat == GL_RGBA16F ) {1301return GL_RGBA;1302}1303
1304#ifdef GL_RGBA32F_EXT1305if( aInternalFormat == GL_RGBA32F_EXT ) {1306return GL_RGBA;1307}1308#endif1309#ifdef GL_RGB32F_EXT1310if( aInternalFormat == GL_RGB32F_EXT ) {1311return GL_RGB;1312}1313#endif1314#endif1315return GL_RGB;1316}
1317
1318//--------------------------------------------------------------
1319int ofCubeMap::getNumPixelChannels() {1320GLuint glType = getGlTypeFromInternalFormat();1321if( glType == GL_RGBA ) {1322return 4;1323}1324return 3;1325}
1326
1327//--------------------------------------------------------------
1328bool ofCubeMap::_loadRenderShader() {1329shaderRender.unload();1330
1331auto rsource = ofCubeMapShaders::renderShader();1332shaderRender.setupShaderFromSource(GL_VERTEX_SHADER, rsource.vertShader );1333shaderRender.setupShaderFromSource(GL_FRAGMENT_SHADER, rsource.fragShader );1334shaderRender.bindDefaults();1335return shaderRender.linkProgram();1336}
1337
1338//--------------------------------------------------------------
1339bool ofCubeMap::_loadEquiRectToCubeMapShader() {1340if( !shaderEquiRectToCubeMap.isLoaded() ) {1341auto esource = ofCubeMapShaders::equiRectToCubeMap();1342shaderEquiRectToCubeMap.setupShaderFromSource(GL_VERTEX_SHADER, esource.vertShader );1343shaderEquiRectToCubeMap.setupShaderFromSource(GL_FRAGMENT_SHADER, esource.fragShader );1344shaderEquiRectToCubeMap.bindDefaults();1345if(shaderEquiRectToCubeMap.linkProgram()) {1346return true;1347} else {1348shaderEquiRectToCubeMap.unload();1349ofLogNotice("ofCubeMap::_loadEquiRectToCubeMapShader : unable to create shaderEquiRectToCubeMap shader ");1350return false;1351}1352}1353return true;1354}
1355