/* * Copyright (c) 2005-2007 Hypertriton, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "tileset.h" #include "rg_math.h" void RG_ColorRGB(RG_Tile *t, Uint8 r, Uint8 g, Uint8 b) { t->c.r = r; t->c.g = g; t->c.b = b; t->pc = AG_MapRGB(t->su->format, r,g,b); } void RG_ColorRGBA(RG_Tile *t, Uint8 r, Uint8 g, Uint8 b, Uint8 a) { t->c.r = r; t->c.g = g; t->c.b = b; t->pc = AG_MapRGBA(t->su->format, r,g,b,a); } void RG_ColorHSV(RG_Tile *t, float h, float s, float v) { AG_HSV2RGB(h, s, v, &t->c.r, &t->c.g, &t->c.b); t->pc = AG_MapRGB(t->su->format, t->c.r, t->c.g, t->c.b); } void RG_ColorHSVA(RG_Tile *t, float h, float s, float v, Uint8 a) { AG_HSV2RGB(h, s, v, &t->c.r, &t->c.g, &t->c.b); t->pc = AG_MapRGBA(t->su->format, t->c.r, t->c.g, t->c.b, a); } void RG_ColorUint32(RG_Tile *t, Uint32 pc) { AG_GetRGB(pc, t->su->format, &t->c.r, &t->c.g, &t->c.b); t->pc = pc; } /* Blend the pixel at t:[x,y] with the given RGBA value. */ void RG_BlendRGB(AG_Surface *su, int x, int y, enum rg_prim_blend_mode mode, Uint8 sR, Uint8 sG, Uint8 sB, Uint8 sA) { Uint8 dR, dG, dB, dA; Uint8 *pDst; int alpha; if (x < 0 || y < 0 || x >= su->w || y >= su->h) { return; } pDst = (Uint8 *)su->pixels + y*su->pitch + (x << 2); if (*(Uint32 *)pDst != su->format->colorkey) { AG_GetRGBA(*(Uint32 *)pDst, su->format, &dR,&dG,&dB,&dA); switch (mode) { case RG_PRIM_OVERLAY_ALPHA: alpha = dA + sA; if (alpha > 255) { alpha = 255; } *(Uint32 *)pDst = AG_MapRGBA(su->format, (((sR - dR) * sA) >> 8) + dR, (((sG - dG) * sA) >> 8) + dG, (((sB - dB) * sA) >> 8) + dB, (Uint8)alpha); break; case RG_PRIM_AVERAGE_ALPHA: *(Uint32 *)pDst = AG_MapRGBA(su->format, (((sR - dR) * sA) >> 8) + dR, (((sG - dG) * sA) >> 8) + dG, (((sB - dB) * sA) >> 8) + dB, (Uint8)((dA*sA)/2)); break; case RG_PRIM_SRC_ALPHA: *(Uint32 *)pDst = AG_MapRGBA(su->format, (((sR - dR) * sA) >> 8) + dR, (((sG - dG) * sA) >> 8) + dG, (((sB - dB) * sA) >> 8) + dB, (Uint8)(sA)); break; case RG_PRIM_DST_ALPHA: *(Uint32 *)pDst = AG_MapRGBA(su->format, (((sR - dR) * sA) >> 8) + dR, (((sG - dG) * sA) >> 8) + dG, (((sB - dB) * sA) >> 8) + dB, dA); break; } } else { *(Uint32 *)pDst = AG_MapRGBA(su->format, sR,sG,sB,sA); } } /* * Draw a line segment between two points using the Bresenham algorithm * as presented by Foley & Van Dam [1990]. */ void RG_Line(RG_Tile *t, int x1, int y1, int x2, int y2) { int dx, dy; int inc1, inc2; int d, x, y; int xend, yend; int xdir, ydir; dx = abs(x2-x1); dy = abs(y2-y1); if (dy <= dx) { d = dy*2 - dx; inc1 = dy*2; inc2 = (dy-dx)*2; if (x1 > x2) { x = x2; y = y2; ydir = -1; xend = x1; } else { x = x1; y = y1; ydir = 1; xend = x2; } RG_PutPixel(t->su, x, y, t->pc); if (((y2-y1)*ydir) > 0) { while (x < xend) { x++; if (d < 0) { d += inc1; } else { y++; d += inc2; } RG_PutPixel(t->su, x, y, t->pc); } } else { while (x < xend) { x++; if (d < 0) { d += inc1; } else { y--; d += inc2; } RG_PutPixel(t->su, x, y, t->pc); } } } else { d = dx*2 - dy; inc1 = dx*2; inc2 = (dx-dy)*2; if (y1 > y2) { y = y2; x = x2; yend = y1; xdir = -1; } else { y = y1; x = x1; yend = y2; xdir = 1; } RG_PutPixel(t->su, x, y, t->pc); if (((x2-x1)*xdir) > 0) { while (y < yend) { y++; if (d < 0) { d += inc1; } else { x++; d += inc2; } RG_PutPixel(t->su, x, y, t->pc); } } else { while (y < yend) { y++; if (d < 0) { d += inc1; } else { x--; d += inc2; } RG_PutPixel(t->su, x, y, t->pc); } } } } /* Draw a horizontal line segment. */ void RG_HLine(RG_Tile *t, int x1, int x2, int y, Uint32 c) { int xTmp; Uint8 *pDst, *pEnd; int dx; if (y >= t->su->h || y < 0) { return; } if (x1 >= t->su->w) { x1 = t->su->w - 1; } else if (x1 < 0) { x1 = 0; } if (x2 >= t->su->w) { x2 = t->su->w - 1; } else if (x2 < 0) { x2 = 0; } if (x1 > x2) { xTmp = x2; x2 = x1; x1 = xTmp; } dx = x2 - x1; pDst = (Uint8 *)t->su->pixels + y*t->su->pitch + ((x1)<<2); pEnd = pDst + (dx<<2); while (pDst < pEnd) { *(Uint32 *)pDst = c; pDst += 4; } } /* Draw an antialiased line using the Wu-line algorithm. */ void RG_WuLine(RG_Tile *t, float x1p, float y1p, float x2p, float y2p) { float x1 = x1p, y1 = y1p, x2 = x2p, y2 = y2p; float grad, xd, yd, xgap, xend, yend, xf, yf, lum1, lum2; int x, y, ix1, ix2, iy1, iy2; Uint8 r, g, b, a; xd = x2 - x1; yd = y2 - y1; AG_GetRGBA(t->pc, t->ts->fmt, &r,&g,&b,&a); if (Fabs(xd) > Fabs(yd)) { /* Horizontal */ if (x1 > x2) { float tmp; tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; xd = (x2-x1); yd = (y2-y1); } grad = yd/xd; /* End point 1 */ xend = Truncf(x1+0.5); yend = y1 + grad*(xend-x1); xgap = FracInvf(x1+0.5); ix1 = (int)xend; iy1 = (int)yend; lum1 = FracInvf(yend)*xgap; lum2 = Fracf(yend)*xgap; RG_BlendRGB(t->su, ix1, iy1, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum1*255)); RG_BlendRGB(t->su, ix1, iy1+1, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum2*255)); yf = yend+grad; /* End point 2 */ xend = Truncf(x2+0.5); yend = y2 + grad*(xend-x2); xgap = FracInvf(x2-0.5); ix2 = (int)xend; iy2 = (int)yend; lum1 = FracInvf(yend)*xgap; lum2 = Fracf(yend)*xgap; RG_BlendRGB(t->su, ix2, iy2, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum1*255)); RG_BlendRGB(t->su, ix2, iy2+1, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum2*255)); /* Main loop */ for (x = (ix1+1); x < ix2; x++) { float focus; lum1 = FracInvf(yf); lum2 = Fracf(yf); focus = (1.0 - Fabs(lum1-lum2)); lum1 += 0.3*focus; lum2 += 0.3*focus; RG_BlendRGB(t->su, x, (int)yf, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum1*255)); RG_BlendRGB(t->su, x, (int)yf+1, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum2*255)); yf = yf + grad; } } else { /* Vertical */ if (x1 > x2) { float tmp; tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; xd = (x2 - x1); yd = (y2 - y1); } grad = xd/yd; /* End point 1 */ xend = Truncf(x1+0.5); yend = y1 + grad*(xend-x1); xgap = Fracf(x1+0.5); ix1 = (int)xend; iy1 = (int)yend; lum1 = FracInvf(yend)*xgap; lum2 = Fracf(yend)*xgap; RG_BlendRGB(t->su, ix1, iy1, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum1*255)); RG_BlendRGB(t->su, ix1, iy1+1, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum2*255)); xf = xend + grad; /* End point 2 */ xend = Truncf(x2+0.5); yend = y2 + grad*(xend-x2); xgap = FracInvf(x2-0.5); ix2 = (int)xend; iy2 = (int)yend; lum1 = FracInvf(yend)*xgap; lum2 = Fracf(yend)*xgap; RG_BlendRGB(t->su, ix2, iy2, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum1*255)); RG_BlendRGB(t->su, ix2, iy2+1, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum2*255)); /* Main loop */ for (y = (iy1+1); y < iy2; y++) { float focus; lum1 = FracInvf(xf); lum2 = Fracf(xf); focus = (1.0 - Fabs(lum1-lum2)); lum1 += 0.3*focus; lum2 += 0.3*focus; RG_BlendRGB(t->su, (int)xf, y, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum1*255)); RG_BlendRGB(t->su, (int)xf+1, y, RG_PRIM_OVERLAY_ALPHA, r, g, b, (Uint8)(lum2*255)); xf = xf + grad; } } } /* Draw a circle. */ void RG_Circle2(RG_Tile *t, int wx, int wy, int radius) { int v = 2*radius - 1; int e = 0, u = 1; int x = 0, y = radius; while (x < y) { RG_PutPixel(t->su, wx+x, wy+y, t->pc); RG_PutPixel(t->su, wx+x+1, wy+y, t->pc); RG_PutPixel(t->su, wx+x, wy-y, t->pc); RG_PutPixel(t->su, wx+x+1, wy-y, t->pc); RG_PutPixel(t->su, wx-x, wy+y, t->pc); RG_PutPixel(t->su, wx-x-1, wy+y, t->pc); RG_PutPixel(t->su, wx-x, wy-y, t->pc); RG_PutPixel(t->su, wx-x-1, wy-y, t->pc); e += u; u += 2; if (v < 2*e) { y--; e -= v; v -= 2; } x++; RG_PutPixel(t->su, wx+y, wy+x, t->pc); RG_PutPixel(t->su, wx+y+1, wy+x, t->pc); RG_PutPixel(t->su, wx+y, wy-x, t->pc); RG_PutPixel(t->su, wx+y+1, wy-x, t->pc); RG_PutPixel(t->su, wx-y, wy+x, t->pc); RG_PutPixel(t->su, wx-y-1, wy+x, t->pc); RG_PutPixel(t->su, wx-y, wy-x, t->pc); RG_PutPixel(t->su, wx-y-1, wy-x, t->pc); } RG_PutPixel(t->su, wx-radius, wy, t->pc); RG_PutPixel(t->su, wx+radius, wy, t->pc); }