bool Texture::Actual::createTile( SDL_Surface const* surface, int tileX, int tileY, int tileWidth, int tileHeight ) { // debug checks if ( _filename.compare( "" ) != 0 ) { cerr << "*** Texture::Actual::createTile() over (" << _filename << ") refused." << endl; return false; } _filename = "a tile"; _width = tileWidth; _height = tileHeight; _hasAlpha = true; // The raw data of the source image. unsigned char * data = ( unsigned char * ) ( surface->pixels ); // The destination image (a single tile) std::vector<GLubyte> image( tileWidth * tileHeight * 4 ); int count = 0; // where the tile starts in a line int offs = tileX * tileWidth * 4; // where the tile ends in a line int rest = ( tileX + 1 ) * tileWidth * 4; // Current position in the source data int c = offs + ( tileY * tileHeight * surface->pitch ); // the following lines extract R,G and B values from any bitmap for ( int i = 0; i < tileWidth * tileHeight; ++i ) { if ( i > 0 && i % tileWidth == 0 ) { // skip the rest of the line c += ( surface->pitch - rest ); // skip the offset (go to where the tile starts) c += offs; } for ( int p = 0; p < 4; p++ ) { image[count++] = data[c++]; } } Preferences *prefs = Session::instance->getPreferences(); // Create The Texture glGenTextures( 1, &_id ); // Typical Texture Generation Using Data From The Bitmap glBindTexture( GL_TEXTURE_2D, _id ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); gluBuild2DMipmaps( GL_TEXTURE_2D, ( prefs->getBpp() > 16 ? GL_RGBA : GL_RGBA4 ), tileWidth, tileHeight, GL_RGBA, GL_UNSIGNED_BYTE, &image[0] ); assert( _id != INVALID && _id != INPROGRESS ); _isComplete = true; return true; }
GLuint Texture::saveAreaUnder( int x, int y, int w, int h, GLuint *tex ) { // Copy to a texture the original image glLoadIdentity(); glsEnable( GLS_TEXTURE_2D ); GLuint background; if( !tex || *tex == 0 ) { glGenTextures( 1, &background ); } else { background = *tex; } std::vector<unsigned char*> backgroundInMem( w * h * 4 ); glBindTexture( GL_TEXTURE_2D, background ); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); 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_WRAP_S, GL_CLAMP ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); Preferences *prefs = Session::instance->getPreferences(); glTexImage2D( GL_TEXTURE_2D, 0, ( prefs->getBpp() > 16 ? GL_RGBA : GL_RGBA4 ), w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, &backgroundInMem[0] ); glBindTexture( GL_TEXTURE_2D, background ); glCopyTexSubImage2D( GL_TEXTURE_2D, 0, // MIPMAP level 0, // x texture offset 0, // y texture offset 0, // x window coordinates Session::instance->getGameAdapter()->getScreenHeight() - h, // y window coordinates w, // width h // height ); return background; }
bool Texture::Actual::letsToBind() { if ( _isComplete ) return true; if ( _id == INVALID ) return false; if ( _width == -1 && !loadImage() ) { clear(); return false; } assert( _surface != NULL ); Preferences *prefs = Session::instance->getPreferences(); GLuint destFormat; GLuint srcFormat; GLuint minFilter; GLuint magFilter; if ( _hasAlpha ) { srcFormat = GL_RGBA; destFormat = ( prefs->getBpp() > 16 ? GL_RGBA : GL_RGBA4 ); minFilter = ( _isSprite ? GL_LINEAR : ( prefs->getBpp() > 16 ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST ) ); magFilter = GL_LINEAR; } else { srcFormat = GL_RGB; destFormat = ( prefs->getBpp() > 16 ? GL_RGB : GL_RGB5 ); minFilter = GL_LINEAR_MIPMAP_LINEAR; magFilter = prefs->getBpp() > 16 ? GL_LINEAR : GL_NEAREST; } glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ); glGenTextures( 1, &_id ); glBindTexture( GL_TEXTURE_2D, _id ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter ); // Enable anisotropic filtering if requested, mipmapping is enabled // and the hardware supports it. if ( _wantsAnisotropy && !_hasAlpha && strstr( ( char* )glGetString( GL_EXTENSIONS ), "GL_EXT_texture_filter_anisotropic" ) && prefs->getAnisoFilter() ) { float maxAnisotropy; glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAnisotropy ); } else { glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f ); } // lordthoran said glTexImage2D causes white textures // glTexImage2D( GL_TEXTURE_2D, 0, destFormat, _width, _height, 0, srcFormat, GL_UNSIGNED_BYTE, surface->pixels ); gluBuild2DMipmaps( GL_TEXTURE_2D, destFormat, _width, _height, srcFormat, GL_UNSIGNED_BYTE, _surface->pixels ); unloadImage(); if ( _priority > 0 ) glPrioritizeTextures( 1, &_id, &_priority ); assert( _id != INVALID && _id != INPROGRESS ); _isComplete = true; return true; }
bool Texture::Actual::createAlpha( Actual* alpha, Actual* sample[], int sampleCount, int textureSizeW, int textureSizeH, int width, int height ) { // debug checks if ( _filename.compare( "" ) != 0 ) { cerr << "*** Texture::Actual::createAlpha() over (" << _filename << ") refused." << endl; return false; } if ( alpha == NULL || !alpha->letsToBind() ) { cerr << "*** Texture::Actual::createAlpha() with missing alpha texture." << endl; return false; } for( int i = 0; i < sampleCount; i++ ) { if ( sample[i] == NULL || !sample[i]->letsToBind() ) { cerr << "*** Texture::Actual::createAlpha() with missing sample texture. i=" << i << endl; return false; } } Preferences *prefs = Session::instance->getPreferences(); GLuint background = saveAreaUnder( 0, 0, textureSizeW, textureSizeH ); _filename = ""; for( int i = 0; i < sampleCount; i++ ) { if( i > 0 ) _filename += ","; _filename += sample[i]->_filename; } _filename += " with added alpha"; _width = width; _height = height; _hasAlpha = true; std::vector<unsigned char*> texInMem( textureSizeW * textureSizeH * 4 ); //GLuint tex[1]; glsDisable( GLS_CULL_FACE | GLS_DEPTH_TEST ); glsEnable( GLS_TEXTURE_2D ); glGenTextures( 1, &_id ); glBindTexture( GL_TEXTURE_2D, _id ); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); /** * This method should not create mip-maps. They don't work well with alpha-tested textures and cause flickering. */ //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, isSprite ? GL_NEAREST : GL_LINEAR_MIPMAP_NEAREST ); 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_WRAP_S, GL_CLAMP ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); glTexImage2D( GL_TEXTURE_2D, 0, ( prefs->getBpp() > 16 ? GL_RGBA : GL_RGBA4 ), textureSizeW, textureSizeH, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texInMem[0] ); //if( !isSprite ) gluBuild2DMipmaps(GL_TEXTURE_2D, 4, textureSizeW, textureSizeH, GL_BGRA, GL_UNSIGNED_BYTE, texInMem); glPushMatrix(); glLoadIdentity(); glsDisable( GLS_TEXTURE_2D ); glColor4f( 0.0f, 0.0f, 0.0f, 0.0f ); glBegin( GL_TRIANGLE_STRIP ); glVertex2i( 0, 0 ); glVertex2i( textureSizeW, 0 ); glVertex2i( 0, textureSizeH ); glVertex2i( textureSizeW, textureSizeH ); glEnd(); glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); // draw the grass glsEnable( GLS_TEXTURE_2D ); for( int i = 0; i < sampleCount; i++ ) { glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); drawQuad( sample[i]->_id, width, height ); } // draw the alpha pixels only glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE ); glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); drawQuad( alpha->_id, width, height ); glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); // Copy to a texture glLoadIdentity(); glsEnable( GLS_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, _id ); glCopyTexSubImage2D( GL_TEXTURE_2D, 0, // MIPMAP level 0, // x texture offset 0, // y texture offset 0, // x window coordinates Session::instance->getGameAdapter()->getScreenHeight() - textureSizeH, // y window coordinates textureSizeW, // width textureSizeH // height ); // cover with the original drawQuad( background, width, height ); glPopMatrix(); glDeleteTextures( 1, &background ); glsDisable( GLS_BLEND ); glsEnable( GLS_CULL_FACE | GLS_DEPTH_TEST ); assert( _id != INVALID && _id != INPROGRESS ); _isComplete = true; return true; }
bool Texture::Actual::createEdgeBlended( const string& path, Actual* original, Actual* west, Actual* east, Actual* south, Actual* north, Actual* edge, Actual* corner, Actual* tip, Actual* hole ) { // debug checks if ( original == NULL || !original->letsToBind() ) { cerr << "*** Texture::Actual::createEdgeBlended() with missing original texture." << endl; return false; } if ( west == NULL || !west->letsToBind() ) { // cerr << "*** Texture::Actual::createEdgeBlended() with missing west texture." << endl; // return false; } if ( east == NULL || !east->letsToBind() ) { // cerr << "*** Texture::Actual::createEdgeBlended() with missing east texture." << endl; // return false; } if ( south == NULL || !south->letsToBind() ) { // cerr << "*** Texture::Actual::createEdgeBlended() with missing south texture." << endl; // return false; } if ( north == NULL || !north->letsToBind() ) { // cerr << "*** Texture::Actual::createEdgeBlended() with missing north texture." << endl; // return false; } if ( edge == NULL || !edge->letsToBind() ) { cerr << "*** Texture::Actual::createEdgeBlended() with missing edge texture." << endl; return false; } if ( corner == NULL || !corner->letsToBind() ) { cerr << "*** Texture::Actual::createEdgeBlended() with missing corner texture." << endl; return false; } if ( tip == NULL || !tip->letsToBind() ) { cerr << "*** Texture::Actual::createEdgeBlended() with missing tip texture." << endl; return false; } if ( hole == NULL || !hole->letsToBind() ) { cerr << "*** Texture::Actual::createEdgeBlended() with missing hole texture:" << hole->_filename << endl; return false; } _filename = path; Preferences *prefs = Session::instance->getPreferences(); int textureSizeW = 256; int textureSizeH = 256; // cerr << "creating blended edge: " << _filename << endl; _width = textureSizeW; _height = textureSizeH; _isSprite = original->_isSprite; _wantsAnisotropy = original->_wantsAnisotropy; _hasAlpha = true; std::vector<unsigned char*> texInMem( textureSizeW * textureSizeH * 4 ); glGenTextures( 1, &_id ); glBindTexture( GL_TEXTURE_2D, _id ); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexImage2D( GL_TEXTURE_2D, 0, ( prefs->getBpp() > 16 ? GL_RGBA : GL_RGBA4 ), textureSizeW, textureSizeH, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texInMem[0] ); glPushMatrix(); GLuint background = saveAreaUnder( 0, 0, textureSizeW, textureSizeH ); // create a tmp alpha texture vector<float> angles; vector<Actual*> tmps; // cerr << "n=" << north->_id << " w=" << west->_id << " e=" << east->_id << " s=" << south->_id << endl; bool n = false; bool w = false; bool e = false; bool s = false; if( !north->matches( original ) && north->matches( east ) && north->matches( south ) && north->matches( west ) ) { Actual *tmp2 = new Actual; tmp2->createAlpha( hole, &north, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 0.0f ); n = e = s = w = true; // cerr << "\thole" << endl; } else if( !north->matches( original ) && north->matches( east ) && north->matches( south ) ) { Actual *tmp2 = new Actual; tmp2->createAlpha( tip, &north, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 90.0f ); n = e = s = true; // cerr << "\ttip 1" << endl; } else if( !east->matches( original ) && east->matches( south ) && east->matches( west ) ) { Actual *tmp2 = new Actual; tmp2->createAlpha( tip, &east, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 0.0f ); e = s = w = true; // cerr << "\ttip 2" << endl; } else if( !south->matches( original ) && south->matches( west ) && south->matches( north ) ) { Actual *tmp2 = new Actual; tmp2->createAlpha( tip, &south, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 270.0f ); s = w = n = true; // cerr << "\ttip 3" << endl; } else if( !west->matches( original ) && west->matches( north ) && west->matches( east ) ) { Actual *tmp2 = new Actual; tmp2->createAlpha( tip, &west, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 180.0f ); w = n = e = true; // cerr << "\ttip 4" << endl; } else { if( !north->matches( original ) && north->matches( east ) ) { Actual *tmp2 = new Actual; tmp2->createAlpha( corner, &north, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 180.0f ); n = e = true; // cerr << "\tcorner 1" << endl; } if( !east->matches( original ) && east->matches( south ) ) { Actual *tmp2 = new Actual; tmp2->createAlpha( corner, &east, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 90.0f ); e = s = true; // cerr << "\tcorner 2" << endl; } if( !south->matches( original ) && south->matches( west ) ) { Actual *tmp2 = new Actual; tmp2->createAlpha( corner, &south, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 0.0f ); s = w = true; // cerr << "\tcorner 3" << endl; } if( !west->matches( original ) && west->matches( north ) ) { Actual *tmp2 = new Actual; tmp2->createAlpha( corner, &west, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 270.0f ); w = n = true; // cerr << "\tcorner 4" << endl; } } if( !n && !north->matches( original ) && north->_id != INVALID ) { Actual *tmp2 = new Actual; tmp2->createAlpha( edge, &north, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 270.0f ); // cerr << "\tedge 1" << endl; } if( !w && !west->matches( original ) && west->_id != INVALID ) { Actual *tmp2 = new Actual; tmp2->createAlpha( edge, &west, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 0.0f ); // cerr << "\tedge 2" << endl; } if( !e && !east->matches( original ) && east->_id != INVALID ) { Actual *tmp2 = new Actual; tmp2->createAlpha( edge, &east, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 180.0f ); // cerr << "\tedge 3" << endl; } if( !s && !south->matches( original ) && south->_id != INVALID ) { Actual *tmp2 = new Actual; tmp2->createAlpha( edge, &south, 1, _width, _height, _width, _height ); tmps.push_back( tmp2 ); angles.push_back( 90.0f ); // cerr << "\tedge 4" << endl; } glsDisable( GLS_BLEND | GLS_DEPTH_TEST | GLS_CULL_FACE ); glsEnable( GLS_TEXTURE_2D ); glLoadIdentity(); glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); // draw the original drawQuad( original->_id, _width, _height ); // blend in the tmp glsDisable( GLS_DEPTH_MASK ); glsEnable( GLS_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); for( unsigned int i = 0; i < tmps.size(); i++ ) { glPushMatrix(); glLoadIdentity(); glTranslatef( _width / 2.0f, _height / 2.0f, 0.0f ); glRotatef( angles[i], 0.0f, 0.0f, 1.0f ); glTranslatef( -_width / 2.0f, -_height / 2.0f, 0.0f ); drawQuad( tmps[i]->_id, _width, _height ); glPopMatrix(); } glsDisable( GLS_BLEND ); glsEnable( GLS_TEXTURE_2D | GLS_DEPTH_MASK ); // Copy to a texture glLoadIdentity(); glBindTexture( GL_TEXTURE_2D, _id ); glCopyTexSubImage2D( GL_TEXTURE_2D, 0, // MIPMAP level 0, // x texture offset 0, // y texture offset 0, // x window coordinates Session::instance->getGameAdapter()->getScreenHeight() - textureSizeH, // y window coordinates textureSizeW, // width textureSizeH // height ); // delete the tmps for( unsigned int i = 0; i < tmps.size(); i++ ) { delete tmps[i]; } // cover with the original drawQuad( background, _width, _height ); glPopMatrix(); glDeleteTextures( 1, &background ); glsDisable( GLS_BLEND ); glsEnable( GLS_CULL_FACE | GLS_DEPTH_TEST ); assert( _id != INVALID && _id != INPROGRESS ); _isComplete = true; return true; }