rendered paste body/* SEL - Simple DirectMedia Layer Extension Library Copyright (C) 2002 Matej Knopp <knopp@users.sf.net> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include "../sel-config.h"#include "painter.h"#include "../base/surface.h"#include "../base/error.h"namespace SEL{//////////////////////////////////////////////////////////////////////////////////// EMPTY (to avoid crashing) drawing functions ////////////////////////////////////////////////////////////////////////////////////static voidputPixelInvalid (Surface *, Uint16, Uint16, Uint32){}static voiddrawHLineInvalid (Surface *, Uint16, Uint16, Uint16, Uint32){}static voiddrawVLineInvalid (Surface *, Uint16, Uint16, Uint16, Uint32){}static voiddrawLineInvalid (Surface *, Uint16, Uint16, Uint16, Uint16, Uint32){}GFXTable GFXInvalid = { putPixelInvalid, drawHLineInvalid, drawVLineInvalid, drawLineInvalid };#define __SET_PIXEL(bpp, pixelData, color) \ *(Uint##bpp*)pixelData = color;// anyone knows about something faster?#if SDL_BYTEORDER == SDL_BIG_ENDIAN# define __SET_PIXEL24(data, b1, b2, b3) \ data [0] = (b3); data [1] = (b2); data[2] = (b1);#else# define __SET_PIXEL24(data, b1, b2, b3) \ data [0] = (b1); data[1] = (b2); data[2] = (b3);#endif //////////////////////////////////////////////////////////////////////////////////// SOLID (not alpha blended) drawing functions ////////////////////////////////////////////////////////////////////////////////////static void putPixelSolid8 (Surface *surface, Uint16 x, Uint16 y, Uint32 color){ Uint8 *data = (Uint8*) surface->pixels () + y * surface->pitch () + x; __SET_PIXEL (8, data, color);}static void putPixelSolid16 (Surface *surface, Uint16 x, Uint16 y, Uint32 color){ Uint8 *data = (Uint8*) surface->pixels () + y * surface->pitch () + 2 * x; __SET_PIXEL (16, data, color);}static void putPixelSolid24 (Surface *surface, Uint16 x, Uint16 y, Uint32 color){ Uint8 *data = (Uint8*) surface->pixels () + y * surface->pitch () + 3 * x; __SET_PIXEL24 (data, color & 0xFF, (color >> 8) & 0xFF, (color >> 16) & 0xFF);}static void putPixelSolid32 (Surface *surface, Uint16 x, Uint16 y, Uint32 color){ Uint8 *data = (Uint8*) surface->pixels () + y * surface->pitch () + 4 * x; __SET_PIXEL (32, data, color);}static voiddrawHLineSolid8 (Surface *surface, Uint16 x, Uint16 y, Uint16 w, Uint32 color){ Uint8 *data = (Uint8*) surface->pixels () + y * surface->pitch () + x; while (w > 0) { __SET_PIXEL (8, data, color); ++data; --w; } }static voiddrawHLineSolid16 (Surface *surface, Uint16 x, Uint16 y, Uint16 w, Uint32 color){ Uint16 *data = (Uint16*) ((Uint8*) surface->pixels () + y * surface->pitch () + 2 * x); while (w > 0) { __SET_PIXEL (16, data, color); ++data; --w; } }static voiddrawHLineSolid24 (Surface *surface, Uint16 x, Uint16 y, Uint16 w, Uint32 color){ Uint8 *data = (Uint8*) surface->pixels () + y * surface->pitch () + 3 * x; Uint8 c1 = color & 0xFF; Uint8 c2 = (color >> 8) & 0xFF; Uint8 c3 = (color >> 16) & 0xFF; while (w > 0) { __SET_PIXEL24 (data, c1, c2, c3); data += 3; --w; } }static voiddrawHLineSolid32 (Surface *surface, Uint16 x, Uint16 y, Uint16 w, Uint32 color){ Uint32 *data = (Uint32*) ((Uint8*) surface->pixels () + y * surface->pitch () + 4 * x); while (w > 0) { __SET_PIXEL (32, data, color); ++data; --w; } }static voiddrawVLineSolid8 (Surface *surface, Uint16 x, Uint16 y, Uint16 h, Uint32 color){ Uint16 pitch = surface->pitch (); Uint8 *data = (Uint8*) surface->pixels () + (y * pitch) + x; while (h > 0) { __SET_PIXEL (8, data, color); data += pitch; --h; } }static voiddrawVLineSolid16 (Surface *surface, Uint16 x, Uint16 y, Uint16 h, Uint32 color){ Uint16 pitch = surface->pitch (); Uint8 *data = (Uint8*) surface->pixels () + (y * pitch) + (2 * x); while (h > 0) { __SET_PIXEL (16, data, color); data += pitch; --h; } }static voiddrawVLineSolid24 (Surface *surface, Uint16 x, Uint16 y, Uint16 h, Uint32 color){ Uint16 pitch = surface->pitch (); Uint8 *data = (Uint8*) surface->pixels () + (y * pitch) + (3 * x); Uint8 c1 = color & 0xFF; Uint8 c2 = (color >> 8) & 0xFF; Uint8 c3 = (color >> 16) & 0xFF; while (h > 0) { __SET_PIXEL24 (data, c1, c2, c3); data += pitch; --h; } }static voiddrawVLineSolid32 (Surface *surface, Uint16 x, Uint16 y, Uint16 h, Uint32 color){ Uint16 pitch = surface->pitch (); Uint8 *data = (Uint8*) surface->pixels () + (y * pitch) + (4 * x); while (h > 0) { __SET_PIXEL (32, data, color); data += pitch; --h; } }// Line drawing algorithm (Bresenham)#define __DO_LINE(x1, y1, x2, y2, command, surface) \{ \ Sint16 dx = x2 - x1; \ Sint16 dy = y2 - y1; \ Uint16 x = 0; \ Uint16 y = 0; \ Uint8 *data = \ (Uint8*) surface->pixels () + y1 * surface->pitch () + x1 * surface->format ()->BytesPerPixel; \ Sint16 d_pitch = (dy < 0) ? -surface->pitch () : surface->pitch (); \ Sint16 d_data = (dx < 0) ? -surface->format ()->BytesPerPixel : surface->format ()->BytesPerPixel; \ dx = abs (dx); \ dy = abs (dy); \ \ if (dx >= dy) \ { \ for (x = 0; x <= dx; x++) \ { \ { command; } \ \ y += dy; \ if (y >= dx) \ { \ y -= dx; \ data += d_pitch; \ } \ \ data += d_data; \ } \ } \ else \ { \ for (y = 0; y <= dy; y++) \ { \ { command; } \ \ x += dx; \ if (x >= dy) \ { \ x -= dy; \ data += d_data; \ } \ data += d_pitch; \ } \ } \}static voiddrawLineSolid8 (Surface *surface, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, Uint32 color){ __DO_LINE (x1, y1, x2, y2, __SET_PIXEL (8, data, color), surface);} static voiddrawLineSolid16 (Surface *surface, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, Uint32 color){ __DO_LINE (x1, y1, x2, y2, __SET_PIXEL (16, data, color), surface);}static voiddrawLineSolid24 (Surface *surface, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, Uint32 color){ Uint8 c1 = color & 0xFF; Uint8 c2 = (color >> 8) & 0xFF; Uint8 c3 = (color >> 16) & 0xFF; __DO_LINE (x1, y1, x2, y2, __SET_PIXEL24 (data, c1, c2, c3), surface);}static voiddrawLineSolid32 (Surface *surface, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, Uint32 color){ __DO_LINE (x1, y1, x2, y2, __SET_PIXEL (32, data, color), surface);}#define __MAKE_LOCKED_PUT_PIXEL(type) \static void \putPixel##type##L (Surface *surface, Uint16 x, Uint16 y, Uint32 color) \{ \ surface->lock (); \ putPixel##type (surface, x, y, color); \ surface->unlock (); \}#define __MAKE_LOCKED_H_LINE(type) \static void \drawHLine##type##L (Surface *surface, Uint16 x, Uint16 y, Uint16 w, Uint32 color) \{ \ surface->lock (); \ drawHLine##type (surface, x, y, w, color); \ surface->unlock (); \}#define __MAKE_LOCKED_V_LINE(type) \static void \drawVLine##type##L (Surface *surface, Uint16 x, Uint16 y, Uint16 h, Uint32 color) \{ \ surface->lock (); \ drawVLine##type (surface, x, y, h, color); \ surface->unlock (); \}#define __MAKE_LOCKED_LINE(type) \static void \drawLine##type##L (Surface *surface, Uint16 x, Uint16 y, Uint16 x2, Uint16 y2, Uint32 color) \{ \ surface->lock (); \ drawLine##type (surface, x, y, x2, y2, color); \ surface->unlock (); \}__MAKE_LOCKED_PUT_PIXEL (Solid8);__MAKE_LOCKED_H_LINE (Solid8);__MAKE_LOCKED_V_LINE (Solid8);__MAKE_LOCKED_LINE (Solid8);__MAKE_LOCKED_PUT_PIXEL (Solid16);__MAKE_LOCKED_H_LINE (Solid16);__MAKE_LOCKED_V_LINE (Solid16);__MAKE_LOCKED_LINE (Solid16);__MAKE_LOCKED_PUT_PIXEL (Solid24);__MAKE_LOCKED_H_LINE (Solid24);__MAKE_LOCKED_V_LINE (Solid24);__MAKE_LOCKED_LINE (Solid24);__MAKE_LOCKED_PUT_PIXEL (Solid32);__MAKE_LOCKED_H_LINE (Solid32);__MAKE_LOCKED_V_LINE (Solid32);__MAKE_LOCKED_LINE (Solid32);//////////////////////////////////////////////////////////////////////////////////// ALPHA BLENDED (transparency aware) drawing functions ////////////////////////////////////////////////////////////////////////////////////// macros for color manipulation (some are taken from SDL)#define __RGBA_FROM_RGBA8888(pixel, r, g, b, a) \{ \ r = (pixel>>24); \ g = ((pixel>>16)&0xFF); \ b = ((pixel>>8)&0xFF); \ a = (pixel&0xFF); \}#define __RGB_FROM_RGB565(pixel, r, g, b) \{ \ r = (((pixel&0xF800)>>11)<<3); \ g = (((pixel&0x07E0)>>5)<<2); \ b = ((pixel&0x001F)<<3); \}#define __RGB_FROM_RGB888(pixel, r, g, b) \{ \ r = ((pixel&0xFF0000)>>16); \ g = ((pixel&0xFF00)>>8); \ b = (pixel&0xFF); \}#define __RGB565_FROM_RGB(pixel, r, g, b) \{ \ pixel = ((r>>3)<<11)|((g>>2)<<5)|(b>>3); \}#define __RGB888_FROM_RGB(pixel, r, g, b) \{ \ pixel = (r<<16)|(g<<8)|b; \}// Blend the RGB values of two pixels based on a source alpha value */#define __ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB) \do { \ dR = ((((sR-dR)*(A))>>8)+dR) & 0xFF; \ dG = ((((sG-dG)*(A))>>8)+dG) & 0xFF; \ dB = ((((sB-dB)*(A))>>8)+dB) & 0xFF; \} while(0)// this is in fact 128 (~127)#define __ALPHA_HALF 127 // Blend the RGB values two pixel with alpha = 128 (~127) - optimized#define __ALPHA_BLEND_HALF(sR, sG, sB, dR, dG, dB) \do { \ dR = ((sR + dR) >> 1); \ dG = ((sG + dG) >> 1); \ dB = ((sB + dB) >> 1); \} while (0)#define __ALPHA_BLEND_AUTO(sR, sG, sB, A, dR, dG, dB) \{ \ if (a == 127) \ __ALPHA_BLEND_HALF (sR, sG, sB, dR, dG, dB); \ else \ __ALPHA_BLEND (sR, sG, sB, A, dR, dG, dB); \}static void putPixelBlend16 (Surface *surface, Uint16 x, Uint16 y, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; Uint16 *data = (Uint16*) ((Uint8*) surface->pixels () + y * surface->pitch () + 2 * x); if (a == 255) { __RGB565_FROM_RGB (*data, dr, dg, db); return; } Uint8 sr, sg, sb; __RGB_FROM_RGB565 (*data, sr, sg, sb); a = ~a; __ALPHA_BLEND_AUTO (sr, sg, sb, a, dr, dg, db); __RGB565_FROM_RGB (*data, dr, dg, db);}static void putPixelBlend24 (Surface *surface, Uint16 x, Uint16 y, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; Uint32 *data = (Uint32*) ((Uint8*) surface->pixels () + y * surface->pitch () + 3 * x); if (a == 255) { __SET_PIXEL24 (((Uint8*)data), db, dg, dr); return; } Uint8 sr, sg, sb; __RGB_FROM_RGB888 (*data, sr, sg, sb); a = ~a; __ALPHA_BLEND_AUTO (sr, sg, sb, a, dr, dg, db); __SET_PIXEL24 (((Uint8*)data), db, dg, dr); }static void putPixelBlend32 (Surface *surface, Uint16 x, Uint16 y, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; Uint32 *data = (Uint32*) ((Uint8*) surface->pixels () + y * surface->pitch () + 4 * x); if (a == 255) { __RGB888_FROM_RGB (*data, dr, dg, db); return; } Uint8 sr, sg, sb; __RGB_FROM_RGB888 (*data, sr, sg, sb); a = ~a; __ALPHA_BLEND_AUTO (sr, sg, sb, a, dr, dg, db); __RGB888_FROM_RGB (*data, dr, dg, db);}static void drawHLineBlend16 (Surface *surface, Uint16 x, Uint16 y, Uint16 w, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; if (a == 255) { __RGB565_FROM_RGB (color, dr, dg, db); drawHLineSolid16 (surface, x, y, w, color); return; } Uint16 *data = (Uint16*) ((Uint8*) surface->pixels () + y * surface->pitch () + 2 * x); Uint8 sr, sg, sb; Uint8 dr_, dg_, db_; a = ~a; if (a == __ALPHA_HALF) { while (w > 0) { __RGB_FROM_RGB565 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND_HALF (sr, sg, sb, dr_, dg_, db_); __RGB565_FROM_RGB (*data, dr_, dg_, db_); ++data; --w; } } else { while (w > 0) { __RGB_FROM_RGB565 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND (sr, sg, sb, a, dr_, dg_, db_); __RGB565_FROM_RGB (*data, dr_, dg_, db_); ++data; --w; } } }static void drawHLineBlend24 (Surface *surface, Uint16 x, Uint16 y, Uint16 w, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; if (a == 255) { __RGB888_FROM_RGB (color, dr, dg, db); drawHLineSolid24 (surface, x, y, w, color); return; } Uint32 *data = (Uint32*) ((Uint8*) surface->pixels () + y * surface->pitch () + 3 * x); Uint8 sr, sg, sb; Uint8 dr_, dg_, db_; a = ~a; if (a == __ALPHA_HALF) { while (w > 0) { __RGB_FROM_RGB888 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND_HALF (sr, sg, sb, dr_, dg_, db_); __SET_PIXEL24 (((Uint8*)data), db_, dg_, dr_);#ifdef _MSC_VER data = (Uint32*) ((Uint8*)data + 3);#else ((Uint8*)data) += 3;#endif --w; } } else { while (w > 0) { __RGB_FROM_RGB888 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND (sr, sg, sb, a, dr_, dg_, db_); __SET_PIXEL24 (((Uint8*)data), db_, dg_, dr_);#ifdef _MSC_VER data = (Uint32*) ((Uint8*)data + 3);#else ((Uint8*)data) += 3;#endif --w; } } }static void drawHLineBlend32 (Surface *surface, Uint16 x, Uint16 y, Uint16 w, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; if (a == 255) { __RGB888_FROM_RGB (color, dr, dg, db); drawHLineSolid32 (surface, x, y, w, color); return; } Uint32 *data = (Uint32*) ((Uint8*) surface->pixels () + y * surface->pitch () + 4 * x); Uint8 sr, sg, sb; Uint8 dr_, dg_, db_; a = ~a; if (a == __ALPHA_HALF) { while (w > 0) { __RGB_FROM_RGB888 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND_HALF (sr, sg, sb, dr_, dg_, db_); __RGB888_FROM_RGB (*data, dr_, dg_, db_); ++data; --w; } } else { while (w > 0) { __RGB_FROM_RGB888 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND (sr, sg, sb, a, dr_, dg_, db_); __RGB888_FROM_RGB (*data, dr_, dg_, db_); ++data; --w; } } }static void drawVLineBlend16 (Surface *surface, Uint16 x, Uint16 y, Uint16 h, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; if (a == 255) { __RGB565_FROM_RGB (color, dr, dg, db); drawVLineSolid16 (surface, x, y, h, color); return; } Uint16 pitch = surface->pitch (); Uint16 *data = (Uint16*) ((Uint8*) surface->pixels () + (y * pitch) + (2 * x)); Uint8 sr, sg, sb; Uint8 dr_, dg_, db_; a = ~a; if (a == __ALPHA_HALF) { while (h > 0) { __RGB_FROM_RGB565 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND_HALF (sr, sg, sb, dr_, dg_, db_); __RGB565_FROM_RGB (*data, dr_, dg_, db_);#ifdef _MSC_VER data = (Uint16*) ((Uint8*)data + pitch);#else ((Uint8*)data) += pitch;#endif --h; } } else { while (h > 0) { __RGB_FROM_RGB565 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND (sr, sg, sb, a, dr_, dg_, db_); __RGB565_FROM_RGB (*data, dr_, dg_, db_); #ifdef _MSC_VER data = (Uint16*) ((Uint8*)data + pitch);#else ((Uint8*)data) += pitch;#endif --h; } } }static void drawVLineBlend24 (Surface *surface, Uint16 x, Uint16 y, Uint16 h, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; if (a == 255) { __RGB888_FROM_RGB (color, dr, dg, db); drawVLineSolid24 (surface, x, y, h, color); return; } Uint16 pitch = surface->pitch (); Uint32 *data = (Uint32*) ((Uint8*) surface->pixels () + (y * pitch) + (3 * x)); Uint8 sr, sg, sb; Uint8 dr_, dg_, db_; a = ~a; if (a == __ALPHA_HALF) { while (h > 0) { __RGB_FROM_RGB888 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND_HALF (sr, sg, sb, dr_, dg_, db_); __SET_PIXEL24 (((Uint8*)data), db_, dg_, dr_);#ifdef _MSC_VER data = (Uint32*) ((Uint8*)data + pitch);#else ((Uint8*)data) += pitch;#endif --h; } } else { while (h > 0) { __RGB_FROM_RGB888 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND (sr, sg, sb, a, dr_, dg_, db_); __SET_PIXEL24 (((Uint8*)data), db_, dg_, dr_);#ifdef _MSC_VER data = (Uint32*) ((Uint8*)data + pitch);#else ((Uint8*)data) += pitch;#endif --h; } } }static void drawVLineBlend32 (Surface *surface, Uint16 x, Uint16 y, Uint16 h, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; if (a == 255) { __RGB888_FROM_RGB (color, dr, dg, db); drawVLineSolid32 (surface, x, y, h, color); return; } Uint16 pitch = surface->pitch (); Uint32 *data = (Uint32*) ((Uint8*) surface->pixels () + (y * pitch) + (4 * x)); Uint8 sr, sg, sb; Uint8 dr_, dg_, db_; a = ~a; if (a == __ALPHA_HALF) { while (h > 0) { __RGB_FROM_RGB888 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND_HALF (sr, sg, sb, dr_, dg_, db_); __RGB888_FROM_RGB (*data, dr_, dg_, db_);#ifdef _MSC_VER data = (Uint32*) ((Uint8*)data + pitch);#else ((Uint8*)data) += pitch;#endif --h; } } else { while (h > 0) { __RGB_FROM_RGB888 (*data, sr, sg, sb); dr_ = dr; dg_ = dg; db_ = db; __ALPHA_BLEND (sr, sg, sb, a, dr_, dg_, db_); __RGB888_FROM_RGB (*data, dr_, dg_, db_);#ifdef _MSC_VER data = (Uint32*) ((Uint8*)data + pitch);#else ((Uint8*)data) += pitch;#endif --h; } } }static voiddrawLineBlend16 (Surface *surface, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; if (a == 255) { __RGB565_FROM_RGB (color, dr, dg, db); drawLineSolid16 (surface, x1, y1, x2, y2, color); return; } Uint8 sr, sg, sb; Uint8 dr_, dg_, db_; a = ~a; Uint16 *data_; if (a == __ALPHA_HALF) { __DO_LINE (x1, y1, x2, y2, data_ = (Uint16*)data; __RGB_FROM_RGB565 (*data_, sr, sg, sb); dr_ = dr; dg_= dg; db_ = db; __ALPHA_BLEND_HALF (sr, sg, sb, dr_, dg_, db_); __RGB565_FROM_RGB (*data_, dr_, dg_, db_), surface); } else { __DO_LINE (x1, y1, x2, y2, data_ = (Uint16*)data; __RGB_FROM_RGB565 (*data_, sr, sg, sb); dr_ = dr; dg_= dg; db_ = db; __ALPHA_BLEND (sr, sg, sb, a, dr_, dg_, db_); __RGB565_FROM_RGB (*data_, dr_, dg_, db_), surface); } }static voiddrawLineBlend24 (Surface *surface, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; if (a == 255) { __RGB888_FROM_RGB (color, dr, dg, db); drawLineSolid24 (surface, x1, y1, x2, y2, color); return; } Uint8 sr, sg, sb; Uint8 dr_, dg_, db_; a = ~a; Uint32 *data_; if (a == __ALPHA_HALF) { __DO_LINE (x1, y1, x2, y2, data_ = (Uint32*)data; __RGB_FROM_RGB888 (*data_, sr, sg, sb); dr_ = dr; dg_= dg; db_ = db; __ALPHA_BLEND_HALF (sr, sg, sb, dr_, dg_, db_); __SET_PIXEL24 (data, db_, dg_, dr_), surface); } else { __DO_LINE (x1, y1, x2, y2, data_ = (Uint32*)data; __RGB_FROM_RGB888 (*data_, sr, sg, sb); dr_ = dr; dg_= dg; db_ = db; __ALPHA_BLEND (sr, sg, sb, a, dr_, dg_, db_); __SET_PIXEL24 (data, db_, dg_, dr_), surface); } }static voiddrawLineBlend32 (Surface *surface, Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2, Uint32 color){ Uint8 dr, dg, db, a; __RGBA_FROM_RGBA8888 (color, dr, dg, db, a); if (a == 0) return; if (a == 255) { __RGB888_FROM_RGB (color, dr, dg, db); drawLineSolid32 (surface, x1, y1, x2, y2, color); return; } Uint8 sr, sg, sb; Uint8 dr_, dg_, db_; a = ~a; Uint32 *data_; if (a == __ALPHA_HALF) { __DO_LINE (x1, y1, x2, y2, data_ = (Uint32*)data; __RGB_FROM_RGB888 (*data_, sr, sg, sb); dr_ = dr; dg_= dg; db_ = db; __ALPHA_BLEND_HALF (sr, sg, sb, dr_, dg_, db_); __RGB888_FROM_RGB (*data_, dr_, dg_, db_), surface); } else { __DO_LINE (x1, y1, x2, y2, data_ = (Uint32*)data; __RGB_FROM_RGB888 (*data_, sr, sg, sb); dr_ = dr; dg_= dg; db_ = db; __ALPHA_BLEND (sr, sg, sb, a, dr_, dg_, db_); __RGB888_FROM_RGB (*data_, dr_, dg_, db_), surface); } }#undef __DO_LINE__MAKE_LOCKED_PUT_PIXEL (Blend16);__MAKE_LOCKED_H_LINE (Blend16);__MAKE_LOCKED_V_LINE (Blend16);__MAKE_LOCKED_LINE (Blend16);__MAKE_LOCKED_PUT_PIXEL (Blend24);__MAKE_LOCKED_H_LINE (Blend24);__MAKE_LOCKED_V_LINE (Blend24);__MAKE_LOCKED_LINE (Blend24);__MAKE_LOCKED_PUT_PIXEL (Blend32);__MAKE_LOCKED_H_LINE (Blend32);__MAKE_LOCKED_V_LINE (Blend32);__MAKE_LOCKED_LINE (Blend32);GFXTable Painter::m_gfx_tables [2][2][4] = { { { { putPixelSolid8, drawHLineSolid8, drawVLineSolid8, drawLineSolid8 }, { putPixelSolid16, drawHLineSolid16, drawVLineSolid16, drawLineSolid16 }, { putPixelSolid24, drawHLineSolid24, drawVLineSolid24, drawLineSolid24 }, { putPixelSolid32, drawHLineSolid32, drawVLineSolid32, drawLineSolid32 } }, { { putPixelSolid8L, drawHLineSolid8L, drawVLineSolid8L, drawLineSolid8L }, { putPixelSolid16L, drawHLineSolid16L, drawVLineSolid16L, drawLineSolid16L }, { putPixelSolid24L, drawHLineSolid24L, drawVLineSolid24L, drawLineSolid24L }, { putPixelSolid32L, drawHLineSolid32L, drawVLineSolid32L, drawLineSolid32L } } }, { { { putPixelSolid8, drawHLineSolid8, drawVLineSolid8, drawLineSolid8 }, { putPixelBlend16, drawHLineBlend16, drawVLineBlend16, drawLineBlend16 }, { putPixelBlend24, drawHLineBlend24, drawVLineBlend24, drawLineBlend24 }, { putPixelBlend32, drawHLineBlend32, drawVLineBlend32, drawLineBlend32 } }, { { putPixelSolid8L, drawHLineSolid8L, drawVLineSolid8L, drawLineSolid8L }, { putPixelBlend16L, drawHLineBlend16L, drawVLineBlend16L, drawLineBlend16L }, { putPixelBlend24L, drawHLineBlend24L, drawVLineBlend24L, drawLineBlend24L }, { putPixelBlend32L, drawHLineBlend32L, drawVLineBlend32L, drawLineBlend32L } } }};#if 0 // this will not be included in the GFX table// shamelessly taken from allegro...staticvoid do_circle (Surface *surface, Uint16 x, Uint16 y, Uint16 radius, int d, void (*proc)(Surface *, int, int, int)){ Sint16 cx = 0; Sint16 cy = radius; Sint16 df = 1 - radius; Sint16 d_e = 3; Sint16 d_se = -2 * radius + 5; do { proc (surface, x+cx, y+cy, d); if (cx) proc (surface, x-cx, y+cy, d); if (cy) proc (surface, x+cx, y-cy, d); if ((cx) && (cy)) proc (surface, x-cx, y-cy, d); if (cx != cy) { proc (surface, x+cy, y+cx, d); if (cx) proc (surface, x+cy, y-cx, d); if (cy) proc (surface, x-cy, y+cx, d); if (cx && cy) proc (surface, x-cy, y-cx, d); } if (df < 0) { df += d_e; d_e += 2; d_se += 2; } else { df += d_se; d_e += 2; d_se += 4; cy--; } cx++; } while (cx <= cy);}#endif // 0//////////////////////////////////////////////////////////////////////////////////////// The Painter Class ////////////////////////////////////////////////////////////////////////////////////////Painter::Painter (Surface *target, int mode, bool nothrow) : m_gfx (&GFXInvalid), m_target_surface (target), m_mode (mode), m_clipping (true), m_auto_lock (true){ if (!target) { warning ("Painter: Cannot operate on NULL surface !"); if (!nothrow) throw Error ("Couldn't create painter with NULL target surface"); } else { updateGFXTable (); target->ref (); } resetClipRect ();}Painter::~Painter (){ if (m_target_surface) m_target_surface->unref ();}boolPainter::updateGFXTable (){ m_gfx = &GFXInvalid; return_val_if_fail (m_target_surface != NULL, false); if (m_mode != ModeSolid && m_mode != ModeBlended) { warning ("Unknown drawing mode!"); return false; } int depth = m_target_surface->format ()->BytesPerPixel; if (depth < 1 || depth > 4) { warning ("Unknown bit-depth of the target surface !"); return false; } m_gfx = &m_gfx_tables [m_mode][m_auto_lock][depth - 1]; return true;}void Painter::setMode (int mode){ m_mode = mode; updateGFXTable ();}voidPainter::setTarget (Surface *target){ releaseTarget (); m_target_surface = target; updateGFXTable (); resetClipRect (); if (target) target->ref ();}voidPainter::releaseTarget (){ if (m_target_surface) m_target_surface->unref (); m_target_surface = NULL; m_gfx = NULL; m_clip_rect = Rect (0, 0, 0, 0); }voidPainter::setClipping (bool clipping){ m_clipping = clipping;}voidPainter::setAutoLock (bool auto_lock){ m_auto_lock = auto_lock; updateGFXTable ();}voidPainter::setClipRect (const Rect & rect){ m_clip_rect = rect; m_clip_x2 = rect.x + rect.w - 1; m_clip_y2 = rect.y + rect.h - 1;}voidPainter::retrieveClipRect (){ if (!m_target_surface) setClipRect (Rect (0, 0, 0, 0)); else setClipRect (m_target_surface->clipRect ());}voidPainter::resetClipRect (){ if (!m_target_surface) setClipRect (Rect (0, 0, 0, 0)); else setClipRect (Rect (0, 0, m_target_surface->w (), m_target_surface->h ()));}voidPainter::putPixel (Uint16 x, Uint16 y, Uint32 color){ if (m_clipping) { if (x < m_clip_rect.x || x > m_clip_x2 || y < m_clip_rect.y || y > m_clip_y2) return; } m_gfx->putPixel (m_target_surface, x, y, color);}voidPainter::drawHLine (Uint16 x, Uint16 y, Uint16 w, Uint32 color){ if (w == 0) return; if (m_clipping) { if (y < m_clip_rect.y || y > m_clip_y2) return; if ((x + w - 1) < m_clip_rect.x) return; if (x > m_clip_x2) return; if (x < m_clip_rect.x) { w -= (m_clip_rect.x - x); x = m_clip_rect.x; } if ((x + w) > (m_clip_x2 + 1)) { w -= (w + x) - m_clip_x2 - 1; } } m_gfx->drawHLine (m_target_surface, x, y, w, color);}voidPainter::drawVLine (Uint16 x, Uint16 y, Uint16 h, Uint32 color){ if (h == 0) return; if (m_clipping) { if (x < m_clip_rect.x || x > m_clip_x2) return; if ((y + h - 1) < m_clip_rect.y) return; if (y > m_clip_y2) return; if (y < m_clip_rect.y) { h -= (m_clip_rect.y - y); y = m_clip_rect.y; } if ((y + h) > (m_clip_y2 + 1)) { h -= (h + y) - m_clip_y2 - 1; } } m_gfx->drawVLine (m_target_surface, x, y, h, color);}// This function was ripped from "Tricks of the Windows game programming gurus" // written by Andre Lamothe ISBN: 0-672-31361-8// Then it was ripped from ClanLib and slightly adapted to work with SEL.// It returns false if the line is totally outside the clipping area and true// if the line was successfully clippedstatic bool clipLine (Uint16 &x1, Uint16 &y1, Uint16 &x2, Uint16 &y2, Uint16 min_clip_x, Uint16 max_clip_x, Uint16 min_clip_y, Uint16 max_clip_y){// internal clipping codes#define CLIP_CODE_C 0x0000#define CLIP_CODE_N 0x0008#define CLIP_CODE_S 0x0004#define CLIP_CODE_E 0x0002#define CLIP_CODE_W 0x0001#define CLIP_CODE_NE 0x000a#define CLIP_CODE_SE 0x0006#define CLIP_CODE_NW 0x0009#define CLIP_CODE_SW 0x0005 Uint16 xc1 = x1; Uint16 yc1 = y1; Uint16 xc2 = x2; Uint16 yc2 = y2; int p1_code = 0; int p2_code = 0; // determine codes for p1 and p2 if (y1 < min_clip_y) { p1_code |= CLIP_CODE_N; } else if (y1 > max_clip_y) { p1_code |= CLIP_CODE_S; } if (x1 < min_clip_x) { p1_code |= CLIP_CODE_W; } else if (x1 > max_clip_x) { p1_code |= CLIP_CODE_E; } if (y2 < min_clip_y) { p2_code |= CLIP_CODE_N; } else if (y2 > max_clip_y) { p2_code |= CLIP_CODE_S; } if (x2 < min_clip_x) { p2_code |= CLIP_CODE_W; } else if (x2 > max_clip_x) { p2_code |= CLIP_CODE_E; } // try and trivially reject if ((p1_code & p2_code)) { return 0; } // test for totally visible, if so leave points untouched if (p1_code == 0 && p2_code == 0) { return 1; } // determine end clip point for p1 switch (p1_code) { case CLIP_CODE_C: break; case CLIP_CODE_N: yc1 = (Uint16) min_clip_y; xc1 = (Uint16) (x1 + 0.5 + (min_clip_y - y1) * (x2 - x1) / (y2 - y1)); break; case CLIP_CODE_S: yc1 = (Uint16) max_clip_y; xc1 = (Uint16) (x1 + 0.5 + (max_clip_y-y1) * (x2 - x1) / (y2 - y1)); break; case CLIP_CODE_W: xc1 = (Uint16) min_clip_x; yc1 = (Uint16) (y1 + 0.5 + (min_clip_x - x1) * (y2 - y1) / (x2 - x1)); break; case CLIP_CODE_E: xc1 = (Uint16) max_clip_x; yc1 = (Uint16) (y1 + 0.5 + (max_clip_x - x1) * (y2 - y1) / (x2 - x1)); break; // these cases are more complex, must compute 2 intersections case CLIP_CODE_NE: // north hline intersection yc1 = (Uint16) min_clip_y; xc1 = (Uint16) (x1 + 0.5 + (min_clip_y - y1) * (x2 - x1) / (y2 - y1)); // test if intersection is valid, of so then done, else compute next if (xc1 < min_clip_x || xc1 > max_clip_x) { // east vline intersection xc1 = (Uint16) max_clip_x; yc1 = (Uint16) (y1 + 0.5 + (max_clip_x - x1) * (y2 - y1) / (x2 - x1)); } break; case CLIP_CODE_SE: // south hline intersection yc1 = (Uint16) max_clip_y; xc1 = (Uint16) (x1 + 0.5 + (max_clip_y - y1) * (x2 - x1) / (y2 - y1)); // test if intersection is valid, of so then done, else compute next if (xc1 < min_clip_x || xc1 > max_clip_x) { // east vline intersection xc1 = (Uint16) max_clip_x; yc1 = (Uint16) (y1 + 0.5 + (max_clip_x - x1) * (y2 - y1) / (x2 - x1)); } break; case CLIP_CODE_NW: // north hline intersection yc1 = (Uint16) min_clip_y; xc1 = (Uint16) (x1 + 0.5 + (min_clip_y - y1) * (x2 - x1) / (y2 - y1)); // test if intersection is valid, of so then done, else compute next if (xc1 < min_clip_x || xc1 > max_clip_x) { xc1 = (Uint16) min_clip_x; yc1 = (Uint16) (y1 + 0.5 + (min_clip_x - x1) * (y2 - y1) / (x2 - x1)); } break; case CLIP_CODE_SW: // south hline intersection yc1 = (Uint16) max_clip_y; xc1 = (Uint16) (x1 + 0.5 + (max_clip_y - y1) * (x2-x1)/(y2-y1)); // test if intersection is valid, of so then done, else compute next if (xc1 < min_clip_x || xc1 > max_clip_x) { xc1 = (Uint16) min_clip_x; yc1 = (Uint16) (y1 + 0.5 + (min_clip_x - x1) * (y2 - y1) / (x2 - x1)); } break; default: break; } // switch // determine clip point for p2 switch (p2_code) { case CLIP_CODE_C: break; case CLIP_CODE_N: yc2 = (Uint16) min_clip_y; xc2 = (Uint16) (x2 + (min_clip_y - y2) * (x1 - x2) / (y1 - y2)); break; case CLIP_CODE_S: yc2 = (Uint16) max_clip_y; xc2 = (Uint16) (x2 + (max_clip_y - y2) * (x1 - x2) / (y1 - y2)); break; case CLIP_CODE_W: xc2 = (Uint16) min_clip_x; yc2 = (Uint16) (y2 + (min_clip_x - x2) * (y1 - y2) / (x1 - x2)); break; case CLIP_CODE_E: xc2 = (Uint16) max_clip_x; yc2 = (Uint16) (y2 + (max_clip_x - x2) * (y1 - y2) / (x1 - x2)); break; // these cases are more complex, must compute 2 intersections case CLIP_CODE_NE: // north hline intersection yc2 = (Uint16) min_clip_y; xc2 = (Uint16) (x2 + 0.5 + (min_clip_y - y2) * (x1 - x2) / (y1 - y2)); // test if intersection is valid, of so then done, else compute next if (xc2 < min_clip_x || xc2 > max_clip_x) { // east vline intersection xc2 = (Uint16) max_clip_x; yc2 = (Uint16) (y2 + 0.5 + (max_clip_x - x2) * (y1 - y2) / (x1 - x2)); } break; case CLIP_CODE_SE: // south hline intersection yc2 = (Uint16) max_clip_y; xc2 = (Uint16) (x2 + 0.5 + (max_clip_y - y2) * (x1 - x2) / (y1 - y2)); // test if intersection is valid, of so then done, else compute next if (xc2 < min_clip_x || xc2 > max_clip_x) { // east vline intersection xc2 = (Uint16) max_clip_x; yc2 = (Uint16) (y2 + 0.5 + (max_clip_x - x2) * (y1 - y2) / (x1 - x2)); } break; case CLIP_CODE_NW: // north hline intersection yc2 = (Uint16) min_clip_y; xc2 = (Uint16) (x2 + 0.5 + (min_clip_y - y2) * (x1 - x2) / (y1 - y2)); // test if intersection is valid, of so then done, else compute next if (xc2 < min_clip_x || xc2 > max_clip_x) { xc2 = (Uint16) min_clip_x; yc2 = (Uint16) (y2 + 0.5 + (min_clip_x - x2) * (y1 - y2) / (x1 - x2)); } break; case CLIP_CODE_SW: // south hline intersection yc2 = (Uint16) max_clip_y; xc2 = (Uint16) (x2 + 0.5 + (max_clip_y - y2) * (x1 - x2) / (y1 - y2)); // test if intersection is valid, of so then done, else compute next if (xc2 < min_clip_x || xc2 > max_clip_x) { xc2 = (Uint16) min_clip_x; yc2 = (Uint16) (y2 + 0.5 + (min_clip_x - x2) * (y1 - y2) / (x1 - x2)); } break; default: break; } // switch // do bounds check if ((xc1 < min_clip_x) || (xc1 > max_clip_x) || (yc1 < min_clip_y) || (yc1 > max_clip_y) || (xc2 < min_clip_x) || (xc2 > max_clip_x) || (yc2 < min_clip_y) || (yc2 > max_clip_y) ) { return 0; } // store vars back x1 = xc1; y1 = yc1; x2 = xc2; y2 = yc2; return 1;#undef CLIP_CODE_C #undef CLIP_CODE_N #undef CLIP_CODE_S #undef CLIP_CODE_E #undef CLIP_CODE_W #undef CLIP_CODE_NE #undef CLIP_CODE_SE #undef CLIP_CODE_NW #undef CLIP_CODE_SW }void Painter::drawLine (Uint16 x, Uint16 y, Uint16 x2, Uint16 y2, Uint32 color){ if (y == y2) { Uint16 w; x > x2 ? w = x - x2 + 1, x = x2 : w = x2 - x + 1; drawHLine (x, y, w, color); return; } else if (x == x2) { Uint16 h; y > y2 ? h = y - y2 + 1, y = y2 : h = y2 - y + 1; drawVLine (x, y, h, color); return; } if (m_clipping) { if (!clipLine (x, y, x2, y2, m_clip_rect.x, m_clip_x2, m_clip_rect.y, m_clip_y2)) return; } m_gfx->drawLine (m_target_surface, x, y, x2, y2, color);}voidPainter::drawRect (Uint16 x, Uint16 y, Uint16 w, Uint16 h, Uint32 color){ if (w == 0 || h == 0) return; if (w == 1 && h == 1) { putPixel (x, y, color); return; } if (h == 1) { drawHLine (x, y, w, color); return; } if (w == 1) { drawVLine (x, y, h, color); return; } drawHLine (x, y, w, color); drawHLine (x, y + h - 1, w, color); if (h > 2) { drawVLine (x, y + 1, h - 2, color); drawVLine (x + w - 1, y + 1, h - 2, color); }}voidPainter::fillRect (Uint16 x, Uint16 y, Uint16 w, Uint16 h, Uint32 color){ Uint16 _x; Uint16 _y; Uint16 _w; Uint16 _h;#define ___MIN(a,b) (a < b ? a : b)#define ___MAX(a,b) (a > b ? a : b) if (m_clipping) { if (x > m_clip_x2 || y > m_clip_y2) return; if (x + w < m_clip_rect.x + 1 || y + h < m_clip_rect.y + 1) return; _x = ___MAX (x, m_clip_rect.x); _y = ___MAX (y, m_clip_rect.y); _w = ___MIN (x + w - 1, m_clip_x2) - _x + 1; _h = ___MIN (y + h - 1, m_clip_y2) - _y + 1; } else { _x = x; _y = y; _w = w; _h = h; } #undef ___MIN#undef ___MAX if (_w == 0 || _h == 0) return; if (_w == 1 && h == 1) { m_gfx->putPixel (m_target_surface, _x, _y, color); return; } if (_h == 1) { m_gfx->drawHLine (m_target_surface, _x, _y, _w, color); return; } if (_w == 1) { m_gfx->drawVLine (m_target_surface, _x, _y, _h, color); return; } Uint16 i; if (_h > _w) { for (i = 0; i < _w; ++i) { m_gfx->drawVLine (m_target_surface, _x + i, _y, _h, color); } } else { for (i = 0; i < _h; ++i) { m_gfx->drawHLine (m_target_surface, _x, _y + i, _w, color); } }}} // namespace SEL