Texture.h
#ifndef DRAWING_H#define DRAWING_H#include <SDL/SDL.h>#include <SDL/SDL_image.h>#include <GL/gl.h>#include <string>namespace LGC {// ===============================================================================// This stores a rectangle. As a template, you can use any kind of number typetemplate< class TYPE > class AreaRect {public: TYPE x1; TYPE y1; TYPE x2; TYPE y2; AreaRect( TYPE x, TYPE y, TYPE x2, TYPE y2 ): x1(x), y1(y), x2(x2), y2(y2) {} AreaRect(): x1(0), y1(0), x2(0), y2(0) {} inline TYPE Width() { return x2 - x1; } inline TYPE Height() { return y2 - y1; } inline bool Valid() { return !(!x1 && !x2 && !y1 && !y2); } inline AreaRect<TYPE>& operator /= (const AreaRect<TYPE>& r) { x1 / r.x1; x2 / r.x2; y1 / r.y1; y2 / r.y2; return *this; } inline AreaRect<TYPE>& operator += (const AreaRect<TYPE>& r) { x1 + r.x1; x2 + r.x2; y1 + r.y1; y2 + r.y2; return *this; } inline AreaRect<TYPE>& operator -= (const AreaRect<TYPE>& r) { x1 - r.x1; x2 - r.x2; y1 - r.y1; y2 - r.y2; return *this; } inline AreaRect<TYPE>& operator *= (const AreaRect<TYPE>& r) { x1 * r.x1; x2 * r.x2; y1 * r.y1; y2 * r.y2; return *this; } inline AreaRect<TYPE> operator / (const AreaRect<TYPE>& r) { return AreaRect<TYPE> ( x1 / r.x1, x2 / r.x2, y1 / r.y1, y2 / r.y2 ); } inline AreaRect<TYPE> operator + (const AreaRect<TYPE>& r) { return AreaRect<TYPE> ( x1 + r.x1, x2 + r.x2, y1 + r.y1, y2 + r.y2 ); } inline AreaRect<TYPE> operator - (const AreaRect<TYPE>& r) { return AreaRect<TYPE> ( x1 - r.x1, x2 - r.x2, y1 - r.y1, y2 - r.y2 ); } inline AreaRect<TYPE> operator * (const AreaRect<TYPE>& r) { return AreaRect<TYPE> ( x1 * r.x1, x2 * r.x2, y1 * r.y1, y2 * r.y2 ); } inline bool operator == (const AreaRect<TYPE>& r) { return ( x1 == r.x1 && x2 == r.x2 && y1 == r.y1 && y2 == r.y2 ); } }; // ===============================================================================enum BlendMode { BLEND_NORMAL, BLEND_NONE, BLEND_ADD, BLEND_SUBTRACT }; // ===============================================================================class Texture {public: Texture( std::string name, int texture_id, AreaRect<int>& texture_coords, AreaRect<int>& area_coords ) : name(name), id (texture_id), pixels(area_coords) { ratios.x1 = float(area_coords.x1) / float(texture_coords.x2); ratios.x2 = float(area_coords.x2) / float(texture_coords.x2); ratios.y1 = float(area_coords.y1) / float(texture_coords.y2); ratios.y2 = float(area_coords.y2) / float(texture_coords.y2); is_tilable = ( area_coords == texture_coords ); } Texture() : name("NO_HANDLE"), id(0), pixels(AreaRect<int>()), ratios(AreaRect<float>()), is_tilable(false) {} ~Texture() {}; // allows textures to draw correctly with roto/zoom static void SetScreenOffset( float x, float y ) { screen_x = x; screen_y = y; } // Drawing void Blit ( float x, float y, BlendMode blend=BLEND_NORMAL ); void BlitFromCenter ( float x, float y, BlendMode blend=BLEND_NORMAL ); void BlitFlip ( float x, float y, bool flip_horz=false, bool flip_vert=false, BlendMode blend=BLEND_NORMAL ); void BlitFlipFromCenter ( float x, float y, bool flip_horz=false, bool flip_vert=false, BlendMode blend=BLEND_NORMAL ); void BlitRotoZoom ( float x, float y, float rot, float scale=1.0, BlendMode blend=BLEND_NORMAL ); void BlitRotoZoomFromCenter ( float x, float y, float rot, float scale=1.0, BlendMode blend=BLEND_NORMAL ); void BlitRotoZoomFlip ( float x, float y, float rot, float scale=1.0, bool flip_horz=false, bool flip_vert=false, BlendMode blend=BLEND_NORMAL ); void BlitRotoZoomFlipFromCenter ( float x, float y, float rot, float scale=1.0, bool flip_horz=false, bool flip_vert=false, BlendMode blend=BLEND_NORMAL ); void BlitCustomStretch ( float x, float y, float w, float h, BlendMode blend=BLEND_NORMAL ); void TileAcross ( float x, float y, float w, float h, BlendMode blend=BLEND_NORMAL ); void TileAcrossWithOffset ( float x, float y, float w, float h, float xoff, float yoff, BlendMode blend=BLEND_NORMAL ); // Note: "offset" is a ratio of the texture. 0.5 offsets 50% into the texture. // setters inline void SetID( GLuint x ) { id = x; } // Basic info inline int ID() { return id; } inline int Width() { return pixels.Width(); } inline int Height() { return pixels.Height(); } inline std::string Handle() const { return name; } inline AreaRect<int> GetPixels() { return pixels; } inline AreaRect<float> GetRatios() { return ratios; } inline bool IsTilable() { return is_tilable; } inline bool IsValid() { return ( id != 0 ); } // Get the texture coords as a ratio of the full texture inline float Left() { return ratios.x1; } inline float Top() { return ratios.y1; } inline float Right() { return ratios.x2; } inline float Bottom() { return ratios.y2; } // Get the texture coords as a pixel of the full texture inline float LeftPx() { return pixels.x1; } inline float TopPx() { return pixels.y1; } inline float RightPx() { return pixels.x2; } inline float BottomPx() { return pixels.y2; }private: std::string name; int id; // the actual opengl texture ID AreaRect<int> pixels; // a list of area coords for fast lookup AreaRect<float> ratios; // a list of area coords for fast lookup bool is_tilable; static BlendMode global_blend_mode; static void SwitchBlendMode(BlendMode blend); static float screen_x; static float screen_y; }; } // end namespace LGC #endif
Texture.cpp
#include "Texture.h"namespace LGC {BlendMode Texture::global_blend_mode = BLEND_NORMAL;float Texture::screen_x = 0;float Texture::screen_y = 0;void Texture::Blit( float x, float y, BlendMode blend ) { if (!id) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( Left(), Bottom() ); glVertex2f( x, y+Height() ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( Right(), Bottom() ); glVertex2f( x+Width(), y+Height() ); /* Top Right Of The Texture and Quad */ glTexCoord2f( Right(), Top() ); glVertex2f( x+Width(), y ); /* Top Left Of The Texture and Quad */ glTexCoord2f( Left(), Top() ); glVertex2f( x, y ); glEnd(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::BlitFromCenter( float x, float y, BlendMode blend ) { if (!id) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } float half_w = Width() * 0.5; float half_h = Height() * 0.5; glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( Left(), Bottom() ); glVertex2f( x-half_w, y+half_h ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( Right(), Bottom() ); glVertex2f( x+half_w, y+half_h ); /* Top Right Of The Texture and Quad */ glTexCoord2f( Right(), Top() ); glVertex2f( x+half_w, y-half_h ); /* Top Left Of The Texture and Quad */ glTexCoord2f( Left(), Top() ); glVertex2f( x-half_w, y-half_h ); glEnd(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::BlitFlip( float x, float y, bool flip_horz, bool flip_vert, BlendMode blend ) { if (!id) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } float left = (flip_horz) ? Right() : Left(); float right = (flip_horz) ? Left() : Right(); float bottom = (flip_vert) ? Top() : Bottom(); float top = (flip_vert) ? Bottom() : Top(); glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( left, bottom ); glVertex2f( x, y+Height() ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( right, bottom ); glVertex2f( x+Width(), y+Height() ); /* Top Right Of The Texture and Quad */ glTexCoord2f( right, top ); glVertex2f( x+Width(), y ); /* Top Left Of The Texture and Quad */ glTexCoord2f( left, top ); glVertex2f( x, y ); glEnd(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::BlitFlipFromCenter( float x, float y, bool flip_horz, bool flip_vert, BlendMode blend ) { if (!id) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } float half_w = Width() * 0.5; float half_h = Height() * 0.5; float left = (flip_horz) ? Right() : Left(); float right = (flip_horz) ? Left() : Right(); float bottom = (flip_vert) ? Top() : Bottom(); float top = (flip_vert) ? Bottom() : Top(); glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( left, bottom ); glVertex2f( x-half_w, y+half_h ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( right, bottom ); glVertex2f( x+half_w, y+half_h ); /* Top Right Of The Texture and Quad */ glTexCoord2f( right, top ); glVertex2f( x+half_w, y-half_h ); /* Top Left Of The Texture and Quad */ glTexCoord2f( left, top ); glVertex2f( x-half_w, y-half_h ); glEnd(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::BlitRotoZoom( float x, float y, float rot, float scale, BlendMode blend ) { if (!id) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } float adjust_x = Width() * scale; float adjust_y = Height() * scale; glPushMatrix(); glLoadIdentity(); // TRANSLATE FIRST, ROTOZOOM SECOND! glTranslatef( x - screen_x + adjust_x, y - screen_y + adjust_y, 0 ); if (scale != 1.0) { glScalef( scale, scale, 0); } if (rot) { glRotatef( rot, 0, 0, 1 ); } //glTranslatef( adjust_x, adjust_y, 0 ); glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( Left(), Bottom() ); glVertex2f( 0, Height() ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( Right(), Bottom() ); glVertex2f( Width(), Height() ); /* Top Right Of The Texture and Quad */ glTexCoord2f( Right(), Top() ); glVertex2f( Width(), 0 ); /* Top Left Of The Texture and Quad */ glTexCoord2f( Left(), Top() ); glVertex2f( 0, 0 ); glEnd(); glPopMatrix(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::BlitRotoZoomFromCenter( float x, float y, float rot, float scale, BlendMode blend ) { if (!id) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } glPushMatrix(); glLoadIdentity(); // TRANSLATE FIRST, ROTOZOOM SECOND! glTranslatef( x - screen_x, y - screen_y, 0 ); if (scale != 1.0) { glScalef( scale, scale, 0); } if (rot != 0.0) { glRotatef( rot, 0, 0, 1 ); } glTranslatef( -(Width() * 0.5), -(Height() * 0.5), 0 ); glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( Left(), Bottom() ); glVertex2f( 0, Height() ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( Right(), Bottom() ); glVertex2f( Width(), Height() ); /* Top Right Of The Texture and Quad */ glTexCoord2f( Right(), Top() ); glVertex2f( Width(), 0 ); /* Top Left Of The Texture and Quad */ glTexCoord2f( Left(), Top() ); glVertex2f( 0, 0 ); glEnd(); glPopMatrix(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::BlitRotoZoomFlip( float x, float y, float rot, float scale, bool flip_horz, bool flip_vert, BlendMode blend ) { if (!id) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } float adjust_x = Width() * scale; float adjust_y = Height() * scale; float left = (flip_horz) ? Right() : Left(); float right = (flip_horz) ? Left() : Right(); float bottom = (flip_vert) ? Top() : Bottom(); float top = (flip_vert) ? Bottom() : Top(); glPushMatrix(); glLoadIdentity(); // TRANSLATE FIRST, ROTOZOOM SECOND! glTranslatef( x - screen_x + adjust_x, y - screen_y + adjust_y, 0 ); if (scale != 1.0) { glScalef( scale, scale, 0); } if (rot) { glRotatef( rot, 0, 0, 1 ); } //glTranslatef( adjust_x, adjust_y, 0 ); glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( left, bottom ); glVertex2f( 0, Height() ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( right, bottom ); glVertex2f( Width(), Height() ); /* Top Right Of The Texture and Quad */ glTexCoord2f( right, top ); glVertex2f( Width(), 0 ); /* Top Left Of The Texture and Quad */ glTexCoord2f( left, top ); glVertex2f( 0, 0 ); glEnd(); glPopMatrix(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::BlitRotoZoomFlipFromCenter( float x, float y, float rot, float scale, bool flip_horz, bool flip_vert, BlendMode blend ) { if (!id) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } float left = (flip_horz) ? Right() : Left(); float right = (flip_horz) ? Left() : Right(); float bottom = (flip_vert) ? Top() : Bottom(); float top = (flip_vert) ? Bottom() : Top(); glPushMatrix(); glLoadIdentity(); // TRANSLATE FIRST, ROTOZOOM SECOND! glTranslatef( x - screen_x, y - screen_y, 0 ); if (scale != 1.0) { glScalef( scale, scale, 0); } if (rot != 0.0) { glRotatef( rot, 0, 0, 1 ); } glTranslatef( -(Width() * 0.5), -(Height() * 0.5), 0 ); glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( left, bottom ); glVertex2f( 0, Height() ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( right, bottom ); glVertex2f( Width(), Height() ); /* Top Right Of The Texture and Quad */ glTexCoord2f( right, top ); glVertex2f( Width(), 0 ); /* Top Left Of The Texture and Quad */ glTexCoord2f( left, top ); glVertex2f( 0, 0 ); glEnd(); glPopMatrix(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::BlitCustomStretch ( float x, float y, float w, float h, BlendMode blend) { if (!id) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( Left(), Bottom() ); glVertex2f( x, y+h ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( Right(), Bottom() ); glVertex2f( x+w, y+h ); /* Top Right Of The Texture and Quad */ glTexCoord2f( Right(), Top() ); glVertex2f( x+w, y ); /* Top Left Of The Texture and Quad */ glTexCoord2f( Left(), Top() ); glVertex2f( x, y ); glEnd(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::TileAcross( float x, float y, float w, float h, BlendMode blend ) { if ( !id || !is_tilable ) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } float x_ratio = w / (float)Width(); float y_ratio = h / (float)Height(); glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( 0, y_ratio ); glVertex2f( x, y+h ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( x_ratio, y_ratio ); glVertex2f( x+w, y+h ); /* Top Right Of The Texture and Quad */ glTexCoord2f( x_ratio, 0 ); glVertex2f( x+w, y ); /* Top Left Of The Texture and Quad */ glTexCoord2f( 0, 0 ); glVertex2f( x, y ); glEnd(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::TileAcrossWithOffset( float x, float y, float w, float h, float xoff, float yoff, BlendMode blend ) { if ( !id || !is_tilable ) { return; } glBindTexture( GL_TEXTURE_2D, id ); if ( blend != global_blend_mode ) { SwitchBlendMode( blend ); } float x_ratio = w / (float)Width(); float y_ratio = h / (float)Height(); glBegin(GL_QUADS); /* Bottom Left Of The Texture and Quad */ glTexCoord2f( xoff, y_ratio + yoff ); glVertex2f( x, y+h ); /* Bottom Right Of The Texture and Quad */ glTexCoord2f( x_ratio + xoff, y_ratio + yoff ); glVertex2f( x+w, y+h ); /* Top Right Of The Texture and Quad */ glTexCoord2f( x_ratio + xoff, yoff ); glVertex2f( x+w, y ); /* Top Left Of The Texture and Quad */ glTexCoord2f( xoff, yoff ); glVertex2f( x, y ); glEnd(); // FIXME if ( blend != BLEND_NORMAL ) { SwitchBlendMode( BLEND_NORMAL ); } } void Texture::SwitchBlendMode(BlendMode blend) { switch(blend) { case BLEND_NORMAL: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; case BLEND_NONE: glDisable(GL_BLEND); break; case BLEND_ADD: glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE); break; case BLEND_SUBTRACT: // TODO: NOT IMPLEMENTED YET glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; } global_blend_mode = blend; } } // end namespace LGC