/** ****************************************************************************** @file /gui/engine/TextureManager.cpp @brief Manager textur rendereru @author Vajicek @version 0.1 ******************************************************************************/ #include "gui/engine/TextureManager.h" #include "gui/common/KTime.h" // #include "common/mm.h" #include "common/exc.h" #include "common/rm/rminit.h" //#include "tests/provrm.h" using namespace std; namespace gui{ /*****************************************************************************/ TTextureManager* TTextureManager::tm; void TTextureManager::TextureManager_Init(){ TTextureManager::tm = new TTextureManager; } void TTextureManager::TextureManager_Free(){ delete TTextureManager::tm; } /*****************************************************************************/ TTextureManager::TTextureManager(){ tm_lock = SDL_CreateMutex(); iMemLimit = 1<<26; //64MB iMemOccupied = 0; } TTextureManager::~TTextureManager(){ unloadTextures(); resetAllQueries(); SDL_DestroyMutex(tm_lock); } /***/ TTextureLoaderQuery* TTextureManager::getQuery(int bid){ for(vector::iterator vtq_it = vTextureQuery.begin(); vtq_it != vTextureQuery.end(); vtq_it++) if((*vtq_it)->bid == bid)return (*vtq_it); return NULL; } TTextureLoaderQuery* TTextureManager::getQuery(void* data){ for(vector::iterator vtq_it = vTextureQuery.begin(); vtq_it != vTextureQuery.end(); vtq_it++) if((*vtq_it)->data == data)return (*vtq_it); return NULL; } void TTextureManager::releaseTextureQuery(TTextureLoaderQuery* tq){ if(tq->pHandle)KMemFree(tq->pHandle); if(tq)KMemFree(tq); } /** prida pozadavek na nahrani textury podle jmena souboru */ TTextureLoaderQuery* TTextureManager::loadTextureQuery(char* filename, HWTID* handle, int flag, int internalformat ){ //request do rm, !!! rm::TRM_raster_i* rmi = (rm::TRM_raster_i*)KSendBcAnMsg(MSG_GET_RM_RASTER_I, 0); int bid = rmi->request(filename); delete rmi; if (bid<0) THROW(E_8K_GUI, "TTextureManager::loadTextureQuery - raster file not registred\n"); //request do texturemanageru return loadTextureQuery(bid, handle, flag, internalformat ); } /** prida pozadavek na texturu z pameti */ TTextureLoaderQuery* TTextureManager::loadTextureQuery(void* data, int w, int h, HWTID* handle, int flag, int internalformat ){ SDL_LockMutex(tm_lock); TTextureLoaderQuery* tq; TTexture* t; //textura je uz nahrana t = findTexture( data ); if(t){ *((HWTID*)handle) = t->hwtid; t->iFlag = flag|TEXFLAG_MEMORY; t->tStamp = KTime(); GLclampf c = 0.25f * (flag & TEXFLAG_PRIORITY_MASK); //glPrioritizeTextures(1, &(t->hwtid), &c); BUG! nesmi se vola na vlakne SDL_UnlockMutex(tm_lock); return NULL; } //o texturu uz je pozadano tq = getQuery(data); //zjisteni, zda jde o spravny tq if(!tq){ //pridej do fronty pozadavku k nahrani tq = (TTextureLoaderQuery*)KMemAlloc( sizeof(TTextureLoaderQuery) ); tq->data = data; tq->width = w; tq->height = h; tq->pixelformat.palette = NULL; tq->pixelformat.BitsPerPixel = 32; tq->pixelformat.BytesPerPixel = 4; tq->pixelformat.Rmask = 0x000000FF; tq->pixelformat.Gmask = 0x0000FF00; tq->pixelformat.Bmask = 0x00FF0000; tq->pixelformat.Amask = 0xFF000000; tq->pixelformat.Rshift = 0; tq->pixelformat.Gshift = 0; tq->pixelformat.Bshift = 0; tq->pixelformat.Ashift = 0; tq->pixelformat.Rloss = 0; tq->pixelformat.Gloss = 0; tq->pixelformat.Bloss = 0; tq->pixelformat.Aloss = 0; tq->pixelformat.colorkey = 0; tq->pixelformat.alpha = 0; tq->iHandle_c = 0; tq->pHandle = NULL; tq->iFlag = flag|TEXFLAG_MEMORY; tq->iInternalFormat = internalformat; tq->tl_handler = NULL; // vTextureQuery.push_back(tq); } tq->pHandle = (HWTID**)KExtArrayRealloc(tq->pHandle, sizeof(HWTID*), tq->iHandle_c + 1, tq->iHandle_c); tq->pHandle[ tq->iHandle_c ] = handle; tq->iHandle_c ++; SDL_UnlockMutex(tm_lock); return tq; } /** prida pozadavek na texturu z bitmapy */ TTextureLoaderQuery* TTextureManager::loadTextureQuery(int bid, HWTID* handle, int flag, int internalformat ){ SDL_LockMutex(tm_lock); TTextureLoaderQuery* tq; TTexture* t; //textura je uz nahrana t = findTexture( bid ); if(t){ *((HWTID*)handle) = t->hwtid; t->iFlag = flag|TEXFLAG_RMRASTER; t->tStamp = KTime(); GLclampf c = 0.25f * (flag & TEXFLAG_PRIORITY_MASK); //glPrioritizeTextures(1, &(t->hwtid), &c); BUG viz vyse SDL_UnlockMutex(tm_lock); return NULL; } //o texturu uz je pozadano tq = getQuery(bid); //zjisteni, zda jde o spravny tq if(!tq){ //pridej do fronty pozadavku k nahrani tq = (TTextureLoaderQuery*)KMemAlloc( sizeof(TTextureLoaderQuery) ); tq->bid = bid; tq->iHandle_c = 0; tq->pHandle = NULL; tq->iFlag = flag|TEXFLAG_RMRASTER; tq->iInternalFormat = internalformat; tq->tl_handler = NULL; // vTextureQuery.push_back(tq); } tq->pHandle = (HWTID**)KExtArrayRealloc(tq->pHandle, sizeof(HWTID*), tq->iHandle_c + 1, tq->iHandle_c); tq->pHandle[ tq->iHandle_c ] = handle; tq->iHandle_c ++; SDL_UnlockMutex(tm_lock); return tq; } /** smaze frontu pozadavku */ void TTextureManager::resetAllQueries(){ SDL_LockMutex(tm_lock); for(vector::iterator vtq_it = vTextureQuery.begin(); vtq_it != vTextureQuery.end(); vtq_it++) releaseTextureQuery(*vtq_it); vTextureQuery.clear(); SDL_UnlockMutex(tm_lock); } /** vyhleda */ TTexture* TTextureManager::findTexture(char* filename){ SDL_LockMutex(tm_lock); for(vector::iterator vt_it = vTexture.begin(); vt_it != vTexture.end(); vt_it++) { if( ((*vt_it)->iFlag&TEXFLAG_RMRASTER) && !strcmp((*vt_it)->raster->szFilename, filename)) { SDL_UnlockMutex(tm_lock); return *vt_it; } } SDL_UnlockMutex(tm_lock); return NULL; } /** vyhleda */ TTexture* TTextureManager::findTexture(int bid){ SDL_LockMutex(tm_lock); for(vector::iterator vt_it = vTexture.begin(); vt_it != vTexture.end(); vt_it++) { if( ((*vt_it)->iFlag&TEXFLAG_RMRASTER) && ((*vt_it)->bid == bid)) { SDL_UnlockMutex(tm_lock); return *vt_it; } } SDL_UnlockMutex(tm_lock); return NULL; } TTexture* TTextureManager::findTexture(void* data){ SDL_LockMutex(tm_lock); for(vector::iterator vt_it = vTexture.begin(); vt_it != vTexture.end(); vt_it++) { if( ((*vt_it)->iFlag&TEXFLAG_MEMORY) && ((*vt_it)->texture_surface->pixels == data) ) { SDL_UnlockMutex(tm_lock); return *vt_it; } } SDL_UnlockMutex(tm_lock); return NULL; } TTexture* TTextureManager::addTexture(int flag, int bid, HWTID hwtid){ SDL_LockMutex(tm_lock); TTexture* t; t = (TTexture*)KMemAlloc( sizeof(TTexture) ); // t->iFlag = flag; t->bid = bid; t->hwtid = hwtid; t->iSize = 0; t->tStamp = KTime(); // rm::TRM_raster_i* rmi = (rm::TRM_raster_i*)KSendBcAnMsg(MSG_GET_RM_RASTER_I, 0); t->raster = rmi->get(t->bid); delete rmi; // if (!t->raster->surface) { // THROW(E_8K_GUI, "TextureManager::addTexture - raster not loaded\n"); KMemFree(t); SDL_UnlockMutex(tm_lock); return NULL; } // t->iSize = t->raster->surface->w * t->raster->surface->h * 4; // vTexture.push_back(t); iMemOccupied += t->iSize; // SDL_UnlockMutex(tm_lock); return t; } TTexture* TTextureManager::addTexture(int flag, void* data, int w, int h, SDL_PixelFormat pf, HWTID hwtid){ SDL_LockMutex(tm_lock); TTexture* t; t = (TTexture*)KMemAlloc( sizeof(TTexture) ); // t->iFlag = flag; t->hwtid = hwtid; t->iSize = w*h*4; t->tStamp = KTime(); // t->texture_surface = SDL_CreateRGBSurfaceFrom( data, w, h, 32, 0, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); if (!t->texture_surface) THROW(E_8K_GUI, "TextureManager::addTexture - error creating texture_surface\n"); // vTexture.push_back(t); iMemOccupied += t->iSize; // SDL_UnlockMutex(tm_lock); return t; } /* uvolni texturu z graficky krarty - MUSI SE VOLAT NA HALVNIM VLAKNE */ void TTextureManager::freeTexture(TTexture* t, int hwtid = 1){ SDL_LockMutex(tm_lock); if(t){ if(hwtid) glDeleteTextures(1, &(t->hwtid)); if(t->iFlag==TEXFLAG_MEMORY) SDL_FreeSurface(t->texture_surface); KMemFree(t); } SDL_UnlockMutex(tm_lock); } /** nahraje textury do graficky karty - MUSI SE VOLAT NA HLAVNIM VLAKNE */ void TTextureManager::loadTextures(){ SDL_LockMutex(tm_lock); TTextureLoaderQuery* tq; TTexture* t; HWTID *ids = NULL; GLclampf* priorities = NULL; size_t tql; int idi; std::vector vNewTextureQuery; // tql = vTextureQuery.size(); if(!tql) { SDL_UnlockMutex(tm_lock); return; } ids = (HWTID*)KMemAlloc( sizeof(HWTID) * tql); priorities = (GLclampf*)KMemAlloc( sizeof(GLclampf) * tql); idi = 0; // glGenTextures(GLsizei(tql), ids); int dd= glGetError(); // for(vector::iterator vtq_it = vTextureQuery.begin(); vtq_it != vTextureQuery.end(); vtq_it++) { tq = *vtq_it; t = NULL; // GLenum format = GL_RGB; int w,h; GLvoid* data; //vlozit texturu jednou if(tq->iFlag & TEXFLAG_RMRASTER){ t = addTexture(tq->iFlag, tq->bid, ids[idi]); //bitmapa neni jeste nahrana if(t==NULL) { vNewTextureQuery.push_back(tq); continue; } //urceni typu if(t->raster->surface->format->BitsPerPixel == 24){ if(t->raster->surface->format->Rmask == 0x000000FF) format = GL_RGB; else format = GL_BGR; } else if(t->raster->surface->format->BitsPerPixel == 32){ if(t->raster->surface->format->Rmask == 0x000000FF) format = GL_RGBA; else { tq->iInternalFormat = GL_RGBA8; format = GL_BGRA; } } else if(t->raster->surface->format->BitsPerPixel == 8) format = GL_COLOR_INDEX; w = t->raster->surface->w; h = t->raster->surface->h; data = t->raster->surface->pixels; }//if rm raster else if(tq->iFlag & TEXFLAG_MEMORY){ t = addTexture(tq->iFlag, tq->data, tq->width, tq->height, tq->pixelformat, ids[idi]); w = tq->width; h = tq->height; format = GL_RGBA; data = t->texture_surface->pixels; }//else if memory // if(!t)continue; t->iFormat = format; t->iInternalFormat = tq->iInternalFormat; //nastav aktualni texturu glBindTexture(GL_TEXTURE_2D, ids[idi]); //nahraj do ni data glTexImage2D( GL_TEXTURE_2D, 0, //TODO,LOD textury tq->iInternalFormat, w, h, 0, //TODO, okraj format, //TODO, zalezi na formatu GL_UNSIGNED_BYTE, data ); /* glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST ); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST );*/ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR ); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR ); if(tq->tl_handler) tq->tl_handler(t,tq); //pouzit vicekrat for(int i = 0; i < tq->iHandle_c; i++){ *((HWTID*)tq->pHandle[i]) = ids[idi]; } releaseTextureQuery(tq); idi++; } // glPrioritizeTextures(GLsizei(tql), ids, priorities); // if(priorities)KMemFree(priorities); if(ids)KMemFree(ids); vTextureQuery.clear(); vTextureQuery = vNewTextureQuery; SDL_UnlockMutex(tm_lock); } /** nahraje texturu z hlavni pameti do graficky karty - MUSI SE VOLAT NA HLAVNIM VLAKNE */ TTexture* TTextureManager::reloadTextureNow(TTexture* t){ SDL_LockMutex(tm_lock); //nastav aktualni texturu glBindTexture(GL_TEXTURE_2D, t->hwtid); //nahraj do ni data glTexImage2D( GL_TEXTURE_2D, 0, //TODO,LOD textury t->iInternalFormat, t->texture_surface->w, t->texture_surface->h, 0, //TODO, okraj t->iFormat, //TODO, zalezi na formatu GL_UNSIGNED_BYTE, t->texture_surface->pixels ); SDL_UnlockMutex(tm_lock); return NULL; } /** odstran textury - MUSI SE VOLAT NA HLAVNIM VLAKNE */ void TTextureManager::unloadTextures(){ SDL_LockMutex(tm_lock); size_t hwtid_l = vTexture.size(); HWTID* hwtid = (HWTID*)KMemAlloc( hwtid_l * sizeof(HWTID)); int i = 0; for(vector::iterator vt_it = vTexture.begin(); vt_it != vTexture.end(); vt_it++) { hwtid[i] = (*vt_it)->hwtid; freeTexture(*vt_it, 0); i++; } vTextureQuery.clear(); //hromadne zruseni glDeleteTextures(GLsizei(hwtid_l), hwtid); if(hwtid) KMemFree(hwtid); SDL_UnlockMutex(tm_lock); } /** uvolni nejmene pouzivane textury - MUSI SE VOLAT NA HALVNIM VLAKNE */ void TTextureManager::freeTextureMemory(int iSize){ SDL_LockMutex(tm_lock); vector::iterator min; while( iMemLimit < (iMemOccupied+iSize)){ //najdi minimum min = vTexture.begin(); for(vector::iterator vt_it = vTexture.begin(); vt_it != vTexture.end(); vt_it++) if((*vt_it)->tStamp < (*min)->tStamp ) min = vt_it; if( min == vTexture.end() ) THROW(E_8K_GUI,"Neni mozne uvolnit vic pameti"); freeTexture(*min); vTexture.erase(min); } SDL_UnlockMutex(tm_lock); } /** uvolni dlouho nepouzivane textury - MUSI SE VOLAT NA HALVNIM VLAKNE */ void TTextureManager::freeOldTextures(int tStamp){ SDL_LockMutex(tm_lock); for(vector::iterator vt_it = vTexture.begin(); vt_it != vTexture.end(); vt_it++) { if((*vt_it)->tStamp < tStamp ){ freeTexture(*vt_it); vTexture.erase(vt_it); } } SDL_UnlockMutex(tm_lock); } /** Projde model a pripravi vsechny resourcy */ void TTextureManager::prepareModel(TModel* m, int flags){ SDL_LockMutex(tm_lock); vector::iterator it; PMaterial mat; void* st[20]; int sst=0; for( it = m->matr.begin(); it != m->matr.end(); it++) { st[sst] = (void*)*it; sst++; } //projit se zasobnikem while(sst){ //vyber z vrcholu mat = (PMaterial)st[sst-1]; sst--; //doplneni for(int j = 0; j < mat->submat_c; j++){ st[sst] = (void*)&(mat->submat[j]); sst++; } //pruchod mapami for(int k = 0; k < mat->mmap_c; k++){ if(mat->mmap[k].bitmap_file){ //find in buffer TTextureManager::tm->loadTextureQuery( mat->mmap[k].bitmap_file, &(mat->mmap[k].id), TEXFLAG_PRIORITY_NORMAL, GL_RGBA ); }//if bitmap }//for mmap }//zasobnik = 0 SDL_UnlockMutex(tm_lock); } }//namespace /*****************************************************************************/