Heffer.cpp
C++ source for C++ graphics effects, 2643 lines. Raw file
/*
Heffer - Lewpen's 2D graphics lib
Heffer.CPP
Deep Red/Lewpen
*/
#include "../Main/ERisk.h"
/*---- COMMENTS --------------------------------------------------------------//
TODOs
-
Make alpha so that 0 is opaque and 255 is transparent - this means that to
plot a full pixel you can just use (0xrrggbb)
NOTES
-
The blits onto ABGR haven't been tested - I just made up the way to combine
source and destination alpha. The rule is that alpha blitting should be
assocative - ie. (a+b)+c = a+(b+c) where a b and c are images with alpha.
TYPES
-
HEFFER_IMAGE
HEFFER_FONT
A font is an 8-bit greyscale image containing the characters 0-255 and an
array of x-co-ordinates and widths for extracting the characters.
These can be generated from an image of the characters.
FUNCTIONS
-
BOOL Heffer_Startup();
BOOL Heffer_Shutdown();
Must be called at start & end of program. Return TRUE on success.
HEFFER_IMAGE *Heffer_LoadBitmapResource(HINSTANCE hInst, char *name);
HEFFER_IMAGE *Heffer_LoadTargaResource(HINSTANCE hInst, char *name);
Loads images from a executable's resource file.
hInst - the process handle of the executable
name - the ASCII name of the resource
returns a pointer to the created image
BITMAP images are loaded as 24-bit BGR (HEFFER_FORMAT_BGR24)
TARGA images are loaded as 32-bit ABGR (HEFFER_FORMAT_ABGR32)
HEFFER_IMAGE *Heffer_CreateImage(int w, int h, char format);
Creates a blank image with the given dimentions and format
BOOL Heffer_DeleteImage(HEFFER_IMAGE *im);
Deletes an image and any data associated with it.
void Heffer_Image_Display(HDC dc, HEFFER_IMAGE *im, int x, int y);
BOOL Heffer_GetImage(HEFFER_IMAGE *imdest, int dx, int dy, int w, int h, HDC dc, int sx, int sy, int flags);
void Heffer_Blit(HEFFER_IMAGE *imsrc, int dx, int dy, int w, int h, HEFFER_IMAGE *imdest, int sx, int sy, int flags);
void Heffer_AlphaBlit(HEFFER_IMAGE *imsrc, int dx, int dy, int w, int h, HEFFER_IMAGE *imdest, int sx, int sy, unsigned char alpha, int flags);
void Heffer_AlphaRect(HEFFER_IMAGE *imdest, int dx, int dy, int w, int h, int col);
void Heffer_DarkenRect(HEFFER_IMAGE *im, int x, int y, int w, int h);
void Heffer_BlurRect(HEFFER_IMAGE *im, int x, int y, int w, int h);
void Heffer_DrawDot(HEFFER_IMAGE *im, int x, int y, int col);
void Heffer_PutPixel(HEFFER_IMAGE *im, int x, int y, int col);
int Heffer_GetPixel(HEFFER_IMAGE *im, int x, int y);
void Heffer_DrawLine(HEFFER_IMAGE *im, int x1, int y1, int x2, int y2, int col);
void Heffer_DrawRing(HEFFER_IMAGE *im, float x1, float y1, float x2, float y2, int col);
HRGN Heffer_RegionFromImage(HEFFER_IMAGE *im, int col);
Creates a Windows HRGN object from an image and a transparent colour.
im - image to create region from
col - solid colour to use as transparent (0x00bbggrr)
Returns an HRGN which can be used in functions such as SetWindowRgn for
changing the shape of a window. Returns NULL on error.
HEFFER_IMAGE *Heffer_CreateImage_AlphaMask(HEFFER_IMAGE *imsrc, int col);
Creates a mask of an image in the specified colour - replaces all colour with
the specified colour but leaves the transparency. This is the first step to
creating layer effects such as drop shadow and outer glow.
HEFFER_IMAGE *Heffer_CreateImage_OuterGlow(HEFFER_IMAGE *imsrc, int col, double blur, double intens);
Creates an outer glow layer from the source image
The source image has to be in an alpha format (ie. HEFFER_FORMAT_ABGR32)
HEFFER_FONT *Heffer_LoadFontResource(HINSTANCE hInst, char *name);
Loads a font stored in a resource in the Heffer font format.
void Heffer_TextOut(HEFFER_IMAGE *im, int x, int y, HEFFER_FONT *font, char *text, int col, int flags);
TECHNICAL NOTES
-
Colour ordering is Blue Green Red because this is the way GDI does it.
In memory each scan line of a bitmap (DIB) has to be a multiple of 4 bytes.
//---- PRIVATE FUNCTION PROTOS -----------------------------------------------*/
//---- PRIVATE TYPES ---------------------------------------------------------//
//---- GLOBALS ---------------------------------------------------------------//
#define talloc(a) ((a*)calloc(1, sizeof(a)))
int heffer_error = 0;
BOOL heffer_startup = FALSE;
// Alpha-blend lookup tables - [modifier][value]
unsigned char heffer_bacon[256][256];
unsigned char heffer_prawn[256][256];
// Intensity lookup table - [intens][alpha]
unsigned char heffer_intens[256][256];
// 256-colour dithering lookups
unsigned char heffer_lookup_b_g[256][256];
unsigned char heffer_lookup_r_bg[256][256];
unsigned char heffer_lookup_dither[16][256];
// 256-colour palette
HPALETTE heffer_hpal;
typedef struct HEFFER_TAG_LOGPALETTE256 {
WORD palVersion;
WORD palNumEntries;
PALETTEENTRY palPalEntry[256];
} HEFFER_LOGPALETTE256;
typedef struct HEFFER_TAG_BITMAPINFO256 {
BITMAPINFOHEADER bmiHeader;
WORD bmiColors[256];
} HEFFER_BITMAPINFO256;
HEFFER_LOGPALETTE256 heffer_lp256;
HEFFER_BITMAPINFO256 heffer_bmi;
//---- Heffer_Startup --------------------------------------------------------//
// Initialises the library
BOOL Heffer_Startup()
{
//- Create alpha-blend lookup tables
int i, j;
for(j=0; j<256; j++) for(i=0; i<256; i++) {
heffer_bacon[j][i] = (j*i)/255;
heffer_prawn[j][i] = ((255-j)*i)/255;
}
//- Create intensity lookup
for(j=0; j<256; j++) for(i=0; i<256; i++) {
int k = (i*(j*3+256))/256;
if(k>255) k = 255;
heffer_intens[j][i] = k;
}
//- Create 256-colour dither lookups
// Blue & Green combination lookup
for(j=0; j<256; j++) { // Blue value
for(i=0; i<256; i++) { // Green value
heffer_lookup_b_g[j][i] = ((i*6)>>8)*36 + ((j*6)>>8)*6;
}
}
// Red with Blue/Green combination lookup
for(j=0; j<256; j++) { // Red value
for(i=0; i<256; i++) { // B/G combined using previous table
heffer_lookup_r_bg[j][i] = ((j*6)>>8) + i;
}
}
// Dither lookup tables
for(j=0; j<16; j++) {
for(i=0; i<256; i++) {
if(i<128) { heffer_lookup_dither[j][i] = 0; } else { heffer_lookup_dither[j][i] = 255; }
}
}
for(i=0; i<213; i++) {
j = ((int)(i/6))*5+43;
heffer_lookup_dither[ 0][i+ 2] = j;
heffer_lookup_dither[ 1][i+ 5] = j;
heffer_lookup_dither[ 2][i+ 8] = j;
heffer_lookup_dither[ 3][i+10] = j;
heffer_lookup_dither[ 4][i+13] = j;
heffer_lookup_dither[ 5][i+16] = j;
heffer_lookup_dither[ 6][i+18] = j;
heffer_lookup_dither[ 7][i+21] = j;
heffer_lookup_dither[ 8][i+24] = j;
heffer_lookup_dither[ 9][i+26] = j;
heffer_lookup_dither[10][i+29] = j;
heffer_lookup_dither[11][i+32] = j;
heffer_lookup_dither[12][i+34] = j;
heffer_lookup_dither[13][i+37] = j;
heffer_lookup_dither[14][i+40] = j;
heffer_lookup_dither[15][i+42] = j;
}
// Create palette
int r, g, b;
heffer_lp256.palVersion = 0x300;
heffer_lp256.palNumEntries = 216;
for(b=0; b<6; b++) for(g=0; g<6; g++) for(r=0; r<6; r++) {
heffer_lp256.palPalEntry[r+6*g+36*b].peRed = r*255/5;
heffer_lp256.palPalEntry[r+6*g+36*b].peGreen = g*255/5;
heffer_lp256.palPalEntry[r+6*g+36*b].peBlue = b*255/5;
heffer_lp256.palPalEntry[r+6*g+36*b].peFlags = 0;
}
heffer_hpal = CreatePalette((LOGPALETTE *)&heffer_lp256);
//- Done
heffer_startup = TRUE;
return TRUE;
}
//---- Heffer_Shutdown -------------------------------------------------------//
BOOL Heffer_Shutdown()
{
DeleteObject((HGDIOBJ)heffer_hpal);
return TRUE;
}
//---- Heffer_LoadBitmapResource ---------------------------------------------//
HEFFER_IMAGE *Heffer_LoadBitmapResource(HINSTANCE hInst, char *name)
{
//- Create object
HEFFER_IMAGE *im = talloc(HEFFER_IMAGE);
if(!im) return NULL;
// Get bitmap bits into buffer
BITMAPINFO bmi;
HDC dc, memDC;
HBITMAP hbmp;
BITMAP bmp;
hbmp = LoadBitmap(hInst, name);
if(!hbmp) {
heffer_error = 77001001;
free(im);
return NULL;
}
GetObject(hbmp, sizeof(BITMAP), (LPVOID)&bmp);
int w = bmp.bmWidth, h = bmp.bmHeight;
int bufw = (w*3+3)&0xFFFFFFFC;
im->buf = (unsigned char *)malloc(bufw*h);
if(!im->buf) {
heffer_error = 77001002;
free(im);
DeleteObject(hbmp);
return NULL;
}
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = w;
bmi.bmiHeader.biHeight = -h;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
bmi.bmiHeader.biXPelsPerMeter = 1000;
bmi.bmiHeader.biYPelsPerMeter = 1000;
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biClrImportant = 0;
dc = GetDC(GetDesktopWindow());
memDC = CreateCompatibleDC(dc);
int i = GetDIBits(memDC, hbmp, 0,h, (LPVOID)im->buf, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS);
DeleteDC(memDC);
ReleaseDC(GetDesktopWindow(), dc);
DeleteObject(hbmp);
//- Fill in object info
im->w = w; im->h = h; im->bufw = bufw;
im->x1 = 0; im->y1 = 0; im->x2 = w; im->y2 = h;
im->ox = 0; im->oy = 0;
im->size = bufw*h;
im->bpp = 3;
im->format = HEFFER_FORMAT_BGR24;
im->dirty = NULL; im->dirty_size = 0;
return im;
}
//---- Heffer_LoadTargaResource ----------------------------------------------//
HEFFER_IMAGE *Heffer_LoadTargaResource(HINSTANCE hInst, char *name)
{
//- Create object
HEFFER_IMAGE *im = talloc(HEFFER_IMAGE);
if(!im) return NULL;
//- Load resource into memory
HGLOBAL hResource = LoadResource(hInst, FindResource(hInst, name, "TARGA"));
if(!hResource) {
heffer_error = 77002006;
return FALSE;
}
unsigned char *buf = (unsigned char *)LockResource(hResource);
if(!buf) {
heffer_error = 77002007;
return FALSE;
}
//- Read TGA data
BOOL compressed;
// Read over imageid and colormap fields
unsigned char imageid = *buf++;
unsigned char colormap = *buf++;
// Check that the source data is in the correct format
if((int)*buf != 2) if((int)*buf !=10) {
heffer_error = 77002001;
free(im);
return NULL;
}
compressed = *buf == 10;
// Skip past the image type and colour map specifiaction
buf+=6;
// Read image metrics
im->ox = *(short*)buf; buf+=2;
im->oy = *(short*)buf; buf+=2;
im->w = *(short*)buf; buf+=2;
im->h = *(short*)buf; buf+=2;
im->bpp = (*buf)>>3; buf++;
// Bypass the image descriptor
buf++;
if(im->bpp != 4) {
heffer_error = 77002002;
free(im);
return NULL;
}
// Skip over imageid and colormap data
buf+=imageid;
buf+=colormap;
// Allocate memory for the image
im->bufw = (im->w*4+3)&0xFFFFFFFC;
im->size = im->bufw*im->h;
im->buf = (unsigned char*)malloc(im->size);
if(!im->buf) {
heffer_error = 77002003;
free(im);
return NULL;
}
if(compressed) {
// DecompressImageData(image->data, buf, image->w*image->h);
heffer_error = 77002666;
free(im);
return NULL;
} else {
int bufw = im->bufw, h = im->h;
for(int y=0; y<im->h; y++) {
int o = (h-y-1)*im->bufw;
for(int x=0; x<im->w; x++) {
im->buf[o+1] = *buf++;
im->buf[o+2] = *buf++;
im->buf[o+3] = *buf++;
im->buf[o+0] = *buf++;
o += 4;
}
}
}
//- Done
FreeResource(hResource);
//- Fill in object info
im->x1 = 0; im->y1 = 0; im->x2 = im->w; im->y2 = im->h;
im->format = HEFFER_FORMAT_ABGR32;
im->dirty = NULL; im->dirty_size = 0;
return im;
}
//---- Heffer_CreateImage ----------------------------------------------------//
HEFFER_IMAGE *Heffer_CreateImage(int w, int h, char format)
{
HEFFER_IMAGE *im;
char bpp;
switch(format) {
case HEFFER_FORMAT_BGR24: bpp = 3; break;
case HEFFER_FORMAT_ABGR32: bpp = 4; break;
default: return NULL;
}
//- Create image
im = talloc(HEFFER_IMAGE);
if(!im) return NULL;
//- Allocate buffer
int bufw = (w*bpp+3)&0xFFFFFFFC;
im->buf = (unsigned char *)malloc(bufw*h);
if(!im->buf) { free(im); return NULL; }
//- Fill in object info
im->w = w; im->h = h; im->bufw = bufw;
im->x1 = 0; im->y1 = 0; im->x2 = w; im->y2 = h;
im->ox = 0; im->oy = 0;
im->size = bufw*h;
im->bpp = bpp;
im->format = format;
im->dirty = NULL; im->dirty_size = 0;
//- Clear image
Heffer_FillImage(im, 0x00000000);
return im;
}
//---- Heffer_DuplicateImage -------------------------------------------------//
HEFFER_IMAGE *Heffer_DuplicateImage(HEFFER_IMAGE *imsrc)
{
//- Create image
HEFFER_IMAGE *im = talloc(HEFFER_IMAGE);
if(!im) return NULL;
memcpy(im, imsrc, sizeof(HEFFER_IMAGE));
//- Allocate buffer
im->buf = (unsigned char *)malloc(im->bufw*im->h);
if(!im->buf) { free(im); return NULL; }
//- Copy image
memcpy(im->buf, imsrc->buf, im->bufw*im->h);
return im;
}
//---- Heffer_GetImage -------------------------------------------------------//
// Gets a portion of a bitmap from a DC
BOOL Heffer_GetImage(HEFFER_IMAGE *im, int dx, int dy, int w, int h, HDC dc, int sx, int sy, int flags)
{
if(!im) return NULL;
// Blit flags
if(flags & HEFFER_BLIT_FULLSIZE) {
w = im->w;
h = im->h;
}
// Get bitmap bits into buffer
BITMAPINFO bmi;
HDC memDC;
HBITMAP hbmp, oldbmp;
memDC = CreateCompatibleDC(dc);
hbmp = CreateCompatibleBitmap(dc, w, h);
if(!hbmp) {
heffer_error = 77003001;
free(im);
return FALSE;
}
int bufw = (w*3+3)&0xFFFFFFFC;
im->buf = (unsigned char *)malloc(bufw*h);
if(!im->buf) {
heffer_error = 77003002;
free(im);
DeleteObject(hbmp);
return FALSE;
}
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = w;
bmi.bmiHeader.biHeight = -h;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
bmi.bmiHeader.biXPelsPerMeter = 1000;
bmi.bmiHeader.biYPelsPerMeter = 1000;
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biClrImportant = 0;
dc = GetDC(GetDesktopWindow());
memDC = CreateCompatibleDC(dc);
oldbmp = (HBITMAP)SelectObject(memDC, hbmp);
BitBlt(memDC, 0,0, w,h, dc, sx,sy, SRCCOPY);
GetDIBits(memDC, hbmp, 0,h, (LPVOID)im->buf, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS);
SelectObject(memDC, oldbmp);
DeleteDC(memDC);
DeleteObject(hbmp);
//- Fill in object info
im->w = w; im->h = h; im->bufw = bufw;
im->x1 = 0; im->y1 = 0; im->x2 = w; im->y2 = h;
im->ox = 0; im->oy = 0;
im->size = bufw*h;
im->bpp = 3;
im->format = HEFFER_FORMAT_BGR24;
im->dirty = NULL; im->dirty_size = 0;
return TRUE;
}
//---- Heffer_Blit -----------------------------------------------------------//
void Heffer_Blit(HEFFER_IMAGE *imdest, int dx, int dy, int w, int h, HEFFER_IMAGE *imsrc, int sx, int sy, int flags)
{
int i, j;
if(!imdest) return;
if(!imsrc) return;
// Addresses of buffers
unsigned char *sbuf = imsrc->buf;
unsigned char *dbuf = imdest->buf;
// Blit flags
if(flags & HEFFER_BLIT_FULLSIZE) {
w = imsrc->w;
h = imsrc->h;
}
// Clip
if(sx < 0) { dx -= sx; w += sx; sx = 0; }
if(sy < 0) { dy -= sy; h += sy; sy = 0; }
if(sx+w > imsrc->w) { w = imsrc->w-sx; }
if(sy+h > imsrc->h) { h = imsrc->h-sy; }
if(dx+w > imdest->x2) { w = imdest->x2-dx; }
if(dy+h > imdest->y2) { h = imdest->y2-dy; }
if(dx < imdest->x1) { w += dx-imdest->x1; sx -= dx-imdest->x1; dx = imdest->x1; }
if(dy < imdest->y1) { h += dy-imdest->y1; sy -= dy-imdest->y1; dy = imdest->y1; }
if(w<0 || h<0) return;
// Calculate offsets
sbuf += sx*imsrc ->bpp + sy*imsrc ->bufw;
dbuf += dx*imdest->bpp + dy*imdest->bufw;
// Copy data
if(imsrc->format == HEFFER_FORMAT_BGR24) {
if(imdest->format == HEFFER_FORMAT_BGR24) {
// 24-bit BGR to 24-bit BGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
*dbuf++ = *sbuf++;
*dbuf++ = *sbuf++;
*dbuf++ = *sbuf++;
}
sbuf += imsrc-> bufw - w*3;
dbuf += imdest->bufw - w*3;
}
} else if(imdest->format == HEFFER_FORMAT_ABGR32) {
// 24-bit BGR to 32-bit ABGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
*dbuf++ = 255;
*dbuf++ = *sbuf++;
*dbuf++ = *sbuf++;
*dbuf++ = *sbuf++;
}
sbuf += imsrc-> bufw - w*3;
dbuf += imdest->bufw - w*4;
}
}
} else if(imsrc->format == HEFFER_FORMAT_ABGR32) {
if(imdest->format == HEFFER_FORMAT_BGR24) {
// 32-bit ABGR to 24-bit BGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char a = *sbuf++;
unsigned char c1, c2;
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
sbuf += imsrc-> bufw - w*4;
dbuf += imdest->bufw - w*3;
}
} else if(imdest->format == HEFFER_FORMAT_ABGR32) {
// 32-bit ABGR to 32-bit ABGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char a = *sbuf++;
*dbuf++ = (*dbuf*(255-a) + 255*a)/255;
unsigned char c1, c2;
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
sbuf += imsrc-> bufw - w*4;
dbuf += imdest->bufw - w*4;
}
}
}
// TODO: Update dirty region
}
//---- Heffer_AlphaBlit ------------------------------------------------------//
void Heffer_AlphaBlit(HEFFER_IMAGE *imdest, int dx, int dy, int w, int h, HEFFER_IMAGE *imsrc, int sx, int sy, unsigned char alpha, int flags)
{
int i, j;
if(!imdest) return;
if(!imsrc) return;
// Addresses of buffers
unsigned char *sbuf = imsrc->buf;
unsigned char *dbuf = imdest->buf;
// Blit flags
if(flags & HEFFER_BLIT_FULLSIZE) {
w = imsrc->w;
h = imsrc->h;
}
// Clip
if(dx+w > imdest->x2) { w = imdest->x2-dx; }
if(dy+h > imdest->y2) { h = imdest->y2-dy; }
if(dx < imdest->x1) { w += dx-imdest->x1; sx -= dx-imdest->x1; dx = imdest->x1; }
if(dy < imdest->y1) { h += dy-imdest->y1; sy -= dy-imdest->y1; dy = imdest->y1; }
if(w<0 || h<0) return;
// Calculate offsets
sbuf += sx*imsrc ->bpp + sy*imsrc ->bufw;
dbuf += dx*imdest->bpp + dy*imdest->bufw;
// Copy data
if(imsrc->format == HEFFER_FORMAT_BGR24) {
if(imdest->format == HEFFER_FORMAT_BGR24) {
// 24-bit BGR to 24-bit BGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char c1, c2;
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
}
sbuf += imsrc-> bufw - w*3;
dbuf += imdest->bufw - w*3;
}
} else if(imdest->format == HEFFER_FORMAT_ABGR32) {
// 24-bit BGR to 32-bit ABGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char a = alpha;
unsigned char c1, c2;
*dbuf++ = ( (int)(*dbuf)*(255-a) + (int)(255 )*(a) )>>8;
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
sbuf += imsrc-> bufw - w*3;
dbuf += imdest->bufw - w*4;
}
}
} else if(imsrc->format == HEFFER_FORMAT_ABGR32) {
if(imdest->format == HEFFER_FORMAT_BGR24) {
// 32-bit ABGR to 24-bit BGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char a = ((*sbuf++)*alpha)/255;
unsigned char c1, c2;
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
sbuf += imsrc-> bufw - w*4;
dbuf += imdest->bufw - w*3;
}
} else if(imdest->format == HEFFER_FORMAT_ABGR32) {
// 32-bit ABGR to 32-bit ABGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char a = ((*sbuf++)*alpha)/255;
*dbuf++ = ( (int)(*dbuf)*(255-a) + (int)(255 )*(a) )>>8;
*dbuf++ = ( (int)(*dbuf)*(255-a) + (int)(*sbuf++)*(a) )>>8;
*dbuf++ = ( (int)(*dbuf)*(255-a) + (int)(*sbuf++)*(a) )>>8;
*dbuf++ = ( (int)(*dbuf)*(255-a) + (int)(*sbuf++)*(a) )>>8;
}
sbuf += imsrc-> bufw - w*4;
dbuf += imdest->bufw - w*4;
}
}
}
// TODO: Update dirty region
}
//---- Heffer_SoftLightBlit --------------------------------------------------//
void Heffer_SoftLightBlit(HEFFER_IMAGE *imdest, int dx, int dy, int w, int h, HEFFER_IMAGE *imsrc, int sx, int sy, unsigned char alpha, int flags)
{
int i, j;
if(!imdest) return;
if(!imsrc) return;
// Addresses of buffers
unsigned char *sbuf = imsrc->buf;
unsigned char *dbuf = imdest->buf;
// Blit flags
if(flags & HEFFER_BLIT_FULLSIZE) {
w = imsrc->w;
h = imsrc->h;
}
// Clip
if(dx+w > imdest->x2) { w = imdest->x2-dx; }
if(dy+h > imdest->y2) { h = imdest->y2-dy; }
if(dx < imdest->x1) { w += dx-imdest->x1; sx -= dx-imdest->x1; dx = imdest->x1; }
if(dy < imdest->y1) { h += dy-imdest->y1; sy -= dy-imdest->y1; dy = imdest->y1; }
if(w<0 || h<0) return;
// Calculate offsets
sbuf += sx*imsrc ->bpp + sy*imsrc ->bufw;
dbuf += dx*imdest->bpp + dy*imdest->bufw;
// Copy data
if(imsrc->format == HEFFER_FORMAT_BGR24) {
if(imdest->format == HEFFER_FORMAT_BGR24) {
// 24-bit BGR to 24-bit BGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char c1, c2;
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
}
sbuf += imsrc-> bufw - w*3;
dbuf += imdest->bufw - w*3;
}
} else if(imdest->format == HEFFER_FORMAT_ABGR32) {
// 24-bit BGR to 32-bit ABGR blit (only one that's done)
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char a = alpha;
unsigned char c1, c2;
*dbuf++;
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
sbuf += imsrc-> bufw - w*3;
dbuf += imdest->bufw - w*4;
}
}
} else if(imsrc->format == HEFFER_FORMAT_ABGR32) {
if(imdest->format == HEFFER_FORMAT_BGR24) {
// 32-bit ABGR to 24-bit BGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char a = ((*sbuf++)*alpha)/255;
unsigned char c1, c2;
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = *sbuf++, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
sbuf += imsrc-> bufw - w*4;
dbuf += imdest->bufw - w*3;
}
} else if(imdest->format == HEFFER_FORMAT_ABGR32) {
// 32-bit ABGR to 32-bit ABGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char a = ((*sbuf++)*alpha)/255;
*dbuf++;
*dbuf++ = ( (int)(*dbuf)*(255-a) + (int)(*sbuf++)*(a) )>>8;
*dbuf++ = ( (int)(*dbuf)*(255-a) + (int)(*sbuf++)*(a) )>>8;
*dbuf++ = ( (int)(*dbuf)*(255-a) + (int)(*sbuf++)*(a) )>>8;
}
sbuf += imsrc-> bufw - w*4;
dbuf += imdest->bufw - w*4;
}
}
}
// TODO: Update dirty region
}
//---- Heffer_AlphaRect ------------------------------------------------------//
void Heffer_AlphaRect(HEFFER_IMAGE *imdest, int dx, int dy, int w, int h, int col)
{
unsigned char r, g, b, a;
int i, j;
if(!imdest) return;
r = (col>> 0)&0xFF;
g = (col>> 8)&0xFF;
b = (col>>16)&0xFF;
a = (col>>24)&0xFF;
if(a == 0xFF) {
Heffer_FillRect(imdest, dx, dy, w, h, col);
return;
}
// Addresses of buffers
unsigned char *dbuf = imdest->buf;
// Clip
if(dx+w > imdest->x2) { w = imdest->x2-dx; }
if(dy+h > imdest->y2) { h = imdest->y2-dy; }
if(dx < imdest->x1) { w += dx-imdest->x1; dx = imdest->x1; }
if(dy < imdest->y1) { h += dy-imdest->y1; dy = imdest->y1; }
if(w<0 || h<0) return;
// Calculate offsets
dbuf += dx*imdest->bpp + dy*imdest->bufw;
// Copy data
if(imdest->format == HEFFER_FORMAT_BGR24) {
// 24-bit BGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char c1, c2;
(c1 = *dbuf, c2 = b, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = g, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = r, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
dbuf += imdest->bufw - w*3;
}
} else if(imdest->format == HEFFER_FORMAT_ABGR32) {
// 32-bit ABGR blit
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char c1, c2;
*dbuf++ = ( (int)(*dbuf)*(255-a) + (int)(255 )*(a) )>>8;
(c1 = *dbuf, c2 = b, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = g, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = r, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
dbuf += imdest->bufw - w*4;
}
}
// TODO: Update dirty region
}
//---- Heffer_FillRect -------------------------------------------------------//
// DOING: Rewrite in asm so it's nice and fast :)
// At the moment it's bobbins.
void Heffer_FillRect(HEFFER_IMAGE *im, int x, int y, int w, int h, int col)
{
unsigned char r, g, b, a;
int i, j;
r = (col>> 0)&0xFF;
g = (col>> 8)&0xFF;
b = (col>>16)&0xFF;
a = (col>>24)&0xFF;
// Address of buffer
unsigned char *buf = im->buf;
int bufw = im->bufw;
// Calculate offsets
if(x < im->x1) { w += x-im->x1; x = im->x1; }
if(y < im->y1) { h += y-im->y1; y = im->y1; }
if(x+w > im->x2) { w = im->x2-x; }
if(y+h > im->y2) { h = im->y2-y; }
if(w <= 0 || h <= 0) return;
buf += x*im->bpp + y*im->bufw;
// Do stuff
if(im->bpp == 3) {
_asm {
mov ah, b
mov bh, g
mov dh, r
mov al, r
mov bl, b
mov dl, g
rol eax, 16
rol ebx, 16
rol edx, 16
mov ah, g
mov bh, r
mov dh, b
mov al, b
mov bl, g
mov dl, r
mov edi, buf
mov esi, h
yloop:
push edi
mov ecx, w
xloop_test16:
cmp ecx, 16
jl xloop_no16
mov [edi+4* 0], eax
mov [edi+4* 1], ebx
mov [edi+4* 2], edx
mov [edi+4* 3], eax
mov [edi+4* 4], ebx
mov [edi+4* 5], edx
mov [edi+4* 6], eax
mov [edi+4* 7], ebx
mov [edi+4* 8], edx
mov [edi+4* 9], eax
mov [edi+4*10], ebx
mov [edi+4*11], edx
add edi, 4*12
sub ecx, 16
jmp xloop_test16
xloop_no16:
xloop_test4:
cmp ecx, 4
jl xloop_no4
mov [edi+4* 0], eax
mov [edi+4* 1], ebx
mov [edi+4* 2], edx
add edi, 4*3
sub ecx, 4
jmp xloop_test4
xloop_no4:
xloop_test1:
cmp ecx, 1
jl xloop_no1
mov [edi+0], al
mov [edi+1], bl
mov [edi+2], dl
add edi, 3
sub ecx, 1
jmp xloop_test1
xloop_no1:
pop edi
add edi, bufw
dec esi
jnz yloop
}
/*
for(j=0; j<h; j++) {
for(i=0; i<w; i++) { *buf++ = b; *buf++ = g; *buf++ = r; }
buf += im->bufw - w*3;
}
*/
} else if(im->bpp == 4) {
for(j=0; j<h; j++) {
for(i=0; i<w; i++) { *buf++ = b; *buf++ = g; *buf++ = r; *buf++ = a; }
buf += im->bufw - w*4;
}
}
// TODO: Update dirty region
}
//---- Heffer_FillImage ------------------------------------------------------//
void Heffer_FillImage(HEFFER_IMAGE *im, int col)
{
if(!im) return;
Heffer_FillRect(im, 0, 0, im->w, im->h, col);
}
//---- Heffer_DarkenRect -----------------------------------------------------//
void Heffer_DarkenRect(HEFFER_IMAGE *im, int x, int y, int w, int h)
{
int i, j;
// Addresses of buffers
unsigned char *buf = im->buf;
// Calculate offsets
if(x < im->x1) { w += x-im->x1; x = im->x1; }
if(y < im->y1) { h += y-im->y1; y = im->y1; }
if(x+w > im->x2) { w = im->x2-x; }
if(y+h > im->y2) { h = im->y2-y; }
if(w<0 || h<0) return;
buf += x*3 + y*im->bufw;
// Copy data
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
*buf++ >>= 1;
*buf++ >>= 1;
*buf++ >>= 1;
}
buf += im->bufw - w*3;
}
// TODO: Update dirty region
}
//---- Heffer_BlurRect -------------------------------------------------------//
void Heffer_BlurRect(HEFFER_IMAGE *im, int x, int y, int w, int h)
{
int i, j, v;
// Addresses of buffers
unsigned char *buf = im->buf;
int bufw = im->bufw;
// Calculate offsets
if(x < im->x1) { w += x-im->x1; x = im->x1; }
if(y < im->y1) { h += y-im->y1; y = im->y1; }
if(x+w > im->x2) { w = im->x2-x; }
if(y+h > im->y2) { h = im->y2-y; }
if(w<0 || h<0) return;
buf += x*3 + y*im->bufw;
// Copy data
for(j=0; j<h-1; j++) {
for(i=0; i<w-1; i++) {
v = buf[0]; v += buf[3]; v += buf[bufw]; v += buf[bufw+3]; v >>= 2;
*buf++ = v;
v = buf[0]; v += buf[3]; v += buf[bufw]; v += buf[bufw+3]; v >>= 2;
*buf++ = v;
v = buf[0]; v += buf[3]; v += buf[bufw]; v += buf[bufw+3]; v >>= 2;
*buf++ = v;
}
buf += im->bufw - (w+1)*3;
}
// TODO: Update dirty region
}
//---- Heffer_DrawDot ---------------------------------------------------------//
void Heffer_DrawDot(HEFFER_IMAGE *im, int x, int y, int col)
{
Heffer_FillRect(im, x-2, y-2, 5, 5, col^0xFFFFFF);
Heffer_FillRect(im, x-1, y-1, 3, 3, col);
}
//---- Heffer_PutPixel --------------------------------------------------------//
void Heffer_PutPixel(HEFFER_IMAGE *im, int x, int y, int col)
{
unsigned char r, g, b, a;
r = (col>> 0)&0xFF;
g = (col>> 8)&0xFF;
b = (col>>16)&0xFF;
a = (col>>24)&0xFF;
// Clip
if(x<im->x1 || y<im->y1 || x >= im->x2 || y >= im->y2) return;
unsigned char *buf = im->buf;
buf += x*im->bpp + y*im->bufw;
// Plot pixel
if(im->bpp == 3) {
*buf++ = b; *buf++ = g; *buf++ = r;
} else if(im->bpp == 4) {
*buf++ = b; *buf++ = g; *buf++ = r; *buf++ = a;
}
//- TODO: Set dirty region
}
//---- Heffer_GetPixel --------------------------------------------------------//
int Heffer_GetPixel(HEFFER_IMAGE *im, int x, int y)
{
unsigned char r, g, b, a=0;
if(x<im->x1 || y<im->y1 || x >= im->x2 || y >= im->y2) return -1;
unsigned char *buf = im->buf;
buf += x*im->bpp + y*im->bufw;
// Get pixel
if(im->bpp == 3) {
b = *buf++; g = *buf++; r = *buf++;
} else if(im->bpp == 4) {
b = *buf++; g = *buf++; r = *buf++; a = *buf++;
}
return (a<<24)+(b<<16)+(g<<8)+(r);
}
//---- Heffer_DrawLine --------------------------------------------------------//
void Heffer_DrawLine(HEFFER_IMAGE *im, int x1, int y1, int x2, int y2, int col)
{
int x, y, dx, dy;
int i, di;
dx = x2-x1; if(dx < 0) dx =- dx;
dy = y2-y1; if(dy < 0) dy =- dy;
di = dx; if(dy > dx) di = dy;
if(!di) return;
for(i=0; i<=di; i++) {
x = x1 + (x2-x1)*i/di;
y = y1 + (y2-y1)*i/di;
// Heffer_PutPixel(im, x, y, col);
Heffer_PutPixel(im, x , y-1, col);
Heffer_PutPixel(im, x+1, y-1, col);
Heffer_PutPixel(im, x-1, y , col);
Heffer_PutPixel(im, x , y , col);
Heffer_PutPixel(im, x+1, y , col);
Heffer_PutPixel(im, x+2, y , col);
Heffer_PutPixel(im, x-1, y+1, col);
Heffer_PutPixel(im, x , y+1, col);
Heffer_PutPixel(im, x+1, y+1, col);
Heffer_PutPixel(im, x+2, y+1, col);
Heffer_PutPixel(im, x , y+2, col);
Heffer_PutPixel(im, x+1, y+2, col);
}
}
//---- Heffer_DrawRing --------------------------------------------------------//
void Heffer_DrawRing(HEFFER_IMAGE *im, float x1, float y1, float x2, float y2, int col)
{
double cx = 0.5*(x1+x2), cy = 0.5*(y1+y2);
double dx = (x2-x1), dy = (y2-y1);
double d = atan(dy/dx);
double r, a, rx, ry, rm, rd, rr, ratio;
double xa=0, ya=0, xb, yb;
int i;
rx = 40+0.5*sqrt(dx*dx+dy*dy);
ry = 30+sqrt(rx-40);
ratio = 0.7;
if(rx > 120) {
rx = 120;
}
rm = ry;
rd = rx-ry;
for(i=0; i<128; i++) {
a = (1.2*(i/64.0)-0.1)*3.1415926;
rr = 0.5-0.5*cos(a*2);
rr = (rr*rr)*ratio+rr*(1-ratio);
r = rm + rd * rr;
if(i<32) r += 0.4*ry*((32-i)/32.0);
if(i>96) r += 0.4*ry*((i-96)/32.0);
xb = xa; yb = ya;
xa = cx - r*sin(a-d); ya = cy - r*cos(a-d);
if(i) Heffer_DrawLine(im, (int)xa, (int)ya, (int)xb, (int)yb, col);
Heffer_DrawLine(im, 128+i, 480, 128+i, (int)(480-r), col);
}
}
//---- Heffer_Tri ------------------------------------------------------------//
void Heffer_Tri(HEFFER_IMAGE *im, double x1, double y1, double x2, double y2, double x3, double y3, int col)
{
double t;
int x, y, ya, yb, xa, xb;
unsigned char r, g, b, a;
r = (col>> 0)&0xFF;
g = (col>> 8)&0xFF;
b = (col>>16)&0xFF;
a = (col>>24)&0xFF;
// Sort points
if(y1 > y2) { t=y2; y2=y1; y1=t; t=x2; x2=x1; x1=t; }
if(y2 > y3) { t=y3; y3=y2; y2=t; t=x3; x3=x2; x2=t; }
if(y1 > y2) { t=y2; y2=y1; y1=t; t=x2; x2=x1; x1=t; }
// Clip
ya = y1; yb = y3;
if(yb <= im->y1) return;
if(ya >= im->y2) return;
if(ya < im->y1) ya = im->y1-1;
if(yb > im->y2) yb = im->y2;
// Draw
for(y=ya+1; y<yb; y++) {
if(y < y2) { xa = x1 + (x3-x1)*(y-y1)/(y3-y1); xb = x1 + (x2-x1)*(y-y1)/(y2-y1); } else
if(y < y3) { xa = x1 + (x3-x1)*(y-y1)/(y3-y1); xb = x2 + (x3-x2)*(y-y2)/(y3-y2); }
if(xa > xb) { t=xa; xa=xb; xb=t; }
if(xa < im->x1) xa = im->x1;
if(xb > im->x2) xb = im->x2;
char *dbuf = (char *)im->buf + xa*im->bpp + y*im->bufw;
if(im->format == HEFFER_FORMAT_BGR24) {
for(x=xa; x<xb; x++) {
unsigned char c1, c2;
(c1 = *dbuf, c2 = b, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = g, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = r, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
} else if(im->format == HEFFER_FORMAT_ABGR32) {
for(x=xa; x<xb; x++) {
unsigned char c1, c2;
*dbuf++ = ( (int)(*dbuf)*(255-a) + (int)(255 )*(a) )>>8;
(c1 = *dbuf, c2 = b, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = g, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = *dbuf, c2 = r, *dbuf++ = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
}
}
}
//---- Heffer_AATri ----------------------------------------------------------//
void Heffer_AATri(HEFFER_IMAGE *im, double x1, double y1, double x2, double y2, double x3, double y3, int col)
{
int i, j;
for(j=0; j<4; j++) for(i=0; i<4; i++) {
Heffer_Tri(
im,
x1+i*0.25, y1+j*0.25,
x2+i*0.25, y2+j*0.25,
x3+i*0.25, y3+j*0.25,
col
);
}
}
//---- Heffer_LewpensMagicFunction -------------------------------------------//
unsigned char *Heffer_LewpensMagicFunction(HEFFER_IMAGE *im)
{
int w = im->w, h = im->h;
int bufw = im->bufw;
unsigned char *scr = (unsigned char *)malloc(w*h);
unsigned char *buf = im->buf;
_asm {
mov esi, buf
mov edi, scr
xor eax, eax
xor ebx, ebx
mov edx, h
shr dx, 2
ss3d_rgb2pal_dither_yloop:
push esi
push edi
mov ecx, w
shr cx, 2
ss3d_rgb2pal_dither_xloop:
push esi
push edi
// 0 //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// 8 //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+2048]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+2048]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+2048]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// 2 //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+512]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+512]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+512]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// A //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+2560]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+2560]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+2560]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
sub esi, 9
sub edi, 3
add esi, bufw
add edi, w
// C //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+3072]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+3072]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+3072]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// 4 //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+1024]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+1024]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+1024]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// E //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+3584]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+3584]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+3584]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// 6 //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+1536]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+1536]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+1536]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
sub esi, 9
sub edi, 3
add esi, bufw
add edi, w
// 3 //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+768]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+768]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+768]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// B //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+2816]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+2816]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+2816]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// 1 //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+256]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+256]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+256]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// 9 //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+2304]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+2304]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+2304]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
sub esi, 9
sub edi, 3
add esi, bufw
add edi, w
// F //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+3840]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+3840]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+3840]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// 7 //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+1792]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+1792]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+1792]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// D //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+3328]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+3328]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+3328]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
add esi, 3
inc edi
// 5 //
mov bl, [esi]
mov al, heffer_lookup_dither[ebx+1280]
mov bl, [esi+1]
mov ah, heffer_lookup_dither[ebx+1280]
mov al, heffer_lookup_b_g[eax]
mov bl, [esi+2]
mov ah, heffer_lookup_dither[ebx+1280]
mov al, heffer_lookup_r_bg[eax]
mov [edi], al
pop edi
pop esi
add esi, 12
add edi, 4
dec cx
jnz ss3d_rgb2pal_dither_xloop
pop edi
pop esi
add esi, bufw
add edi, w
add esi, bufw
add edi, w
add esi, bufw
add edi, w
add esi, bufw
add edi, w
dec dx
jnz ss3d_rgb2pal_dither_yloop
}
return scr;
}
//---- Heffer_Image_Display --------------------------------------------------//
void Heffer_Image_Display(HDC dc, HEFFER_IMAGE *im, int x, int y, BOOL d)
{
if(!im) return;
heffer_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
heffer_bmi.bmiHeader.biWidth = im->w;
heffer_bmi.bmiHeader.biHeight = -im->h;
heffer_bmi.bmiHeader.biPlanes = 1;
heffer_bmi.bmiHeader.biBitCount = 24;
heffer_bmi.bmiHeader.biCompression = BI_RGB;
heffer_bmi.bmiHeader.biSizeImage = 0;
heffer_bmi.bmiHeader.biXPelsPerMeter = 1000;
heffer_bmi.bmiHeader.biYPelsPerMeter = 1000;
heffer_bmi.bmiHeader.biClrUsed = 0;
heffer_bmi.bmiHeader.biClrImportant = 0;
int dw = im->w, dh = im->h;
if(d) {
dw *= 2;
dh *= 2;
}
// TEMP: Show us exactly what's appearing
// Heffer_AlphaRect(im, 0, 0, 1000, 1000, (GetTickCount()*8261782)&0x33FFFFFF);
if(GetDeviceCaps(dc, BITSPIXEL) > 8) {
//- Hi-colour or Truecolour blit
StretchDIBits(
dc,
x, y, dw, dh,
0, 0, im->w, im->h,
(LPVOID)im->buf,
(LPBITMAPINFO)&heffer_bmi,
DIB_RGB_COLORS, SRCCOPY
);
} else {
//- 256-colour blit
unsigned char *buf = Heffer_LewpensMagicFunction(im);
int i;
for(i=0; i<256; i++) {
buf[i] = i;
buf[i+im->w] = i;
buf[i+im->w*2] = i;
buf[i+im->w*3] = i;
}
SelectPalette(dc, heffer_hpal, FALSE);
RealizePalette(dc);
heffer_bmi.bmiHeader.biBitCount = 8;
heffer_bmi.bmiHeader.biClrUsed = 216;
heffer_bmi.bmiHeader.biClrImportant = 216;
for(i=0; i<216; i++) heffer_bmi.bmiColors[i] = i;
StretchDIBits(
dc,
x, y, dw, dh,
0, 0, im->w, im->h,
(LPVOID)buf,
(LPBITMAPINFO)&heffer_bmi,
DIB_PAL_COLORS, SRCCOPY
);
}
}
//---- Heffer_Image_DisplayRect ----------------------------------------------//
void Heffer_Image_DisplayRect(HDC dc, int dx, int dy, int w, int h, HEFFER_IMAGE *im, int sx, int sy)
{
if(!im) return;
heffer_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
heffer_bmi.bmiHeader.biWidth = im->w;
heffer_bmi.bmiHeader.biHeight = -im->h;
heffer_bmi.bmiHeader.biPlanes = 1;
heffer_bmi.bmiHeader.biBitCount = 24;
heffer_bmi.bmiHeader.biCompression = BI_RGB;
heffer_bmi.bmiHeader.biSizeImage = 0;
heffer_bmi.bmiHeader.biXPelsPerMeter = 1000;
heffer_bmi.bmiHeader.biYPelsPerMeter = 1000;
heffer_bmi.bmiHeader.biClrUsed = 0;
heffer_bmi.bmiHeader.biClrImportant = 0;
// TEMP: Show us exactly what's appearing
// Heffer_AlphaRect(im, 0, 0, 1000, 1000, (GetTickCount()*8261782)&0x33FFFFFF);
if(GetDeviceCaps(dc, BITSPIXEL) > 8) {
//- Hi-colour or Truecolour blit
StretchDIBits(
dc,
dx, dy, w, h,
sx, im->h-sy-h, w, h,
(LPVOID)im->buf,
(LPBITMAPINFO)&heffer_bmi,
DIB_RGB_COLORS, SRCCOPY
);
} else {
//- 256-colour blit
unsigned char *buf = Heffer_LewpensMagicFunction(im);
int i;
for(i=0; i<256; i++) {
buf[i] = i;
buf[i+im->w] = i;
buf[i+im->w*2] = i;
buf[i+im->w*3] = i;
}
SelectPalette(dc, heffer_hpal, FALSE);
RealizePalette(dc);
heffer_bmi.bmiHeader.biBitCount = 8;
heffer_bmi.bmiHeader.biClrUsed = 216;
heffer_bmi.bmiHeader.biClrImportant = 216;
for(i=0; i<216; i++) heffer_bmi.bmiColors[i] = i;
StretchDIBits(
dc,
dx, dy, w, h,
sx, sy, w, h,
(LPVOID)im->buf,
(LPBITMAPINFO)&heffer_bmi,
DIB_RGB_COLORS, SRCCOPY
);
}
}
//---- Heffer_RegionFromImage ------------------------------------------------//
HRGN Heffer_RegionFromImage(HEFFER_IMAGE *im, int col)
{
unsigned char r, g, b;
int x, y, x1;
r = (col>> 0)&0xFF;
g = (col>> 8)&0xFF;
b = (col>>16)&0xFF;
unsigned char *buf = im->buf;
int bufw = im->bufw;
HRGN rgn, rgn2;
rgn = CreateRectRgn(0, 0, im->w, im->h);
for(y=0; y<im->h; y++) {
for(x=0; x<im->w; ) {
// Find transparent pixels
x1 = x;
while(buf[y*bufw+x*3 ] == b &&
buf[y*bufw+x*3+1] == g &&
buf[y*bufw+x*3+2] == r && x < im->w) x++;
// Remove from region
rgn2 = CreateRectRgn(x1, y, x, y+1);
CombineRgn(rgn, rgn, rgn2, RGN_DIFF);
DeleteObject(rgn2);
// Skip over non-transparent pixel
while((buf[y*bufw+x*3 ] != b ||
buf[y*bufw+x*3+1] != g ||
buf[y*bufw+x*3+2] != r) && x < im->w) x++;
}
}
return rgn;
}
//---- Heffer_DeleteImage ----------------------------------------------------//
BOOL Heffer_DeleteImage(HEFFER_IMAGE *im)
{
if(!im) return FALSE;
if(im->buf) free(im->buf);
free(im);
return TRUE;
}
//---- CLIPPING REGION FUNCTIONS ---------------------------------------------//
//---- Heffer_Clip_Set -------------------------------------------------------//
void Heffer_Clip_Set(HEFFER_IMAGE *im, int x1, int y1, int x2, int y2, BOOL combine)
{
// Clip the region against the image size
if(x1<0) x1 = 0;
if(y1<0) y1 = 0;
if(x2>im->w) x2 = im->w;
if(y2>im->h) y2 = im->h;
// Clip against current region
if(combine) {
if(x1<im->x1) x1 = im->x1;
if(y1<im->y1) y1 = im->y1;
if(x2>im->x2) x2 = im->x2;
if(y2>im->y2) y2 = im->y2;
}
// Set clipping region
im->x1 = x1;
im->y1 = y1;
im->x2 = x2;
im->y2 = y2;
}
//---- Heffer_Clip_None ------------------------------------------------------//
void Heffer_Clip_None(HEFFER_IMAGE *im)
{
im->x1 = 0;
im->y1 = 0;
im->x2 = im->w;
im->y2 = im->h;
}
//---- Heffer_Clip_Get -------------------------------------------------------//
void Heffer_Clip_Get(HEFFER_IMAGE *im, int *x1, int *y1, int *x2, int *y2)
{
*x1 = im->x1;
*y1 = im->y1;
*x2 = im->x2;
*y2 = im->y2;
}
//---- IMAGE FILTER ROUTINES -------------------------------------------------//
//---- Heffer_Filter_Blur ----------------------------------------------------//
BOOL Heffer_Filter_Blur(HEFFER_IMAGE *im, int radius, int ox, int oy)
{
heffer_error = 0;
if(!im) {
heffer_error = HEFFER_FILTER_BLUR | HEFFER_ERROR_NULLPTR;
return FALSE;
}
if(im->format != HEFFER_FORMAT_ABGR32) {
heffer_error = HEFFER_FILTER_BLUR | HEFFER_ERROR_FORMAT;
return NULL;
}
int bufw = im->bufw;
int w = im->w, h = im->h;
//- Create destination buffer
unsigned char *newbuf = (unsigned char *)malloc(bufw*h);
if(!newbuf) {
heffer_error = HEFFER_FILTER_BLUR | HEFFER_ERROR_MALLOC;
return FALSE;
}
//- Blur into destination buffer
unsigned char *sbuf = im->buf;
unsigned char *dbuf = newbuf;
int x, y, i, j;
for(y=0; y<h; y++) {
for(x=0; x<w; x++) {
int total = 0;
int a=0, r=0, g=0, b=0;
for(j=-radius; j<=radius; j++) if(j+y-oy >= 0 && j+y-oy < h) {
for(i=-radius; i<=radius; i++) if(i+x-ox >= 0 && i+x-ox < w) {
unsigned char *sbuf2 = sbuf + (i+x-ox)*4 + (j+y-oy)*bufw;
a += *sbuf2++;
r += *sbuf2++;
g += *sbuf2++;
b += *sbuf2++;
total++;
}
}
if(total) {
*dbuf++ = (unsigned char)(a/total);
*dbuf++ = (unsigned char)(b/total);
*dbuf++ = (unsigned char)(g/total);
*dbuf++ = (unsigned char)(r/total);
} else {
*dbuf++ = (unsigned char)0;
*dbuf++ = (unsigned char)0;
*dbuf++ = (unsigned char)0;
*dbuf++ = (unsigned char)0;
}
}
// sbuf += bufw - w*4;
dbuf += bufw - w*4;
}
free(im->buf);
im->buf = newbuf;
//- Done!
return TRUE;
}
//---- IMAGE EFFECT ROUTINES -------------------------------------------------//
//---- Heffer_CreateImage_AlphaMask ------------------------------------------//
HEFFER_IMAGE *Heffer_CreateImage_AlphaMask(HEFFER_IMAGE *imsrc, int col)
{
heffer_error = 0;
if(!imsrc) {
heffer_error = HEFFER_CREATEIMAGE_ALPHAMASK | HEFFER_ERROR_NULLPTR;
return NULL;
}
if(imsrc->format != HEFFER_FORMAT_ABGR32) {
heffer_error = HEFFER_CREATEIMAGE_ALPHAMASK | HEFFER_ERROR_FORMAT;
return NULL;
}
//- Create destination image
int w = imsrc->w, h = imsrc->h;
HEFFER_IMAGE *imdest = Heffer_CreateImage(w, h, HEFFER_FORMAT_ABGR32);
if(!imdest) {
heffer_error = HEFFER_CREATEIMAGE_ALPHAMASK | HEFFER_ERROR_MALLOC;
return NULL;
}
//- Make the mask
unsigned char r, g, b, a;
r = (col>> 0)&0xFF;
g = (col>> 8)&0xFF;
b = (col>>16)&0xFF;
a = (col>>24)&0xFF;
unsigned char *buf = imsrc->buf;
int bufw = imsrc->bufw;
unsigned char *sbuf = imsrc->buf;
unsigned char *dbuf = imdest->buf;
int x, y;
for(y=0; y<h; y++) {
for(x=0; x<w; x++) {
unsigned char c1 = *sbuf;
*dbuf++ = ((int)c1*(int)a)/255;
*dbuf++ = b;
*dbuf++ = g;
*dbuf++ = r;
sbuf+=4;
}
sbuf += imsrc-> bufw - w*4;
dbuf += imdest->bufw - w*4;
}
return imdest;
}
//---- Heffer_CreateImage_DropShadow -----------------------------------------//
HEFFER_IMAGE *Heffer_CreateImage_DropShadow(HEFFER_IMAGE *imsrc, int col, int x, int y, int blur)
{
//- Create alpha mask
HEFFER_IMAGE *imdest = Heffer_CreateImage_AlphaMask(imsrc, col);
if(!imdest) {
return NULL;
}
//- Blur mask
Heffer_Filter_Blur(imdest, blur, x, y);
return imdest;
}
//---- Heffer_CreateImage_OuterGlow ------------------------------------------//
HEFFER_IMAGE *Heffer_CreateImage_OuterGlow(HEFFER_IMAGE *imsrc, int col, int blur, unsigned char intens)
{
//- Create alpha mask
HEFFER_IMAGE *imdest = Heffer_CreateImage_AlphaMask(imsrc, col);
if(!imdest) {
return NULL;
}
//- Blur mask
Heffer_Filter_Blur(imdest, blur, 0, 0);
//- Add intensity
unsigned char *buf = imdest->buf;
int bufw = imdest->bufw;
int w = imdest->w, h = imdest->h;
int x, y;
for(y=0; y<h; y++) {
for(x=0; x<w; x++) {
*buf = heffer_intens[intens][*buf];
buf+=4;
}
buf += imdest->bufw - w*4;
}
return imdest;
}
//---- FONT & TEXT ROUTINES --------------------------------------------------//
//---- Heffer_LoadFontResource -----------------------------------------------//
HEFFER_FONT *Heffer_LoadFontResource(HINSTANCE hInst, char *name)
{
HGLOBAL hResource = LoadResource(hInst, FindResource(hInst, name, "RISKFONT"));
if(!hResource) {
heffer_error = HEFFER_LOADFONTRESOURCE | HEFFER_ERROR_LOADRESOURCE;
return NULL;
}
HEFFER_FONT *font = (HEFFER_FONT *)LockResource(hResource);
if(!font) {
heffer_error = HEFFER_LOADFONTRESOURCE | HEFFER_ERROR_LOCKRESOURCE;
return NULL;
}
// Check magic
if(font->magic != HEFFER_FONT_MAGIC) {
FreeResource(hResource);
heffer_error = HEFFER_LOADFONTRESOURCE | HEFFER_ERROR_MAGIC;
return NULL;
}
return font;
}
//---- Heffer_DeleteFont -----------------------------------------------------//
//---- Heffer_FontFromImage --------------------------------------------------//
HEFFER_FONT *Heffer_FontFromImage(HEFFER_IMAGE *im)
{
return NULL;
}
//---- Heffer_GetTextSize ----------------------------------------------------//
void Heffer_GetTextSize(HEFFER_FONT *font, char *t, int *wp, int *hp)
{
unsigned char *text = (unsigned char *)t;
//- Get length of string
int len;
for(len=0; text[len]; len++);
if(!len) {
*wp = 0;
*hp = font->h;
return;
}
//- Calculate size of string
int w = 0, h = font->h;
int index;
for(index=0; index<len; index++)
w += font->w[text[index]];
*wp = w; *hp = h;
}
//---- Heffer_TextOut --------------------------------------------------------//
/*
TODO: different dest formats
TODO: Better clipping!
*/
void Heffer_TextOut(HEFFER_IMAGE *im, int x, int y, HEFFER_FONT *font, char *t, int col, int flags)
{
int len;
int index, i, j;
unsigned char *text = (unsigned char *)t;
unsigned char r, g, b;
r = (col>> 0)&0xFF;
g = (col>> 8)&0xFF;
b = (col>>16)&0xFF;
if(!im) return;
if(!font) return;
if(!text) return;
unsigned char *buf = im->buf;
int bufw = im->bufw;
//- Get length of string
for(len=0; text[len]; len++);
if(!len) return;
//- Calculate size of string
int w = 0, h = font->h;
for(index=0; index<len; index++)
w += font->w[text[index]];
//- Position based on justification
if(flags & HEFFER_ALIGN_HCENTER) {
x -= w>>1;
} else if(flags & HEFFER_ALIGN_RIGHT) {
x -= w;
}
if(flags & HEFFER_ALIGN_VCENTER) {
y -= h>>1;
} else if(flags & HEFFER_ALIGN_BOTTOM) {
y -= h;
}
//- Put characters in image
int sx, sw;
if(im->format == HEFFER_FORMAT_BGR24) {
for(index=0; index<len; index++) {
sx = font->x[text[index]];
sw = font->w[text[index]];
if(x >= im->x1 && x+sw < im->x2 && y >= im->y1 && y+h < im->y2) {
for(j=0; j<h; j++) {
int o = x*3 + (j+y)*bufw;
for(i=0; i<sw; i++) {
unsigned char a = font->buf[(i+sx)+j*font->bufw];
unsigned char c1, c2;
(c1 = buf[o], c2 = b, buf[o++] = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = buf[o], c2 = g, buf[o++] = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = buf[o], c2 = r, buf[o++] = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
}
} else if(x > im->x1-sw && x < im->x2 && y > im->y1-h && y < im->y2) {
// TODO: calculate clipped area of character
for(j=0; j<h; j++) {
int o = x*3 + (j+y)*bufw;
for(i=0; i<sw; i++) {
if(x+i >= im->x1 && x+i < im->x2 && y+j >= im->y1 && y+j < im->y2) {
unsigned char a = font->buf[(i+sx)+j*font->bufw];
unsigned char c1, c2;
(c1 = buf[o+0], c2 = b, buf[o+0] = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = buf[o+1], c2 = g, buf[o+1] = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
(c1 = buf[o+2], c2 = r, buf[o+2] = ( (int)(c1)*(int)(255-a) + (int)(c2)*(int)(a) )/255);
}
o+=3;
}
}
}
x += sw;
}
} else if(im->format == HEFFER_FORMAT_ABGR32) {
for(index=0; index<len; index++) {
sx = font->x[text[index]];
sw = font->w[text[index]];
if(x >= im->x1 && x+sw < im->x2 && y >= im->y1 && y+h < im->y2) for(j=0; j<h; j++) {
int o = x*4 + (j+y)*bufw;
for(i=0; i<sw; i++) {
unsigned char a = font->buf[(i+sx)+j*font->bufw];
// TODO: Combine properly not just overwrite!
buf[o++] = a;
buf[o++] = b;
buf[o++] = g;
buf[o++] = r;
}
}
x += sw;
}
}
}
//---- Heffer_DrawText -------------------------------------------------------//
char heffer_drawtext_text[1024];
void Heffer_DrawText(HEFFER_IMAGE *im, int x1, int y1, int x2, int y2, HEFFER_FONT *font, char *t, int col, int flags)
{
int w = x2-x1;
int h = y2-y1;
int tw, th=0;
int x=x1, y=y1;
//- Find line breaks
int lastspacei, lastspacej;
int i=0, j=0;
while(t[i] && y+th <= y2) {
//- Get characters until width too big or we meet a newline
tw = 0;
j = 0;
lastspacei = -1;
lastspacej = -1;
heffer_drawtext_text[0] = 0;
while(tw <= w && t[i] && t[i] != '\n') {
if(t[i] == ' ') {
lastspacei = i;
lastspacej = j;
}
heffer_drawtext_text[j++] = t[i];
heffer_drawtext_text[j] = 0;
Heffer_GetTextSize(font, heffer_drawtext_text, &tw, &th);
i++;
}
// Lastspace is the character we need to break at (last space or newline)
if(tw > w) {
if(lastspacej > -1) {
heffer_drawtext_text[lastspacej] = 0;
i = lastspacei+1;
} else {
heffer_drawtext_text[j] = 0;
i--;
}
Heffer_TextOut(im, x, y, font, heffer_drawtext_text, col, flags);
} else if(!t[i]) {
Heffer_TextOut(im, x, y, font, heffer_drawtext_text, col, flags);
} else if(t[i] == '\n') {
Heffer_TextOut(im, x, y, font, heffer_drawtext_text, col, flags);
i++;
}
y += th;
}
}
//---- Heffer_AlphaMerge -----------------------------------------------------//
// Merges 2 images together using alpha into a destination image. Images must
// all the the same size - function not crash-proofed.
// Also all formats must be BGR24
// alpha=0 - all image 1, alpha=255 - all image 2.
void Heffer_AlphaMerge(HEFFER_IMAGE *imdest, HEFFER_IMAGE *imsrc1, HEFFER_IMAGE *imsrc2, int alpha)
{
int i, j;
if(alpha < 0) alpha = 0;
if(alpha > 255) alpha = 255;
// Addresses of buffers
unsigned char *sbuf1 = imsrc1->buf;
unsigned char *sbuf2 = imsrc2->buf;
unsigned char *dbuf = imdest->buf;
int w = imdest->w, h = imdest->h;
// Copy data - BGR24 + BGR24 -> BGR24
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char c1, c2;
(c1 = *sbuf1++, c2 = *sbuf2++, *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
(c1 = *sbuf1++, c2 = *sbuf2++, *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
(c1 = *sbuf1++, c2 = *sbuf2++, *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
}
sbuf1 += imsrc1->bufw - w*3;
sbuf2 += imsrc2->bufw - w*3;
dbuf += imdest->bufw - w*3;
}
}
//---- Heffer_DistortNAll ----------------------------------------------------//
// Merges 2 images together using alpha into a destination image. Images must
// all the the same size - function not crash-proofed.
// Also all formats must be BGR24
// alpha=0 - all image 1, alpha=255 - all image 2.
void Heffer_DistortNAll(HEFFER_IMAGE *imdest, HEFFER_IMAGE *imsrc1, HEFFER_IMAGE *imsrc2, unsigned char *distortx, unsigned char *distorty, int alpha)
{
int i, j;
if(alpha < 0) alpha = 0;
if(alpha > 255) alpha = 255;
int da1, da2;
da1 = alpha/5;
da2 = (255-alpha)/5;
if(da1 < 0) da1 = 0;
if(da1 > 255) da1 = 255;
if(da2 < 0) da2 = 0;
if(da2 > 255) da2 = 255;
// Addresses of buffers
unsigned char *sbuf1 = imsrc1->buf;
unsigned char *sbuf2 = imsrc2->buf;
unsigned char *dbuf = imdest->buf;
int w = imdest->w, h = imdest->h;
// Set up distortion
int pattern_sin[256];
for(i=0; i<256; i++) pattern_sin[i] = (int)(128+127*sin(i*3.1415926/128));
int time = alpha/5;
// Copy data - BGR24 + BGR24 -> BGR24
for(j=0; j<h; j++) {
for(i=0; i<w; i++) {
unsigned char x1, y1, x2, y2;
int distortx = (
pattern_sin[(time*3 + i*5 + j*4)&255] +
pattern_sin[(time*2 + i*2 + j*5)&255] +
pattern_sin[(time*1 + i*1 + j*3)&255] +
pattern_sin[(time*2 + i*3 + j*1)&255]
) * w / 1024;
int distorty = (
pattern_sin[(time*3 - i*1 - j*3)&255] +
pattern_sin[(time*1 - i*2 + j*1)&255] +
pattern_sin[(time*2 + i*1 + j*2)&255] +
pattern_sin[(time*1 + i*3 - j*2)&255]
) * h / 1024;
x1 = (((int)(distortx))*((int)(da1)) + ((int)i)*((int)(255-da1)))/255;
y1 = (((int)(distorty))*((int)(da1)) + ((int)j)*((int)(255-da1)))/255;
x2 = (((int)(distortx))*((int)(da2)) + ((int)i)*((int)(255-da2)))/255;
y2 = (((int)(distorty))*((int)(da2)) + ((int)j)*((int)(255-da2)))/255;
int os1 = x1+y1*w;
int os2 = x2+y2*w;
// os1 = i+j*w;
// os2 = i+j*w;
os1 *= 3; os2 *= 3;
unsigned char c1, c2;
(c1 = sbuf1[os1+0], c2 = sbuf2[os2+0], *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
(c1 = sbuf1[os1+1], c2 = sbuf2[os2+1], *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
(c1 = sbuf1[os1+2], c2 = sbuf2[os2+2], *dbuf++ = ( (int)(c1)*(int)(255-alpha) + (int)(c2)*(int)(alpha) )/255);
distortx ++;
distorty ++;
}
sbuf1 += imsrc1->bufw - w*3;
sbuf2 += imsrc2->bufw - w*3;
dbuf += imdest->bufw - w*3;
}
}
//---- Heffer_TextOutBorder --------------------------------------------------//
void Heffer_TextOutBorder(HEFFER_IMAGE *im, int x, int y, HEFFER_FONT *font, char *t, int col, int bcol, int flags)
{
Heffer_TextOut(im, x+1, y, font, t, bcol, flags);
Heffer_TextOut(im, x-1, y, font, t, bcol, flags);
Heffer_TextOut(im, x, y+1, font, t, bcol, flags);
Heffer_TextOut(im, x, y-1, font, t, bcol, flags);
Heffer_TextOut(im, x, y, font, t, col, flags);
}
//---- END OF FILE -----------------------------------------------------------//