mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-18 01:05:46 -04:00
Initial community commit
This commit is contained in:
60
Src/Wasabi/bfc/draw/convolve.cpp
Normal file
60
Src/Wasabi/bfc/draw/convolve.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include <precomp.h>
|
||||
|
||||
#include "convolve.h"
|
||||
|
||||
#define RED(a) (((a)>>16)&0xff)
|
||||
#define GRN(a) (((a)>>8)&0xff)
|
||||
#define BLU(a) (((a)&0xff))
|
||||
#define ALP(a) (((a)>>24))
|
||||
|
||||
Convolve3x3::Convolve3x3(ARGB32 *_bits, int _w, int _h) : bits(_bits), w(_w), h(_h) {
|
||||
ZERO(vals);
|
||||
multiplier = 0;
|
||||
}
|
||||
|
||||
void Convolve3x3::setPos(int x, int y, float v) {
|
||||
ASSERT(x >= -1 && x <= 1 && y >= -1 && y <= 1);
|
||||
vals[y+1][x+1] = v;
|
||||
}
|
||||
|
||||
void Convolve3x3::setMultiplier(int m) {
|
||||
multiplier = m;
|
||||
}
|
||||
|
||||
void Convolve3x3::convolve() {
|
||||
if (bits == NULL || w <= 0 || h <= 0) return; // nothin'
|
||||
MemMatrix<ARGB32> temp(w, h, bits); // make a copy
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
if (ALP(temp(x, y))<=1) continue;
|
||||
float ra=0, rg=0, rb=0;
|
||||
for (int a = -1; a <= 1; a++) {
|
||||
for (int b = -1; b <= 1; b++) {
|
||||
int px = x + a, py = y + b;
|
||||
if (px < 0 || px >= w || py < 0 || py >= h) continue;
|
||||
ARGB32 c = temp(px, py);
|
||||
if (ALP(c) <= 1) continue;
|
||||
ra += (float)RED(c) * vals[b][a] * multiplier;
|
||||
rg += (float)GRN(c) * vals[b][a] * multiplier;
|
||||
rb += (float)BLU(c) * vals[b][a] * multiplier;
|
||||
}
|
||||
}
|
||||
unsigned int r = MINMAX((int)ra, 0, 255);
|
||||
unsigned int g = MINMAX((int)rg, 0, 255);
|
||||
unsigned int b = MINMAX((int)rb, 0, 255);
|
||||
unsigned int lum = MAX(MAX(r, g), b);
|
||||
if (lum < 64) lum = 0;
|
||||
else if (lum > 192) lum = 255;
|
||||
//bits[x+y*w] = (ALP(*temp.m(x, y))<<24)|(r<<16)|(g<<8)|(b);
|
||||
bits[x+y*w] &= 0xffffff;
|
||||
bits[x+y*w] |= (255-lum) << 24;
|
||||
//if (lum < 64) {
|
||||
// bits[x+y*w] &= 0xffff00ff;
|
||||
// bits[x+y*w] |= lum << 8;
|
||||
//} else {
|
||||
// bits[x+y*w] &= 0xff00ffff;
|
||||
// bits[x+y*w] |= lum << 16;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
24
Src/Wasabi/bfc/draw/convolve.h
Normal file
24
Src/Wasabi/bfc/draw/convolve.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef _CONVOLVE_H
|
||||
#define _CONVOLVE_H
|
||||
|
||||
#include "platform/types.h"
|
||||
// world's slowest crappiest convolve :P think it sucks? write a better one
|
||||
// and send it to me
|
||||
|
||||
class Convolve3x3 {
|
||||
public:
|
||||
Convolve3x3(ARGB32 *bits, int w, int h);
|
||||
|
||||
void setPos(int x, int y, float v);
|
||||
void setMultiplier(int m);
|
||||
|
||||
void convolve();
|
||||
|
||||
private:
|
||||
ARGB32 *bits;
|
||||
int w, h;
|
||||
float vals[3][3];
|
||||
float multiplier;
|
||||
};
|
||||
|
||||
#endif
|
458
Src/Wasabi/bfc/draw/drawpoly.cpp
Normal file
458
Src/Wasabi/bfc/draw/drawpoly.cpp
Normal file
@ -0,0 +1,458 @@
|
||||
#include <precomp.h>
|
||||
|
||||
#include "drawpoly.h"
|
||||
#include <bfc/parse/pathparse.h>
|
||||
|
||||
#define MAXPOINTS 32
|
||||
|
||||
static ARGB32 *bits, color;
|
||||
static int w, h, across;
|
||||
struct Point2d {
|
||||
int X, Y;
|
||||
};
|
||||
typedef struct Point2d Point2d; // bleh
|
||||
static Point2d points[MAXPOINTS];
|
||||
static int npoints;
|
||||
|
||||
void Draw::beginPolygon(ARGB32 *bits, int w, int h, ARGB32 color) {
|
||||
::bits = bits;
|
||||
::w = w;
|
||||
::h = h;
|
||||
::color = color;
|
||||
::across = w;
|
||||
npoints = 0;
|
||||
}
|
||||
|
||||
void Draw::addPoint(int x, int y) {
|
||||
if (npoints >= MAXPOINTS) return;
|
||||
points[npoints].X = x;
|
||||
points[npoints].Y = y;
|
||||
npoints++;
|
||||
}
|
||||
|
||||
static void premultiply(ARGB32 *m_pBits, int nwords) {
|
||||
for (; nwords > 0; nwords--, m_pBits++) {
|
||||
unsigned __int8 *pixel = (unsigned __int8 *)m_pBits;
|
||||
unsigned int alpha = pixel[3];
|
||||
if (alpha == 255) continue;
|
||||
pixel[0] = (pixel[0] * alpha) >> 8; // blue
|
||||
pixel[1] = (pixel[1] * alpha) >> 8; // green
|
||||
pixel[2] = (pixel[2] * alpha) >> 8; // red
|
||||
}
|
||||
}
|
||||
|
||||
void Draw::drawPointList(ARGB32 *bits, int w, int h, const wchar_t *pointlist) {
|
||||
if (pointlist == NULL || *pointlist == '\0') return;
|
||||
PathParserW outer(pointlist, L"|");
|
||||
const wchar_t *pl;
|
||||
for (int i = 0; (pl = outer.enumString(i)) != NULL; i++)
|
||||
{
|
||||
PathParserW inner(pl, L"=");
|
||||
ARGB32 color = WASABI_API_SKIN->parse(inner.enumStringSafe(1, L"255,255,255,255"), L"coloralpha");
|
||||
int a = color & 0xff000000;
|
||||
color = _byteswap_ulong(color<<8) | a;
|
||||
premultiply(&color, 1);
|
||||
beginPolygon(bits, w, h, color);
|
||||
PathParserW eener(inner.enumStringSafe(0, L"0,0"), L";");
|
||||
const wchar_t *cc;
|
||||
for (int j = 0; (cc = eener.enumString(j)) != NULL; j++) {
|
||||
PathParserW com(cc, L",");
|
||||
const wchar_t *xs = com.enumStringSafe(0, L"0");
|
||||
int x = wcschr(xs, '.') ? (int)floor(WTOF(xs) * w + .5f) : WTOI(xs);
|
||||
const wchar_t *ys = com.enumStringSafe(1, L"0");
|
||||
int y = wcschr(ys, '.') ? (int)floor(WTOF(ys) * h + .5f) : WTOI(ys);
|
||||
addPoint(x, y);
|
||||
}
|
||||
endPolygon();
|
||||
}
|
||||
}
|
||||
|
||||
#define PIXEL ARGB32
|
||||
|
||||
// this originally came from Michael Abrash's Zen of Graphics Programming
|
||||
// been modified a bit
|
||||
/* DRAWPOLY.H: Header file for polygon-filling code */
|
||||
|
||||
/* Describes a single point (used for a single vertex) */
|
||||
|
||||
//struct Point2d {
|
||||
// int X; /* X coordinate */
|
||||
// int Y; /* Y coordinate */
|
||||
//};
|
||||
|
||||
//typedef struct Point2d Point2d;
|
||||
|
||||
typedef struct {
|
||||
int X, Y;
|
||||
} Point2dC;
|
||||
|
||||
/* Describes a series of points (used to store a list of vertices that
|
||||
describe a polygon; each vertex is assumed to connect to the two
|
||||
adjacent vertices, and the last vertex is assumed to connect to the
|
||||
first) */
|
||||
struct Point2dListHeader {
|
||||
int Length; /* # of points */
|
||||
struct Point2d *Point2dPtr; /* pointer to list of points */
|
||||
};
|
||||
|
||||
typedef struct Point2dListHeader Point2dListHeader;
|
||||
|
||||
/* Describes the beginning and ending X coordinates of a single
|
||||
horizontal line */
|
||||
struct HLine {
|
||||
int XStart; /* X coordinate of leftmost pixel in line */
|
||||
int XEnd; /* X coordinate of rightmost pixel in line */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int XStart, XEnd;
|
||||
} HLineColor;
|
||||
|
||||
/* Describes a Length-long series of horizontal lines, all assumed to
|
||||
be on contiguous scan lines starting at YStart and proceeding
|
||||
downward (used to describe a scan-converted polygon to the
|
||||
low-level hardware-dependent drawing code) */
|
||||
struct HLineList {
|
||||
int Length; /* # of horizontal lines */
|
||||
int YStart; /* Y coordinate of topmost line */
|
||||
struct HLine * HLinePtr; /* pointer to list of horz lines */
|
||||
};
|
||||
|
||||
static void DrawHorizontalLineList(struct HLineList * HLineListPtr, PIXEL *dest,
|
||||
PIXEL Color) {
|
||||
struct HLine *HLinePtr, *ptr;
|
||||
int Length, Width, c;
|
||||
PIXEL *ScreenPtr;
|
||||
|
||||
/* Point to the start of the first scan line on which to draw */
|
||||
ScreenPtr = dest + HLineListPtr->YStart * across;
|
||||
Length = HLineListPtr->Length;
|
||||
/* Point to the XStart/XEnd descriptor for the first (top)
|
||||
horizontal line */
|
||||
HLinePtr = HLineListPtr->HLinePtr;
|
||||
|
||||
/* clip left/right */
|
||||
for (ptr = HLinePtr, c = Length; c; c--) {
|
||||
if (ptr->XStart < 0) ptr->XStart = 0;
|
||||
if (ptr->XEnd >= w) ptr->XEnd = w - 1;
|
||||
ptr++;
|
||||
}
|
||||
/* clip top */
|
||||
if (HLineListPtr->YStart < 0) {
|
||||
int skip = -HLineListPtr->YStart;
|
||||
HLineListPtr->YStart = 0;
|
||||
ScreenPtr += across * skip;
|
||||
Length -= skip;
|
||||
HLinePtr += skip;
|
||||
}
|
||||
/* clip bottom */
|
||||
if (HLineListPtr->YStart + Length > h) {
|
||||
Length -= (HLineListPtr->YStart + Length) - h;
|
||||
}
|
||||
|
||||
/* Draw each horizontal line in turn, starting with the top one and
|
||||
advancing one line each time */
|
||||
while (Length-- > 0) {
|
||||
/* Draw the whole horizontal line if it has a positive width */
|
||||
if ((Width = HLinePtr->XEnd - HLinePtr->XStart + 1) > 0)
|
||||
// bmemsetw(ScreenPtr+HLinePtr->XStart, Color, Width);
|
||||
MEMFILL<PIXEL>(ScreenPtr+HLinePtr->XStart, Color, Width);
|
||||
HLinePtr++; /* point to next scan line X info */
|
||||
ScreenPtr += across; /* point to next scan line start */
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan converts an edge from (X1,Y1) to (X2,Y2), not including the
|
||||
point at (X2,Y2). If SkipFirst == 1, the point at (X1,Y1) isn't
|
||||
drawn; if SkipFirst == 0, it is. For each scan line, the pixel
|
||||
closest to the scanned edge without being to the left of the
|
||||
scanned edge is chosen. Uses an all-integer approach for speed and
|
||||
precision
|
||||
|
||||
Link with L21-1.C, L21-3.C, and L22-1.C in Compact model.
|
||||
Tested with Borland C++ 4.02 by Jim Mischel 12/16/94.
|
||||
*/
|
||||
|
||||
static void ScanEdge(int X1, int Y1, int X2, int Y2, int SetXStart,
|
||||
int SkipFirst, struct HLine **EdgePoint2dPtr) {
|
||||
int DeltaX, Height, Width, AdvanceAmt, ErrorTerm, i;
|
||||
int ErrorTermAdvance, XMajorAdvanceAmt;
|
||||
struct HLine *WorkingEdgePoint2dPtr;
|
||||
|
||||
WorkingEdgePoint2dPtr = *EdgePoint2dPtr; /* avoid double dereference */
|
||||
AdvanceAmt = ((DeltaX = X2 - X1) > 0) ? 1 : -1;
|
||||
/* direction in which X moves (Y2 is
|
||||
always > Y1, so Y always counts up) */
|
||||
|
||||
if ((Height = Y2 - Y1) <= 0) /* Y length of the edge */
|
||||
return; /* guard against 0-length and horizontal edges */
|
||||
|
||||
/* Figure out whether the edge is vertical, diagonal, X-major
|
||||
(mostly horizontal), or Y-major (mostly vertical) and handle
|
||||
appropriately */
|
||||
if ((Width = abs(DeltaX)) == 0) {
|
||||
/* The edge is vertical; special-case by just storing the same
|
||||
X coordinate for every scan line */
|
||||
/* Scan the edge for each scan line in turn */
|
||||
for (i = Height - SkipFirst; i-- > 0; WorkingEdgePoint2dPtr++) {
|
||||
/* Store the X coordinate in the appropriate edge list */
|
||||
if (SetXStart == 1)
|
||||
WorkingEdgePoint2dPtr->XStart = X1;
|
||||
else
|
||||
WorkingEdgePoint2dPtr->XEnd = X1;
|
||||
}
|
||||
} else if (Width == Height) {
|
||||
/* The edge is diagonal; special-case by advancing the X
|
||||
coordinate 1 pixel for each scan line */
|
||||
if (SkipFirst) /* skip the first point if so indicated */
|
||||
X1 += AdvanceAmt; /* move 1 pixel to the left or right */
|
||||
/* Scan the edge for each scan line in turn */
|
||||
for (i = Height - SkipFirst; i-- > 0; WorkingEdgePoint2dPtr++) {
|
||||
/* Store the X coordinate in the appropriate edge list */
|
||||
if (SetXStart == 1)
|
||||
WorkingEdgePoint2dPtr->XStart = X1;
|
||||
else
|
||||
WorkingEdgePoint2dPtr->XEnd = X1;
|
||||
X1 += AdvanceAmt; /* move 1 pixel to the left or right */
|
||||
}
|
||||
} else if (Height > Width) {
|
||||
/* Edge is closer to vertical than horizontal (Y-major) */
|
||||
if (DeltaX >= 0)
|
||||
ErrorTerm = 0; /* initial error term going left->right */
|
||||
else
|
||||
ErrorTerm = -Height + 1; /* going right->left */
|
||||
if (SkipFirst) { /* skip the first point if so indicated */
|
||||
/* Determine whether it's time for the X coord to advance */
|
||||
if ((ErrorTerm += Width) > 0) {
|
||||
X1 += AdvanceAmt; /* move 1 pixel to the left or right */
|
||||
ErrorTerm -= Height; /* advance ErrorTerm to next point */
|
||||
}
|
||||
}
|
||||
/* Scan the edge for each scan line in turn */
|
||||
for (i = Height - SkipFirst; i-- > 0; WorkingEdgePoint2dPtr++) {
|
||||
/* Store the X coordinate in the appropriate edge list */
|
||||
if (SetXStart == 1)
|
||||
WorkingEdgePoint2dPtr->XStart = X1;
|
||||
else
|
||||
WorkingEdgePoint2dPtr->XEnd = X1;
|
||||
/* Determine whether it's time for the X coord to advance */
|
||||
if ((ErrorTerm += Width) > 0) {
|
||||
X1 += AdvanceAmt; /* move 1 pixel to the left or right */
|
||||
ErrorTerm -= Height; /* advance ErrorTerm to correspond */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Edge is closer to horizontal than vertical (X-major) */
|
||||
/* Minimum distance to advance X each time */
|
||||
XMajorAdvanceAmt = (Width / Height) * AdvanceAmt;
|
||||
/* Error term advance for deciding when to advance X 1 extra */
|
||||
ErrorTermAdvance = Width % Height;
|
||||
if (DeltaX >= 0)
|
||||
ErrorTerm = 0; /* initial error term going left->right */
|
||||
else
|
||||
ErrorTerm = -Height + 1; /* going right->left */
|
||||
if (SkipFirst) { /* skip the first point if so indicated */
|
||||
X1 += XMajorAdvanceAmt; /* move X minimum distance */
|
||||
/* Determine whether it's time for X to advance one extra */
|
||||
if ((ErrorTerm += ErrorTermAdvance) > 0) {
|
||||
X1 += AdvanceAmt; /* move X one more */
|
||||
ErrorTerm -= Height; /* advance ErrorTerm to correspond */
|
||||
}
|
||||
}
|
||||
/* Scan the edge for each scan line in turn */
|
||||
for (i = Height - SkipFirst; i-- > 0; WorkingEdgePoint2dPtr++) {
|
||||
/* Store the X coordinate in the appropriate edge list */
|
||||
if (SetXStart == 1)
|
||||
WorkingEdgePoint2dPtr->XStart = X1;
|
||||
else
|
||||
WorkingEdgePoint2dPtr->XEnd = X1;
|
||||
X1 += XMajorAdvanceAmt; /* move X minimum distance */
|
||||
/* Determine whether it's time for X to advance one extra */
|
||||
if ((ErrorTerm += ErrorTermAdvance) > 0) {
|
||||
X1 += AdvanceAmt; /* move X one more */
|
||||
ErrorTerm -= Height; /* advance ErrorTerm to correspond */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*EdgePoint2dPtr = WorkingEdgePoint2dPtr; /* advance caller's ptr */
|
||||
}
|
||||
|
||||
/* Color-fills a convex polygon. All vertices are offset by (XOffset,
|
||||
YOffset). "Convex" means that every horizontal line drawn through
|
||||
the polygon at any point would cross exactly two active edges
|
||||
(neither horizontal lines nor zero-length edges count as active
|
||||
edges; both are acceptable anywhere in the polygon), and that the
|
||||
right & left edges never cross. (It's OK for them to touch, though,
|
||||
so long as the right edge never crosses over to the left of the
|
||||
left edge.) Nonconvex polygons won't be drawn properly. Returns 1
|
||||
for success, 0 if memory allocation failed.
|
||||
|
||||
Compiled with Borland C++ 4.02. Link with L21-3.C.
|
||||
Checked by Jim Mischel 11/30/94.
|
||||
*/
|
||||
|
||||
/* Advances the index by one vertex forward through the vertex list,
|
||||
wrapping at the end of the list */
|
||||
#define INDEX_FORWARD(Index) \
|
||||
Index = (Index + 1) % VertexList->Length;
|
||||
|
||||
/* Advances the index by one vertex backward through the vertex list,
|
||||
wrapping at the start of the list */
|
||||
#define INDEX_BACKWARD(Index) \
|
||||
Index = (Index - 1 + VertexList->Length) % VertexList->Length;
|
||||
|
||||
/* Advances the index by one vertex either forward or backward through
|
||||
the vertex list, wrapping at either end of the list */
|
||||
#define INDEX_MOVE(Index,Direction) \
|
||||
if (Direction > 0) \
|
||||
Index = (Index + 1) % VertexList->Length; \
|
||||
else \
|
||||
Index = (Index - 1 + VertexList->Length) % VertexList->Length;
|
||||
|
||||
int FillConvexPolygon(struct Point2dListHeader *VertexList, PIXEL *dest,
|
||||
PIXEL Color) {
|
||||
int i, MinIndexL, MaxIndex, MinIndexR, SkipFirst, Temp;
|
||||
int MinPoint2d_Y, MaxPoint2d_Y, TopIsFlat, LeftEdgeDir;
|
||||
int NextIndex, CurrentIndex, PreviousIndex;
|
||||
int DeltaXN, DeltaYN, DeltaXP, DeltaYP;
|
||||
struct HLineList WorkingHLineList;
|
||||
struct HLine *EdgePoint2dPtr;
|
||||
struct Point2d *VertexPtr;
|
||||
|
||||
/* Point to the vertex list */
|
||||
VertexPtr = VertexList->Point2dPtr;
|
||||
|
||||
/* Scan the list to find the top and bottom of the polygon */
|
||||
if (VertexList->Length == 0)
|
||||
return(1); /* reject null polygons */
|
||||
MaxPoint2d_Y = MinPoint2d_Y = VertexPtr[MinIndexL = MaxIndex = 0].Y;
|
||||
for (i = 1; i < VertexList->Length; i++) {
|
||||
if (VertexPtr[i].Y < MinPoint2d_Y)
|
||||
MinPoint2d_Y = VertexPtr[MinIndexL = i].Y; /* new top */
|
||||
else if (VertexPtr[i].Y > MaxPoint2d_Y)
|
||||
MaxPoint2d_Y = VertexPtr[MaxIndex = i].Y; /* new bottom */
|
||||
}
|
||||
if (MinPoint2d_Y == MaxPoint2d_Y)
|
||||
return(1); /* polygon is 0-height; avoid infinite loop below */
|
||||
|
||||
/* Scan in ascending order to find the last top-edge point */
|
||||
MinIndexR = MinIndexL;
|
||||
while (VertexPtr[MinIndexR].Y == MinPoint2d_Y)
|
||||
INDEX_FORWARD(MinIndexR);
|
||||
INDEX_BACKWARD(MinIndexR); /* back up to last top-edge point */
|
||||
|
||||
/* Now scan in descending order to find the first top-edge point */
|
||||
while (VertexPtr[MinIndexL].Y == MinPoint2d_Y)
|
||||
INDEX_BACKWARD(MinIndexL);
|
||||
INDEX_FORWARD(MinIndexL); /* back up to first top-edge point */
|
||||
|
||||
/* Figure out which direction through the vertex list from the top
|
||||
vertex is the left edge and which is the right */
|
||||
LeftEdgeDir = -1; /* assume left edge runs down thru vertex list */
|
||||
if ((TopIsFlat = (VertexPtr[MinIndexL].X !=
|
||||
VertexPtr[MinIndexR].X) ? 1 : 0) == 1) {
|
||||
/* If the top is flat, just see which of the ends is leftmost */
|
||||
if (VertexPtr[MinIndexL].X > VertexPtr[MinIndexR].X) {
|
||||
LeftEdgeDir = 1; /* left edge runs up through vertex list */
|
||||
Temp = MinIndexL; /* swap the indices so MinIndexL */
|
||||
MinIndexL = MinIndexR; /* points to the start of the left */
|
||||
MinIndexR = Temp; /* edge, similarly for MinIndexR */
|
||||
}
|
||||
} else {
|
||||
/* Point to the downward end of the first line of each of the
|
||||
two edges down from the top */
|
||||
NextIndex = MinIndexR;
|
||||
INDEX_FORWARD(NextIndex);
|
||||
PreviousIndex = MinIndexL;
|
||||
INDEX_BACKWARD(PreviousIndex);
|
||||
/* Calculate X and Y lengths from the top vertex to the end of
|
||||
the first line down each edge; use those to compare slopes
|
||||
and see which line is leftmost */
|
||||
DeltaXN = VertexPtr[NextIndex].X - VertexPtr[MinIndexL].X;
|
||||
DeltaYN = VertexPtr[NextIndex].Y - VertexPtr[MinIndexL].Y;
|
||||
DeltaXP = VertexPtr[PreviousIndex].X - VertexPtr[MinIndexL].X;
|
||||
DeltaYP = VertexPtr[PreviousIndex].Y - VertexPtr[MinIndexL].Y;
|
||||
if (((long)DeltaXN * DeltaYP - (long)DeltaYN * DeltaXP) < 0L) {
|
||||
LeftEdgeDir = 1; /* left edge runs up through vertex list */
|
||||
Temp = MinIndexL; /* swap the indices so MinIndexL */
|
||||
MinIndexL = MinIndexR; /* points to the start of the left */
|
||||
MinIndexR = Temp; /* edge, similarly for MinIndexR */
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the # of scan lines in the polygon, skipping the bottom edge
|
||||
and also skipping the top vertex if the top isn't flat because
|
||||
in that case the top vertex has a right edge component, and set
|
||||
the top scan line to draw, which is likewise the second line of
|
||||
the polygon unless the top is flat */
|
||||
if ((WorkingHLineList.Length =
|
||||
MaxPoint2d_Y - MinPoint2d_Y - 1 + TopIsFlat) <= 0)
|
||||
return(1); /* there's nothing to draw, so we're done */
|
||||
//WorkingHLineList.YStart = YOffset + MinPoint2d_Y + 1 - TopIsFlat;
|
||||
WorkingHLineList.YStart = MinPoint2d_Y + 1 - TopIsFlat;
|
||||
|
||||
/* Get memory in which to store the line list we generate */
|
||||
if ((WorkingHLineList.HLinePtr =
|
||||
(struct HLine *) (malloc(sizeof(struct HLine) *
|
||||
WorkingHLineList.Length))) == NULL)
|
||||
return(0); /* couldn't get memory for the line list */
|
||||
|
||||
/* Scan the left edge and store the boundary points in the list */
|
||||
/* Initial pointer for storing scan converted left-edge coords */
|
||||
EdgePoint2dPtr = WorkingHLineList.HLinePtr;
|
||||
/* Start from the top of the left edge */
|
||||
PreviousIndex = CurrentIndex = MinIndexL;
|
||||
/* Skip the first point of the first line unless the top is flat;
|
||||
if the top isn't flat, the top vertex is exactly on a right
|
||||
edge and isn't drawn */
|
||||
SkipFirst = TopIsFlat ? 0 : 1;
|
||||
/* Scan convert each line in the left edge from top to bottom */
|
||||
do {
|
||||
INDEX_MOVE(CurrentIndex,LeftEdgeDir);
|
||||
ScanEdge(VertexPtr[PreviousIndex].X,
|
||||
VertexPtr[PreviousIndex].Y,
|
||||
VertexPtr[CurrentIndex].X,
|
||||
VertexPtr[CurrentIndex].Y, 1, SkipFirst, &EdgePoint2dPtr);
|
||||
PreviousIndex = CurrentIndex;
|
||||
SkipFirst = 0; /* scan convert the first point from now on */
|
||||
} while (CurrentIndex != MaxIndex);
|
||||
|
||||
/* Scan the right edge and store the boundary points in the list */
|
||||
EdgePoint2dPtr = WorkingHLineList.HLinePtr;
|
||||
PreviousIndex = CurrentIndex = MinIndexR;
|
||||
SkipFirst = TopIsFlat ? 0 : 1;
|
||||
/* Scan convert the right edge, top to bottom. X coordinates are
|
||||
adjusted 1 to the left, effectively causing scan conversion of
|
||||
the nearest points to the left of but not exactly on the edge */
|
||||
do {
|
||||
INDEX_MOVE(CurrentIndex,-LeftEdgeDir);
|
||||
//ScanEdge(VertexPtr[PreviousIndex].X + XOffset - 1,
|
||||
ScanEdge(VertexPtr[PreviousIndex].X - 1,
|
||||
VertexPtr[PreviousIndex].Y,
|
||||
//VertexPtr[CurrentIndex].X + XOffset - 1,
|
||||
VertexPtr[CurrentIndex].X - 1,
|
||||
VertexPtr[CurrentIndex].Y, 0, SkipFirst, &EdgePoint2dPtr);
|
||||
PreviousIndex = CurrentIndex;
|
||||
SkipFirst = 0; /* scan convert the first point from now on */
|
||||
} while (CurrentIndex != MaxIndex);
|
||||
|
||||
/* Draw the line list representing the scan converted polygon */
|
||||
//CUT (*drawfn)(&WorkingHLineList, dest, Color, vc);
|
||||
DrawHorizontalLineList(&WorkingHLineList, dest, Color);
|
||||
|
||||
/* Release the line list's memory and we're successfully done */
|
||||
free(WorkingHLineList.HLinePtr);
|
||||
return(1);
|
||||
}
|
||||
|
||||
// done with abrashitude
|
||||
|
||||
void Draw::endPolygon() {
|
||||
if (npoints == 0) return;
|
||||
|
||||
struct Point2dListHeader head;
|
||||
head.Length = npoints;
|
||||
head.Point2dPtr = &points[0];
|
||||
FillConvexPolygon(&head, bits, color);
|
||||
}
|
16
Src/Wasabi/bfc/draw/drawpoly.h
Normal file
16
Src/Wasabi/bfc/draw/drawpoly.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _DRAWPOLY_H
|
||||
#define _DRAWPOLY_H
|
||||
|
||||
#include <bfc/wasabi_std.h>
|
||||
|
||||
class Draw {
|
||||
public:
|
||||
static void beginPolygon(ARGB32 *bits, int w, int h, ARGB32 color);
|
||||
static void addPoint(int x, int y);
|
||||
static void endPolygon();
|
||||
static void drawPointList(ARGB32 *bits, int w, int h, const wchar_t *pointlist);
|
||||
};
|
||||
|
||||
// x,y;x,y;x,y;x,y=R,G,B|x,y;x,y;x,y;=R,G,B
|
||||
|
||||
#endif
|
309
Src/Wasabi/bfc/draw/gradient.cpp
Normal file
309
Src/Wasabi/bfc/draw/gradient.cpp
Normal file
@ -0,0 +1,309 @@
|
||||
#include <precomp.h>
|
||||
|
||||
#include "gradient.h"
|
||||
|
||||
#include <math.h>//floor
|
||||
#include <bfc/ptrlist.h>
|
||||
#include <bfc/parse/pathparse.h>
|
||||
|
||||
|
||||
#define DEFAULT_GRAD_MODE L"linear"
|
||||
|
||||
template<class T> inline void SWAP(T &a, T &b) {
|
||||
T c = a;
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline unsigned int LERPu(unsigned int a, unsigned int b, double p) {
|
||||
// ASSERT(p >= 0);
|
||||
// ASSERT(p <= 1.f);
|
||||
unsigned int ret = (unsigned int)((double)b * p + (double)a * (1. - p));
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline float LERPf(double a, double b, float p) {
|
||||
// ASSERT(p >= 0);
|
||||
// ASSERT(p <= 1.f);
|
||||
return (float)(b * p + a * (1. - p));
|
||||
}
|
||||
|
||||
Gradient::Gradient() :
|
||||
gammagroup(L"")
|
||||
{
|
||||
gradient_x1 = 0.0f;
|
||||
gradient_y1 = 0.0f;
|
||||
gradient_x2 = 1.0f;
|
||||
gradient_y2 = 1.0f;
|
||||
reverse_colors = 0;
|
||||
antialias = 0;
|
||||
mode = DEFAULT_GRAD_MODE;
|
||||
list.addItem(new GradientPoint(0.0f, 0xff00ff00));
|
||||
list.addItem(new GradientPoint(.5, 0x000000ff));
|
||||
list.addItem(new GradientPoint(1.0f, 0xffff0000));
|
||||
}
|
||||
|
||||
Gradient::~Gradient() {
|
||||
list.deleteAll();
|
||||
}
|
||||
|
||||
void Gradient::setX1(float x1) {
|
||||
gradient_x1 = x1;
|
||||
onParamChange();
|
||||
}
|
||||
|
||||
void Gradient::setY1(float y1) {
|
||||
gradient_y1 = y1;
|
||||
onParamChange();
|
||||
}
|
||||
|
||||
void Gradient::setX2(float x2) {
|
||||
gradient_x2 = x2;
|
||||
onParamChange();
|
||||
}
|
||||
|
||||
void Gradient::setY2(float y2) {
|
||||
gradient_y2 = y2;
|
||||
onParamChange();
|
||||
}
|
||||
|
||||
void Gradient::clearPoints() {
|
||||
list.deleteAll();
|
||||
onParamChange();
|
||||
}
|
||||
|
||||
void Gradient::addPoint(float pos, ARGB32 color)
|
||||
{
|
||||
list.addItem(new GradientPoint(pos, color, gammagroup));
|
||||
onParamChange();
|
||||
}
|
||||
|
||||
void Gradient::setPoints(const wchar_t *pointlist)
|
||||
{
|
||||
clearPoints();
|
||||
if (pointlist == NULL || *pointlist == '\0') return;
|
||||
// 0.5=233,445,245,123;
|
||||
PathParserW pp(pointlist, L";");
|
||||
if (pp.getNumStrings() <= 0) return;
|
||||
for (int i = 0; i < pp.getNumStrings(); i++)
|
||||
{
|
||||
PathParserW rp(pp.enumString(i), L"=");
|
||||
if (rp.getNumStrings() != 2)
|
||||
continue;
|
||||
float pos = (float)WTOF(rp.enumString(0));
|
||||
ARGB32 color = (ARGB32)WASABI_API_SKIN->parse(rp.enumString(1), L"coloralpha");
|
||||
addPoint(pos, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Gradient::setReverseColors(int c) {
|
||||
reverse_colors = c;
|
||||
}
|
||||
|
||||
void Gradient::setAntialias(int c) {
|
||||
antialias = c;
|
||||
}
|
||||
|
||||
void Gradient::setMode(const wchar_t *_mode) {
|
||||
mode = _mode;
|
||||
if (mode.isempty())
|
||||
mode = DEFAULT_GRAD_MODE;
|
||||
}
|
||||
|
||||
void Gradient::setGammaGroup(const wchar_t *group) {
|
||||
gammagroup = group;
|
||||
// reset our points
|
||||
foreach(list)
|
||||
list.getfor()->color.setColorGroup(group);
|
||||
endfor
|
||||
}
|
||||
|
||||
static inline ARGB32 colorLerp(ARGB32 color1, ARGB32 color2, double pos) {
|
||||
unsigned int a1 = (color1>>24) & 0xff;
|
||||
unsigned int a2 = (color2>>24) & 0xff;
|
||||
unsigned int r1 = (color1>>16) & 0xff;
|
||||
unsigned int r2 = (color2>>16) & 0xff;
|
||||
unsigned int g1 = (color1>>8) & 0xff;
|
||||
unsigned int g2 = (color2>>8) & 0xff;
|
||||
unsigned int b1 = (color1) & 0xff;
|
||||
unsigned int b2 = (color2) & 0xff;
|
||||
return (LERPu(a1, a2, pos)<<24) | (LERPu(r1, r2, pos) << 16) | (LERPu(g1,g2,pos)<<8) | LERPu(b1, b2, pos);
|
||||
}
|
||||
|
||||
void Gradient::renderGrad(ARGB32 *ptr, int len, int *positions) {
|
||||
|
||||
int npos = list.getNumItems();
|
||||
ASSERT(npos >= 2);
|
||||
|
||||
ARGB32 color1, color2;
|
||||
for (int i = 0; i < npos-1; i++) {
|
||||
color1 = list.q(i)->color.getColor();
|
||||
color2 = list.q(i+1)->color.getColor();
|
||||
|
||||
if (reverse_colors) {
|
||||
color1 = BGRATOARGB(color1);
|
||||
color2 = BGRATOARGB(color2);
|
||||
}
|
||||
|
||||
int x1 = positions[i];
|
||||
int x2 = positions[i+1];
|
||||
if (x1 == x2) continue;
|
||||
// hflip if need be
|
||||
if (x1 > x2) {
|
||||
SWAP(x1, x2);
|
||||
SWAP(color1, color2);
|
||||
}
|
||||
float c = 0;
|
||||
float segment_len = (float)((x2 - x1)+1);
|
||||
|
||||
if (x1 < 0) { // clip left
|
||||
c += -x1;
|
||||
x1 = 0;
|
||||
}
|
||||
for (int x = x1; x < x2; x++, c += 1.0f) {
|
||||
if (x >= len) break; // clip right
|
||||
ptr[x] = colorLerp(color1, color2, c / segment_len);
|
||||
}
|
||||
}
|
||||
#if 0//later
|
||||
// fill in left if needed
|
||||
if (positions[0] > 0) MEMFILL<ARGB32>(ptr, list.q(0)->color, positions[0]);
|
||||
|
||||
// and right if needed
|
||||
int rpos = positions[npos-1];
|
||||
if (rpos < len) MEMFILL<ARGB32>(ptr+rpos, list.getLast()->color, len-rpos);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Gradient::renderGradient(ARGB32 *bits, int w, int h, int pitch)
|
||||
{
|
||||
if (pitch == 0)
|
||||
pitch = w;
|
||||
|
||||
list.sort();
|
||||
|
||||
ARGB32 default_color = 0xffff00ff;
|
||||
if (list.getNumItems() == 1) default_color = list.q(0)->color.getColor();
|
||||
// blank it out to start
|
||||
if (pitch == w)
|
||||
MEMFILL<ARGB32>(bits, default_color, w * h);
|
||||
else
|
||||
{
|
||||
for (int i=0;i<h;i++)
|
||||
MEMFILL<ARGB32>(bits+i*pitch, default_color, w);
|
||||
}
|
||||
|
||||
if (list.getNumItems() > 1) {
|
||||
if (mode.iscaseequal(L"linear")) {
|
||||
//FUCKO: not if endcaps are filled
|
||||
|
||||
// force non-vertical lines
|
||||
if (ABS(gradient_x1 - gradient_x2) < 0.0005f) gradient_x2 = gradient_x1+0.0005f;
|
||||
|
||||
double px1 = gradient_x1 * w, py1 = gradient_y1 * h;
|
||||
double px2 = gradient_x2 * w, py2 = gradient_y2 * h;
|
||||
|
||||
// convert to y = mx + b
|
||||
double m = (py2 - py1)/(px2 - px1);
|
||||
m = -1.f/m; // invert the slope
|
||||
|
||||
int nitems = list.getNumItems();
|
||||
|
||||
// get the in-pixels x and y for points on the gradient
|
||||
for (int i = 0; i < nitems; i++) {
|
||||
GradientPoint *gp = list.q(i);
|
||||
// need x and y given pos
|
||||
gp->x = LERPf(px1, px2, gp->pos);
|
||||
gp->y = LERPf(py1, py2, gp->pos);
|
||||
}
|
||||
|
||||
MemBlock<int> positions(nitems);
|
||||
for (int _y = 0; _y < h; _y++) {
|
||||
// project all the color points onto this scanline
|
||||
for (int i = 0; i < nitems; i++) {
|
||||
GradientPoint *gp = list.q(i);
|
||||
// y = mx + b
|
||||
// b = y - mx;
|
||||
double newb = gp->y - m * gp->x;
|
||||
// y = mx + newb
|
||||
// y - newb = mx
|
||||
// (y - newb)/m = x
|
||||
double xxx = (_y - newb)/m;
|
||||
positions[i] = (int)floor(xxx+0.5f);
|
||||
}
|
||||
renderGrad(bits+_y*pitch, w, positions);
|
||||
}
|
||||
} else if (mode.iscaseequal(L"circular")) {
|
||||
double tot = SQRT(SQR(gradient_x1 - gradient_x2) + SQR(gradient_y1 - gradient_y2));
|
||||
foreach(list)
|
||||
GradientPoint *gp = list.getfor();
|
||||
gp->dist = gp->pos * tot;
|
||||
endfor
|
||||
|
||||
ARGB32 *dst = bits;
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
ARGB32 c;
|
||||
if (antialias) {
|
||||
double fx = (((double)x)-0.5f) / (double)w;
|
||||
double fy = (((double)y)-0.5f) / (double)h;
|
||||
ARGB32 ul = getPixelCirc(fx, fy);
|
||||
fx = (((double)x)+0.5f) / (double)w;
|
||||
fy = (((double)y)-0.5f) / (double)h;
|
||||
ARGB32 ur = getPixelCirc(fx, fy);
|
||||
fx = (((double)x)+0.5f) / (double)w;
|
||||
fy = (((double)y)+0.5f) / (double)h;
|
||||
ARGB32 lr = getPixelCirc(fx, fy);
|
||||
fx = (((double)x)-0.5f) / (double)w;
|
||||
fy = (((double)y)+0.5f) / (double)h;
|
||||
ARGB32 ll = getPixelCirc(fx, fy);
|
||||
c = colorLerp(colorLerp(ll, lr, 0.5f), colorLerp(ul, ur, 0.5f), 0.5);
|
||||
} else {
|
||||
double fy = (double)y / (double)h;
|
||||
double fx = (double)x / (double)w;
|
||||
c = getPixelCirc(fx, fy);
|
||||
}
|
||||
*dst++ = c;
|
||||
}
|
||||
dst += (pitch-w);
|
||||
}
|
||||
}
|
||||
}//list.getNumItems()>1
|
||||
|
||||
if (pitch == w)
|
||||
premultiplyARGB32(bits, w * h);
|
||||
else
|
||||
{
|
||||
for (int i=0;i<h;i++)
|
||||
premultiplyARGB32(bits+i*pitch, w);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ARGB32 Gradient::getPixelCirc(double fx, double fy) {
|
||||
int nitems = list.getNumItems();
|
||||
//double dist = SQR(fx - gradient_x1) + SQR(fy - gradient_y1);
|
||||
double dist = SQRT(SQR(fx - gradient_x1) + SQR(fy - gradient_y1));
|
||||
ARGB32 c = 0xff00ff00;
|
||||
if (dist <= list.q(0)->dist)
|
||||
c = list.q(0)->color.getColor();
|
||||
else if (dist >= list.getLast()->dist)
|
||||
c = list.getLast()->color.getColor();
|
||||
else for (int i = 0; i < nitems-1; i++) {
|
||||
if (list.q(i)->dist <= dist && list.q(i+1)->dist >= dist) {
|
||||
double pdist = list.q(i+1)->dist - list.q(i)->dist;
|
||||
double pp = dist - list.q(i)->dist;
|
||||
pp /= pdist;
|
||||
if (list.q(i)->color.getColor() == list.q(i+1)->color.getColor())
|
||||
c = list.q(i)->color.getColor();
|
||||
else
|
||||
c = colorLerp(list.q(i)->color.getColor(), list.q(i+1)->color.getColor(), pp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reverse_colors) c = BGRATOARGB(c);
|
||||
return c;
|
||||
}
|
67
Src/Wasabi/bfc/draw/gradient.h
Normal file
67
Src/Wasabi/bfc/draw/gradient.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef _GRADIENT_H
|
||||
#define _GRADIENT_H
|
||||
|
||||
#include <bfc/wasabi_std.h>
|
||||
#include <bfc/string/StringW.h>
|
||||
#include <tataki/color/filteredcolor.h>
|
||||
|
||||
class GradientPoint
|
||||
{
|
||||
public:
|
||||
GradientPoint(float p, ARGB32 c, const wchar_t *group=L"") : pos(p), dist(0), color(c, group), x(0), y(0) { }
|
||||
float pos;
|
||||
double dist;
|
||||
FilteredColor color;
|
||||
float x, y;
|
||||
static int compareItem(GradientPoint *p1, GradientPoint* p2) {
|
||||
int r = CMP3(p1->pos, p2->pos);
|
||||
if (r == 0) return CMP3(p1, p2);
|
||||
else return r;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Gradient
|
||||
{
|
||||
public:
|
||||
Gradient();
|
||||
virtual ~Gradient();
|
||||
|
||||
void setX1(float x1);
|
||||
void setY1(float y1);
|
||||
void setX2(float x2);
|
||||
void setY2(float y2);
|
||||
|
||||
void clearPoints();
|
||||
void addPoint(float pos, ARGB32 color);
|
||||
|
||||
// "pos=color;pos=color" "0.25=34,45,111"
|
||||
void setPoints(const wchar_t *str);
|
||||
|
||||
void setReverseColors(int c);
|
||||
|
||||
void setAntialias(int c);
|
||||
|
||||
void setMode(const wchar_t *mode);
|
||||
|
||||
void setGammaGroup(const wchar_t *group);
|
||||
|
||||
// note: this will automatically premultiply against alpha
|
||||
void renderGradient(ARGB32 *bits, int width, int height, int pitch=0);
|
||||
|
||||
protected:
|
||||
virtual void onParamChange() { }
|
||||
|
||||
ARGB32 getPixelCirc(double x, double y);
|
||||
|
||||
private:
|
||||
float gradient_x1, gradient_y1, gradient_x2, gradient_y2;
|
||||
class GradientList : public PtrListQuickSorted<GradientPoint, GradientPoint> { };
|
||||
GradientList list;
|
||||
void renderGrad(ARGB32 *bits, int len, int *positions);
|
||||
int reverse_colors;
|
||||
int antialias;
|
||||
StringW mode, gammagroup;
|
||||
};
|
||||
|
||||
#endif
|
17
Src/Wasabi/bfc/draw/skinfilter.cpp
Normal file
17
Src/Wasabi/bfc/draw/skinfilter.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include <precomp.h>
|
||||
|
||||
#include "skinfilter.h"
|
||||
|
||||
#include <studio/services/svc_skinfilter.h>
|
||||
|
||||
void ApplySkinFilters::apply(const char *elementid, const char *forced_gammagroup, ARGB32 *bits, int w, int h, int bpp) {
|
||||
if ((elementid == NULL && forced_gammagroup == NULL) || bits == NULL || w <= 0 || h <= 0) return;
|
||||
SkinFilterEnum sfe;
|
||||
|
||||
while (1) {
|
||||
svc_skinFilter *obj = sfe.getNext(FALSE);
|
||||
if (!obj) break;
|
||||
obj->filterBitmap((unsigned char *)bits, w, h, bpp, elementid, forced_gammagroup);
|
||||
sfe.getLastFactory()->releaseInterface(obj);
|
||||
}
|
||||
}
|
11
Src/Wasabi/bfc/draw/skinfilter.h
Normal file
11
Src/Wasabi/bfc/draw/skinfilter.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef _SKINFILTER_H
|
||||
#define _SKINFILTER_H
|
||||
|
||||
#include <bfc/std.h>
|
||||
|
||||
class ApplySkinFilters {
|
||||
public:
|
||||
static void apply(const char *element_id, const char *forced_gammagroup, ARGB32 *bits, int w, int h, int bpp=32);
|
||||
};
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user