// Copyright (c) 1999-2012 OPEN CASCADE SAS // // The content of this file is subject to the Open CASCADE Technology Public // License Version 6.5 (the "License"). You may not use the content of this file // except in compliance with the License. Please obtain a copy of the License // at http://www.opencascade.org and read it completely before using this file. // // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. // // The Original Code and all software distributed under the License is // distributed on an "AS IS" basis, without warranty of any kind, and the // Initial Developer hereby disclaims all such warranties, including without // limitation, any warranties of merchantability, fitness for a particular // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. /* * Fonction * ~~~~~~~~ * Gestion des textures sous OpenGL * * * Notes * ~~~~~ * Les textures sont toujours initialisee avec des parametres par defaut * texture 1D: WRAP_S = CLAMP * MAG_FILTER = NEAREST * generation de texture automatique en OBJECT_LINEAR * rendu avec DECAL * * texture 2D: WRAP_S/T = REPEAT * MAG/MIN_FILTER = LINEAR * generation de texture automatique en OBJECT_LINEAR * rendu avec MODULATE * * texture 2D MipMap: WRAP_S/T = REPEAT * MAG_FILTER = LINEAR * MIN_FILTER = LINEAR_MIPMAP_NEAREST * generation de texture automatique en OBJECT_LINEAR * rendu avec MODULATE * * Historique des modifications * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * 22-05-97: PCT ; Creation * 18-06-97: FMN ; Ajout entete * 20-06-97: PCT ; Correction bug parametres par defaut texture 1D * 30-06-97: PCT ; Correction bug rechargement de la texture courante * 04-07-97: PCT ; suppression de l'utilisation de libimage.a de SGI * 01-08-97: PCT ; suppression InitializeTextureBox() * 04-08-97: FMN,PCT ; Portage WNT * 05-08-97: FMN ; ajout GetTextureData... * 10-09-97: PCT ; ajout commentaires. GetTexture() ne doit pas * etre utilisee dans Cas.Cade ( le chargement est * fait par Graphic3d ) * 06-10-97: FMN ; Portage HP * 14-10-97: FMN ; Ajout OpenGl_Extension * 22-10-97: FMN ; Meilleure gestion de l'extension glXGetCurrentDisplayEXT * 04-11-97: FMN ; Gestion des differentes versions GLX * 19-11-97: FMN ; Ajout GetCurrentDisplay plus simple que glXGetCurrentDisplayEXT * 04-12-97: FMN ; On suppose que l'on travaille en OpenGL1.1 (cf OpenGl_Extension) * 17-12-97: FMN ; Probleme compilation SGI * 17-12-97: FMN ; Probleme sur Optimisation sur MyBindTextureEXT() * Le test sur la texture courante doit tenir compte du contexte. * 22-07-98: FGU ; Ajout fonctions TransferTexture_To_Data() et TransferData_To_Texture() * */ #include #include #include #include #include #include #include #include #include #include #include // gluBuild2DMipmaps() #define GROW_TEXTURES 8 #define GROW_TEXTURES_DATA 8 #define GROW_CONTEXT 8 typedef enum {TEXDATA_NONE, TEXDATA_1D, TEXDATA_2D, TEXDATA_2DMM} texDataStatus; typedef enum {TEX_NONE, TEX_ALLOCATED} texStatus; typedef GLfloat SizeType[4]; typedef int TextureDataID; #define TEXTUREDATA_ERROR -1 struct texData { char imageFileName[128]; int imageWidth, imageHeight; GLubyte *image; texDataStatus status; GLint type; int share_count; DEFINE_STANDARD_ALLOC }; struct texDraw { TextureDataID data; GLuint *number; GLDRAWABLE *drawable; GLCONTEXT *context; char *use_bind_texture; int context_count; int context_size; texStatus status; GLint Gen; GLint Light; GLint Wrap; GLfloat Plane1[4]; GLfloat Plane2[4]; GLint Render; GLfloat scalex, scaley; GLfloat transx, transy; GLfloat angle; DEFINE_STANDARD_ALLOC }; /*----------------------------------------------------------------------*/ /* * Variables statiques */ static texDraw *textab = NULL; static int textures_count = 0; static int textures_size = 0; static texData *texdata = NULL; static int textures_data_count = 0; static int textures_data_size = 0; static TextureDataID current_texture_data = TEXTUREDATA_ERROR; static TextureID current_texture = TEXTUREBOX_ERROR; static GLfloat sgenparams[] = { 1.0 ,0.0 ,0.0 ,0.0}; static GLfloat tgenparams[] = { 0.0 ,1.0 ,0.0 ,0.0}; static GLenum status2type[] = { GL_NONE, GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_2D }; /*----------------------------------------------------------------------*/ /* * Fonctions privees */ /*----------------------------------------------------------------------*/ /* * recherche l'existence de datas de texture par son nom */ static TextureDataID FindTextureData(char *FileName) { int i; for (i=0; i(texdata, textures_data_size); #endif if (texdata == NULL) return TEXTUREDATA_ERROR; for (i=textures_data_count; i retourne un ID rapidement... */ return textures_data_count++; } /* recherche d'un ID libre */ for (i=0; i(textab, textures_size); #endif if (textab == NULL) return TEXTUREBOX_ERROR; for (i=textures_count; i retourne un ID rapidement... */ return textures_count++; } for (i=0; i(textab[ID].number, textab[ID].context_size); textab[ID].context = cmn_resizemem(textab[ID].context, textab[ID].context_size); textab[ID].drawable = cmn_resizemem(textab[ID].drawable, textab[ID].context_size); textab[ID].use_bind_texture = cmn_resizemem(textab[ID].use_bind_texture, textab[ID].context_size); #endif if ( (textab[ID].number == NULL) || (textab[ID].context == NULL) || (textab[ID].drawable == NULL) || (textab[ID].use_bind_texture == NULL) ) { /* erreur => libere tout */ free(textab[ID].number); free(textab[ID].context); free(textab[ID].drawable); free(textab[ID].use_bind_texture); textab[ID].context_size = 0; return TEXTUREBOX_ERROR; } } MyGenTextureEXT(ID); SetTextureParam(ID); #ifdef PRINT printf("InstallTextureInContext::context ok\n"); #endif return 0; } /*----------------------------------------------------------------------*/ static TextureID GetTexture(char *FileName, texDataStatus status) { TextureDataID i; TextureID j; int dummy; /* essait de trouver la texture */ i = FindTextureData(FileName); if (i == TEXTUREDATA_ERROR) { #ifdef PRINT printf("GetTexture::la texture %s n'existe pas => chargement\n", FileName); #endif /* creation d'une texture */ i = FindFreeTextureData(); if (i == TEXTUREDATA_ERROR) return TEXTUREBOX_ERROR; texdata[i].share_count = 0; strcpy(texdata[i].imageFileName, FileName); texdata[i].image = (GLubyte *)read_texture(FileName, &texdata[i].imageWidth, &texdata[i].imageHeight, &dummy); if (texdata[i].image == NULL) return TEXTUREBOX_ERROR; texdata[i].status = status; texdata[i].type = status2type[status]; } j = FindFreeTexture(); if (j != TEXTUREBOX_ERROR) { #ifdef PRINT printf("GetTexture::installation texture pour obj %d\n", j); #endif textab[j].context_count = 0; textab[j].context_size = 0; textab[j].number = NULL; textab[j].drawable = NULL; textab[j].context = NULL; textab[j].use_bind_texture = NULL; textab[j].data = i; textab[j].status = TEX_ALLOCATED; texdata[i].share_count++; SetTextureDefaultParams(j); #ifdef PRINT printf("GetTexture::texture %s(%d) texture %d count=%d\n", texdata[i].imageFileName, i, j, texdata[i].share_count); #endif } else if (texdata[i].share_count != 0) free(texdata[i].image); return j; } /*----------------------------------------------------------------------*/ static TextureID GetTextureData(char *FileName, texDataStatus status, const GLint width, const GLint height, const void *data) { TextureDataID i; TextureID j; /* essait de trouver la texture */ i = FindTextureData(FileName); if (i == TEXTUREDATA_ERROR) { #ifdef PRINT printf("GetTextureData::la texture %s n'existe pas => chargement\n", FileName); #endif /* creation d'une texture */ i = FindFreeTextureData(); if (i == TEXTUREDATA_ERROR) return TEXTUREBOX_ERROR; texdata[i].share_count = 0; strcpy(texdata[i].imageFileName, FileName); texdata[i].image = (GLubyte *)malloc(width*height*4*sizeof(GLubyte)); memcpy(texdata[i].image, data, (width*height*4)); texdata[i].imageWidth = width; texdata[i].imageHeight = height; if (texdata[i].image == NULL) return TEXTUREBOX_ERROR; texdata[i].status = status; texdata[i].type = status2type[status]; } j = FindFreeTexture(); if (j != TEXTUREBOX_ERROR) { #ifdef PRINT printf("GetTextureData::installation texture pour obj %d\n", j); #endif textab[j].context_count = 0; textab[j].context_size = 0; textab[j].number = NULL; textab[j].drawable = NULL; textab[j].context = NULL; textab[j].use_bind_texture = NULL; textab[j].data = i; textab[j].status = TEX_ALLOCATED; texdata[i].share_count++; SetTextureDefaultParams(j); #ifdef PRINT printf("GetTextureData::texture %s(%d) texture %d count=%d\n", texdata[i].imageFileName, i, j, texdata[i].share_count); #endif } else if (texdata[i].share_count != 0) free(texdata[i].image); return j; } /*----------------------------------------------------------------------*/ /* * Fonctions publiques */ /*----------------------------------------------------------------------*/ GLboolean IsTextureValid(TextureID ID) { if ((ID<0) | (ID>=textures_count)) return GL_FALSE; if (textab) return textab[ID].status == TEX_ALLOCATED; else return GL_TRUE; } /*----------------------------------------------------------------------*/ TextureID GetTexture1D(char *FileName) { #ifdef PRINT printf("GetTexture1D::loading 1d %s \n", FileName); #endif return GetTexture(FileName, TEXDATA_1D); } /*----------------------------------------------------------------------*/ TextureID GetTexture2D(char *FileName) { #ifdef PRINT printf("GetTexture2D::loading 2d %s \n", FileName); #endif return GetTexture(FileName, TEXDATA_2D); } /*----------------------------------------------------------------------*/ TextureID GetTexture2DMipMap(char *FileName) { #ifdef PRINT printf("GetTexture2DMipMap::loading 2dmm %s \n", FileName); #endif return GetTexture(FileName, TEXDATA_2DMM); } /*----------------------------------------------------------------------*/ TextureID GetTextureData1D(char *FileName, const GLint width, const GLint height, const void *data) { #ifdef PRINT printf("GetTextureData1D::loading 1d %s \n", FileName); #endif return GetTextureData(FileName, TEXDATA_1D, width, height, data); } /*----------------------------------------------------------------------*/ TextureID GetTextureData2D(char *FileName, const GLint width, const GLint height, const void *data) { #ifdef PRINT printf("GetTextureData2D::loading 2d %s \n", FileName); #endif return GetTextureData(FileName, TEXDATA_2D, width, height, data); } /*----------------------------------------------------------------------*/ TextureID GetTextureData2DMipMap(char *FileName, const GLint width, const GLint height, const void *data) { #ifdef PRINT printf("GetTextureData2DMipMap::loading 2dmm %s \n", FileName); #endif return GetTextureData(FileName, TEXDATA_2DMM, width, height, data); } /*----------------------------------------------------------------------*/ void SetCurrentTexture(TextureID ID) { int context; if (!IsTextureValid(ID)) return; context = FindTextureContext(ID); /* la texture n'existe pas dans ce contexte */ if (context == TEXTUREBOX_ERROR) { #ifdef PRINT printf("SetCurrentTexture::installation texture %d dans context\n", ID); #endif /* si on a une erreur pendant l'installation dans le context * alors on installe la texture sans bind */ if (InstallTextureInContext(ID) == TEXTUREBOX_ERROR) { LoadTexture(ID); SetTextureParam(ID); } } /*oui, alors on bind directement */ else { #ifdef PRINT printf("SetCurrentTexture: utilisation du bind %d\n", ID); #endif MyBindTextureEXT(ID, context); SetTextureParam(ID); } current_texture = ID; current_texture_data = textab[ID].data; } /*----------------------------------------------------------------------*/ void FreeTexture(TextureID ID) { TextureDataID data; bool notResource = false; // if there old-style texture deletion GLCONTEXT cur_context; GLDRAWABLE cur_drawable; int i; if (!IsTextureValid(ID)) return; data = textab[ID].data; texdata[data].share_count--; if (texdata[data].share_count == 0) { // liberation des datas de la textures free(texdata[data].image); // liberation de la texture dans tous les contextes cur_drawable = GET_GLDEV_CONTEXT(); for (i = 0; i < textab[ID].context_count; ++i) { cur_context = 0; bool isResource = false; if (textab[ID].use_bind_texture[i]) { if( !OpenGl_ResourceCleaner::GetInstance()->AddResource(textab[ID].context[i], new OpenGl_ResourceTexture(textab[ID].number[i])) ) { GL_MAKE_CURRENT((openglDisplay.IsNull() ? (Display* )NULL : (Display* )openglDisplay->GetDisplay()), textab[ID].drawable[i], textab[ID].context[i]); // This check has been added to avoid exception, // which is raised when trying to delete textures when no rendering context is available cur_context = GET_GL_CONTEXT(); if (cur_context) glDeleteTextures (1, &textab[ID].number[i]); notResource = true; } else { isResource = true; } } if( !isResource && cur_context ) glFinish(); } if( notResource ) GL_MAKE_CURRENT((openglDisplay.IsNull() ? (Display* )NULL : (Display* )openglDisplay->GetDisplay()), cur_drawable, cur_context); texdata[data].status = TEXDATA_NONE; if (data + 1 == textures_data_count) { --textures_data_count; } free(textab[ID].context); free(textab[ID].drawable); free(textab[ID].use_bind_texture); free(textab[ID].number); } textab[ID].status = TEX_NONE; if (ID + 1 == textures_count) { --textures_count; } current_texture_data = TEXTUREDATA_ERROR; } /*----------------------------------------------------------------------*/ void EnableTexture(void) { if (!IsTextureValid(current_texture)) return; switch (texdata[current_texture_data].status) { case TEXDATA_1D: if (textab[current_texture].Gen != GL_NONE) glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_1D); break; case TEXDATA_2D: case TEXDATA_2DMM: if (textab[current_texture].Gen != GL_NONE) { glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); } glEnable(GL_TEXTURE_2D); break; default: break; } } /*----------------------------------------------------------------------*/ void DisableTexture(void) { if ( !IsTextureEnabled() ) return; if ( !IsTextureValid( current_texture ) ) return; switch (texdata[current_texture_data].status) { case TEXDATA_1D: if (textab[current_texture].Gen != GL_NONE) glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_1D); break; case TEXDATA_2D: case TEXDATA_2DMM: if (textab[current_texture].Gen != GL_NONE) { glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); } glDisable(GL_TEXTURE_2D); break; default: break; } } /*----------------------------------------------------------------------*/ GLboolean IsTextureEnabled(void) { GLboolean isEnabled1D= GL_FALSE, isEnabled2D= GL_FALSE; glGetBooleanv( GL_TEXTURE_1D, &isEnabled1D ); glGetBooleanv( GL_TEXTURE_2D, &isEnabled2D ); return isEnabled1D || isEnabled2D; } /*----------------------------------------------------------------------*/ void SetTextureModulate(TextureID ID) { if (!IsTextureValid(ID)) return; textab[ID].Light = GL_MODULATE; } /*----------------------------------------------------------------------*/ void SetTextureDecal(TextureID ID) { if (!IsTextureValid(ID)) return; textab[ID].Light = GL_DECAL; } /*----------------------------------------------------------------------*/ void SetTextureClamp(TextureID ID) { if (!IsTextureValid(ID)) return; textab[ID].Wrap = GL_CLAMP; } /*----------------------------------------------------------------------*/ void SetTextureRepeat(TextureID ID) { if (!IsTextureValid(ID)) return; textab[ID].Wrap = GL_REPEAT; } /*----------------------------------------------------------------------*/ /* gestion de la facon d'appliquer la texture */ void SetModeObject(TextureID ID, const GLfloat sparams[4], const GLfloat tparams[4]) { if (!IsTextureValid(ID)) return; textab[ID].Gen = GL_OBJECT_LINEAR; if (sparams != NULL) memcpy(textab[ID].Plane1, sparams, sizeof(sgenparams)); else memcpy(textab[ID].Plane1, sgenparams, sizeof(sgenparams)); if (texdata[textab[ID].data].status != TEXDATA_1D) { if (tparams != NULL) memcpy(textab[ID].Plane2, tparams, sizeof(tgenparams)); else memcpy(textab[ID].Plane2, tgenparams, sizeof(tgenparams)); } } /*----------------------------------------------------------------------*/ void SetModeSphere(TextureID ID) { if (!IsTextureValid(ID)) return; textab[ID].Gen = GL_SPHERE_MAP; } /*----------------------------------------------------------------------*/ void SetModeEye(TextureID ID, const GLfloat sparams[4], const GLfloat tparams[4]) { if (!IsTextureValid(ID)) return; textab[ID].Gen = GL_EYE_LINEAR; if (sparams != NULL) memcpy(textab[ID].Plane1, sparams, sizeof(sgenparams)); else memcpy(textab[ID].Plane1, sgenparams, sizeof(sgenparams)); if (texdata[textab[ID].data].status != TEXDATA_1D) { if (tparams != NULL) memcpy(textab[ID].Plane2, tparams, sizeof(tgenparams)); else memcpy(textab[ID].Plane2, tgenparams, sizeof(tgenparams)); } } /*----------------------------------------------------------------------*/ void SetModeManual(TextureID ID) { if (!IsTextureValid(ID)) return; textab[ID].Gen = GL_NONE; } /*----------------------------------------------------------------------*/ void SetRenderNearest(TextureID ID) { if (!IsTextureValid(ID)) return; textab[ID].Render = GL_NEAREST; } /*----------------------------------------------------------------------*/ void SetRenderLinear(TextureID ID) { if (!IsTextureValid(ID)) return; textab[ID].Render = GL_LINEAR; } /*----------------------------------------------------------------------*/ void SetTexturePosition(TextureID ID, GLfloat scalex, GLfloat scaley, GLfloat transx, GLfloat transy, GLfloat angle) { textab[ID].scalex = scalex; textab[ID].scaley = scaley; textab[ID].transx = transx; textab[ID].transy = transy; textab[ID].angle = angle; } /*----------------------------------------------------------------------*/ void SetTextureDefaultParams(TextureID ID) { if (!IsTextureValid(ID)) return; #ifdef PRINT printf("SetTextureDefaultParams::set parm par defaut textures\n"); #endif textab[ID].scalex = 1.0; textab[ID].scaley = 1.0; textab[ID].transx = 0.0; textab[ID].transy = 0.0; textab[ID].angle = 0.0; textab[ID].Gen = GL_OBJECT_LINEAR; textab[ID].Light = texdata[textab[ID].data].status == TEXDATA_1D ? GL_DECAL : GL_MODULATE; textab[ID].Wrap = texdata[textab[ID].data].status == TEXDATA_1D ? GL_CLAMP : GL_REPEAT; memcpy(textab[ID].Plane1, sgenparams, sizeof(sgenparams)); memcpy(textab[ID].Plane2, tgenparams, sizeof(tgenparams)); textab[ID].Render = texdata[textab[ID].data].status == TEXDATA_1D ? GL_NEAREST : GL_LINEAR; } /*----------------------------------------------------------------------*/ /* Transfere de donnee des donnees internes a la structure TransferData */ void TransferTexture_To_Data(TextureID ID, TextureData *TransfDt) { /* affectations */ strcpy(TransfDt->path, texdata[textab[ID].data].imageFileName); TransfDt->gen = textab[ID].Gen; TransfDt->wrap = textab[ID].Wrap; TransfDt->render = textab[ID].Light; TransfDt->scalex = textab[ID].scalex; TransfDt->scaley = textab[ID].scaley; TransfDt->transx = textab[ID].transx; TransfDt->transy = textab[ID].transy; TransfDt->angle = textab[ID].angle; memcpy(TransfDt->plane1, textab[ID].Plane1, sizeof(SizeType)); memcpy(TransfDt->plane2, textab[ID].Plane2, sizeof(SizeType)); } /*----------------------------------------------------------------------*/ /* Transfere de donnee de la structure TransferData aux donnees internes */ void TransferData_To_Texture(TextureData *TransfDt, TextureID *newID) { TextureID ID; /* Affectations */ FreeTexture(*newID); ID = GetTexture2DMipMap(TransfDt->path); if(IsTextureValid(ID)) { /* Affectation de l id courant */ *newID = ID; /* Donnees concernant les caracteristiques de la texture */ strcpy(texdata[textab[ID].data].imageFileName, TransfDt->path); textab[ID].Gen = TransfDt->gen; textab[ID].Wrap = TransfDt->wrap; textab[ID].Light = TransfDt->render; textab[ID].scalex = TransfDt->scalex; textab[ID].scaley = TransfDt->scaley; textab[ID].transx = TransfDt->transx; textab[ID].transy = TransfDt->transy; textab[ID].angle = TransfDt->angle; memcpy(textab[ID].Plane1, TransfDt->plane1, sizeof(SizeType)); memcpy(textab[ID].Plane2, TransfDt->plane2, sizeof(SizeType)); } }