Continuando nossa série de artigos traduzidos do site lazyfoo, veremos agora como renderizar uma cena para uma textura.
Para alguns efeitos, ser capaz de renderizar uma cena para uma textura se faz necessário. Aqui estaremos renderizando uma cena para uma textura para conseguir um efeito de cena giratória.
//Texture wrapper class class LTexture { public: //Initializes variables LTexture(); //Deallocates memory ~LTexture(); //Loads image at specified path bool loadFromFile( std::string path ); #ifdef _SDL_TTF_H //Creates image from font string bool loadFromRenderedText( std::string textureText, SDL_Color textColor ); #endif //Creates blank texture bool createBlank( int width, int height, SDL_TextureAccess = SDL_TEXTUREACCESS_STREAMING ); //Deallocates texture void free(); //Set color modulation void setColor( Uint8 red, Uint8 green, Uint8 blue ); //Set blending void setBlendMode( SDL_BlendMode blending ); //Set alpha modulation void setAlpha( Uint8 alpha ); //Renders texture at given point void render( int x, int y, SDL_Rect* clip = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE ); //Set self as render target void setAsRenderTarget(); //Gets image dimensions int getWidth(); int getHeight(); //Pixel manipulators bool lockTexture(); bool unlockTexture(); void* getPixels(); void copyPixels( void* pixels ); int getPitch(); Uint32 getPixel32( unsigned int x, unsigned int y ); private: //The actual hardware texture SDL_Texture* mTexture; void* mPixels; int mPitch; //Image dimensions int mWidth; int mHeight; };
Aqui adicionamos mais funcionalidade para a classe da textura. A função createBlank agora precisa de outro argumento que define como ela é acessada. Nós também temos uma função setAsRenderTarget que possibilita que possamos renderizar para essa textura.
bool LTexture::createBlank( int width, int height, SDL_TextureAccess access ) { //Create uninitialized texture mTexture = SDL_CreateTexture( gRenderer, SDL_PIXELFORMAT_RGBA8888, access, width, height ); if( mTexture == NULL ) { printf( "Unable to create blank texture! SDL Error: %s\n", SDL_GetError() ); } else { mWidth = width; mHeight = height; } return mTexture != NULL; }
Quando quisermos renderizar para uma textura precisamos configurar o acesso à essa textura como SDL_TEXTUREACCESS_TARGET, que é o motivo pelo qual essa função precisa de mais um argumento agora.
void LTexture::setAsRenderTarget() { //Make self render target SDL_SetRenderTarget( gRenderer, mTexture ); }
Para renderizar para um textura, temos que configurar o alvo da renderização, que é feito usando a função SDL_SetRenderTarget.
bool loadMedia() { //Loading success flag bool success = true; //Load texture target if( !gTargetTexture.createBlank( SCREEN_WIDTH, SCREEN_HEIGHT, SDL_TEXTUREACCESS_TARGET ) ) { printf( "Failed to create target texture!\n" ); success = false; } return success; }
Criamos nossa textura na função de carregamento de mídia.
//Main loop flag bool quit = false; //Event handler SDL_Event e; //Rotation variables double angle = 0; SDL_Point screenCenter = { SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 };
Nesse exemplo, iremos renderizar uma forma geométrica para a textura e girar essa textura no centro da tela. Por isso temos variáveis para ângulo de rotação e centro da tela.
//While application is running while( quit == false ) { //Handle events on queue while( SDL_PollEvent( &e ) != 0 ) { //User requests quit if( e.type == SDL_QUIT ) { quit = true; } } //rotate angle += 2; if( angle > 360 ) { angle -= 360; } //Set self as render target gTargetTexture.setAsRenderTarget(); //Clear screen SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF ); SDL_RenderClear( gRenderer ); //Render red filled quad SDL_Rect fillRect = { SCREEN_WIDTH / 4, SCREEN_HEIGHT / 4, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2 }; SDL_SetRenderDrawColor( gRenderer, 0xFF, 0x00, 0x00, 0xFF ); SDL_RenderFillRect( gRenderer, &fillRect ); //Render green outlined quad SDL_Rect outlineRect = { SCREEN_WIDTH / 6, SCREEN_HEIGHT / 6, SCREEN_WIDTH * 2 / 3, SCREEN_HEIGHT * 2 / 3 }; SDL_SetRenderDrawColor( gRenderer, 0x00, 0xFF, 0x00, 0xFF ); SDL_RenderDrawRect( gRenderer, &outlineRect ); //Draw blue horizontal line SDL_SetRenderDrawColor( gRenderer, 0x00, 0x00, 0xFF, 0xFF ); SDL_RenderDrawLine( gRenderer, 0, SCREEN_HEIGHT / 2, SCREEN_WIDTH, SCREEN_HEIGHT / 2 ); //Draw vertical line of yellow dots SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0x00, 0xFF ); for( int i = 0; i < SCREEN_HEIGHT; i += 4 ) { SDL_RenderDrawPoint( gRenderer, SCREEN_WIDTH / 2, i ); } //Reset render target SDL_SetRenderTarget( gRenderer, NULL ); //Show rendered to texture gTargetTexture.render( 0, 0, NULL, angle, &screenCenter ); //Update screen SDL_RenderPresent( gRenderer ); }
Em nosso loop principal, antes de fazermos quaisquer renderização, configuramos a textura alvo como target. Em seguida renderizamos nossa cena geométrica e quando tivermos terminado para a textura chamamos SDL_SetRenderTarget com uma textura NULL de forma que qualquer renderização posterior seja feita na tela. Com nossa cena renderizada para a textura, agora renderizamos a textura alvo na tela de acordo com o ângulo de rotação.
Baixe os arquivo de mídia e de código fonte desse artigo aqui.