Initial community commit

This commit is contained in:
Jef
2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit 20d28e80a5
16810 changed files with 4640254 additions and 2 deletions

View 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;
//}
}
}
}

View 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

View 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);
}

View 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

View 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;
}

View 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

View 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);
}
}

View 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