mirror of
https://gitea.nishi.boats/pyrite-dev/milsko
synced 2026-01-02 15:40:50 +00:00
821 lines
20 KiB
C
821 lines
20 KiB
C
#include <Mw/Milsko.h>
|
|
|
|
#ifdef NO_IMAGE
|
|
#elif defined(USE_STB_IMAGE)
|
|
#include "../external/stb_image.h"
|
|
#else
|
|
#include <png.h>
|
|
#include <jpeglib.h>
|
|
#include <jerror.h>
|
|
#endif
|
|
|
|
#include "../external/stb_ds.h"
|
|
|
|
static int get_color_diff(MwWidget handle) {
|
|
if(MwGetInteger(handle, MwNmodernLook)) {
|
|
return 46;
|
|
} else {
|
|
return 80;
|
|
}
|
|
}
|
|
|
|
static int hex(const char* txt, int len) {
|
|
int i;
|
|
int r = 0;
|
|
for(i = 0; i < len; i++) {
|
|
char c = txt[i];
|
|
int n = 0;
|
|
if('a' <= c && c <= 'f') {
|
|
n = c - 'a' + 10;
|
|
} else if('A' <= c && c <= 'F') {
|
|
n = c - 'A' + 10;
|
|
} else if('0' <= c && c <= '9') {
|
|
n = c - '0';
|
|
}
|
|
r = r << 4;
|
|
r |= n;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void MwParseColorNoAllocate(const char* text, MwRGB* rgb) {
|
|
if(text[0] == '#' && strlen(text) == 4) {
|
|
rgb->red = hex(text + 1, 1);
|
|
rgb->green = hex(text + 2, 1);
|
|
rgb->blue = hex(text + 3, 1);
|
|
|
|
rgb->red |= rgb->red << 4;
|
|
rgb->green |= rgb->green << 4;
|
|
rgb->blue |= rgb->blue << 4;
|
|
} else if(text[0] == '#' && strlen(text) == 7) {
|
|
rgb->red = hex(text + 1, 2);
|
|
rgb->green = hex(text + 3, 2);
|
|
rgb->blue = hex(text + 5, 2);
|
|
} else {
|
|
MwParseColorNameNoAllocate(text, rgb);
|
|
return;
|
|
}
|
|
}
|
|
|
|
MwLLColor MwParseColor(MwWidget handle, const char* text) {
|
|
MwRGB rgb;
|
|
|
|
rgb.red = 0;
|
|
rgb.green = 0;
|
|
rgb.blue = 0;
|
|
|
|
MwParseColorNoAllocate(text, &rgb);
|
|
|
|
return MwLLAllocColor(handle->lowlevel, rgb.red, rgb.green, rgb.blue);
|
|
}
|
|
|
|
MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b) {
|
|
int cr = color->common.red + r;
|
|
int cg = color->common.green + g;
|
|
int cb = color->common.blue + b;
|
|
|
|
if(cr < 0) cr = 0;
|
|
if(cg < 0) cg = 0;
|
|
if(cb < 0) cb = 0;
|
|
if(cr > 255) cr = 255;
|
|
if(cg > 255) cg = 255;
|
|
if(cb > 255) cb = 255;
|
|
|
|
return MwLLAllocColor(handle->lowlevel, cr, cg, cb);
|
|
}
|
|
|
|
void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) {
|
|
MwPoint p[4];
|
|
|
|
p[0].x = rect->x;
|
|
p[0].y = rect->y;
|
|
|
|
p[1].x = rect->x + rect->width;
|
|
p[1].y = rect->y;
|
|
|
|
p[2].x = rect->x + rect->width;
|
|
p[2].y = rect->y + rect->height;
|
|
|
|
p[3].x = rect->x;
|
|
p[3].y = rect->y + rect->height;
|
|
|
|
MwLLPolygon(handle->lowlevel, p, 4, color);
|
|
}
|
|
|
|
void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) {
|
|
MwLLPixmap pixmap;
|
|
int y;
|
|
double darken = 0.;
|
|
int ColorDiff = get_color_diff(handle);
|
|
double darkenStep = (ColorDiff / 4.) / rect->height;
|
|
unsigned long sz = 1 * rect->height * 4;
|
|
unsigned char* data = malloc(sz);
|
|
memset(data, 0, sz);
|
|
|
|
for(y = 0; y < rect->height; y++) {
|
|
MwLLColor col = MwLightenColor(handle, color, -darken, -darken, -darken);
|
|
int idx = y * 4;
|
|
data[idx] = col->common.red;
|
|
data[idx + 1] = col->common.green;
|
|
data[idx + 2] = col->common.blue;
|
|
data[idx + 3] = 255;
|
|
MwLLFreeColor(col);
|
|
darken += darkenStep;
|
|
}
|
|
|
|
pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height);
|
|
MwLLDrawPixmap(handle->lowlevel, rect, pixmap);
|
|
MwLLDestroyPixmap(pixmap);
|
|
|
|
free(data);
|
|
}
|
|
|
|
void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) {
|
|
int inv;
|
|
|
|
if((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv) invert = 1;
|
|
if(MwGetInteger(handle, MwNmodernLook)) {
|
|
MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle), 0, 0);
|
|
} else {
|
|
int diff = get_color_diff(handle) / 3 * 2;
|
|
|
|
if(MwDefaultBorderWidth(handle) >= 2) {
|
|
int i;
|
|
int st = invert ? 1 : 0;
|
|
for(i = st; i < st + 2; i++) {
|
|
if((i % 2) == 0) MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle) - 1, -diff, (handle->parent == NULL || handle->parent->lowlevel == NULL) ? 1 : 0);
|
|
if((i % 2) == 1) MwDrawFrameEx(handle, rect, color, invert, 1, diff, 0);
|
|
}
|
|
} else {
|
|
MwDrawFrameEx(handle, rect, color, invert, 1, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border) {
|
|
MwLLColor col;
|
|
|
|
if(border) {
|
|
MwDrawFrame(handle, rect, color, invert);
|
|
}
|
|
col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color;
|
|
if(MwGetInteger(handle, MwNmodernLook)) {
|
|
MwDrawRectFading(handle, rect, col);
|
|
} else {
|
|
MwDrawRect(handle, rect, col);
|
|
}
|
|
if(col != color) MwLLFreeColor(col);
|
|
}
|
|
|
|
void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) {
|
|
MwPoint p[6];
|
|
int border = MwDefaultBorderWidth(handle);
|
|
int ColorDiff = get_color_diff(handle);
|
|
MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff);
|
|
MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff);
|
|
MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color;
|
|
|
|
p[0].x = rect->x;
|
|
p[0].y = rect->y + rect->height / 2;
|
|
|
|
p[1].x = rect->x + rect->width / 2;
|
|
p[1].y = rect->y;
|
|
|
|
p[2].x = rect->x + rect->width;
|
|
p[2].y = rect->y + rect->height / 2;
|
|
|
|
p[3].x = rect->x + rect->width - border;
|
|
p[3].y = rect->y + rect->height / 2;
|
|
|
|
p[4].x = rect->x + rect->width / 2;
|
|
p[4].y = rect->y + border;
|
|
|
|
p[5].x = rect->x + border;
|
|
p[5].y = rect->y + rect->height / 2;
|
|
|
|
MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter);
|
|
|
|
p[0].x = rect->x;
|
|
p[0].y = rect->y + rect->height / 2;
|
|
|
|
p[1].x = rect->x + rect->width / 2;
|
|
p[1].y = rect->y + rect->height;
|
|
|
|
p[2].x = rect->x + rect->width;
|
|
p[2].y = rect->y + rect->height / 2;
|
|
|
|
p[3].x = rect->x + rect->width - border;
|
|
p[3].y = rect->y + rect->height / 2;
|
|
|
|
p[4].x = rect->x + rect->width / 2;
|
|
p[4].y = rect->y + rect->height - border;
|
|
|
|
p[5].x = rect->x + border;
|
|
p[5].y = rect->y + rect->height / 2;
|
|
|
|
MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker);
|
|
|
|
p[0].x = rect->x + rect->width / 2;
|
|
p[0].y = border;
|
|
|
|
p[1].x = rect->x + rect->width - border;
|
|
p[1].y = rect->height / 2;
|
|
|
|
p[2].x = rect->x + rect->width / 2;
|
|
p[2].y = rect->y + rect->height - border;
|
|
|
|
p[3].x = rect->x + border;
|
|
p[3].y = rect->height / 2;
|
|
|
|
MwLLPolygon(handle->lowlevel, p, 4, col);
|
|
|
|
if(col != color) MwLLFreeColor(col);
|
|
MwLLFreeColor(lighter);
|
|
MwLLFreeColor(darker);
|
|
}
|
|
|
|
void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) {
|
|
MwPoint p[6];
|
|
int ColorDiff = get_color_diff(handle);
|
|
MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff);
|
|
MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, ColorDiff - diff, ColorDiff - diff, ColorDiff - diff);
|
|
|
|
p[0].x = rect->x;
|
|
p[0].y = rect->y;
|
|
|
|
p[1].x = rect->x + rect->width;
|
|
p[1].y = rect->y;
|
|
|
|
p[2].x = rect->x + rect->width - border;
|
|
p[2].y = rect->y + border;
|
|
|
|
p[3].x = rect->x + border;
|
|
p[3].y = rect->y + border;
|
|
|
|
p[4].x = rect->x + border;
|
|
p[4].y = rect->y + rect->height - border;
|
|
|
|
p[5].x = rect->x;
|
|
p[5].y = rect->y + rect->height;
|
|
|
|
MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter);
|
|
|
|
p[0].x = rect->x + rect->width;
|
|
p[0].y = rect->y;
|
|
|
|
p[1].x = rect->x + rect->width - border;
|
|
p[1].y = rect->y + border;
|
|
|
|
p[2].x = rect->x + rect->width - border;
|
|
p[2].y = rect->y + rect->height - border;
|
|
|
|
p[3].x = rect->x + border;
|
|
p[3].y = rect->y + rect->height - border;
|
|
|
|
p[4].x = rect->x;
|
|
p[4].y = rect->y + rect->height;
|
|
|
|
p[5].x = rect->x + rect->width;
|
|
p[5].y = rect->y + rect->height;
|
|
|
|
MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker);
|
|
|
|
MwLLFreeColor(lighter);
|
|
MwLLFreeColor(darker);
|
|
|
|
rect->x += border;
|
|
rect->y += border;
|
|
rect->width -= border * 2;
|
|
rect->height -= border * 2;
|
|
}
|
|
|
|
void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int direction) {
|
|
MwPoint p1[4], p2[4], p3[4], p4[3];
|
|
const int border = MwGetInteger(handle, MwNmodernLook) ? 2 : MwDefaultBorderWidth(handle);
|
|
int ColorDiff = get_color_diff(handle);
|
|
MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff);
|
|
MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff);
|
|
MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color;
|
|
|
|
double deg = 30 * ((direction == MwEAST || direction == MwWEST) ? 2 : 1);
|
|
double c = cos(deg / 180 * M_PI);
|
|
double s = sin(deg / 180 * M_PI);
|
|
|
|
if(direction == MwNORTH) {
|
|
p1[0].x = rect->x + rect->width / 2;
|
|
p1[0].y = rect->y;
|
|
|
|
p1[1].x = rect->x;
|
|
p1[1].y = rect->y + rect->height;
|
|
|
|
p1[2].x = rect->x + c * border;
|
|
p1[2].y = rect->y + rect->height - s * border;
|
|
|
|
p1[3].x = rect->x + rect->width / 2;
|
|
p1[3].y = rect->y + border;
|
|
|
|
p2[0].x = rect->x + rect->width / 2;
|
|
p2[0].y = rect->y;
|
|
|
|
p2[1].x = rect->x + rect->width;
|
|
p2[1].y = rect->y + rect->height;
|
|
|
|
p2[2].x = rect->x + rect->width - c * border;
|
|
p2[2].y = rect->y + rect->height - s * border;
|
|
|
|
p2[3].x = rect->x + rect->width / 2;
|
|
p2[3].y = rect->y + border;
|
|
|
|
p3[0].x = rect->x + c * border;
|
|
p3[0].y = rect->y + rect->height - s * border;
|
|
|
|
p3[1].x = rect->x;
|
|
p3[1].y = rect->y + rect->height;
|
|
|
|
p3[2].x = rect->x + rect->width;
|
|
p3[2].y = rect->y + rect->height;
|
|
|
|
p3[3].x = rect->x + rect->width - c * border;
|
|
p3[3].y = rect->y + rect->height - s * border;
|
|
|
|
MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter);
|
|
MwLLPolygon(handle->lowlevel, p2, 4, invert ? lighter : darker);
|
|
MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker);
|
|
|
|
p4[0].x = rect->x + c * border;
|
|
p4[0].y = rect->y + rect->height - s * border;
|
|
|
|
p4[1].x = rect->x + rect->width - c * border;
|
|
p4[1].y = rect->y + rect->height - s * border;
|
|
|
|
p4[2].x = rect->x + rect->width / 2;
|
|
p4[2].y = rect->y + border;
|
|
} else if(direction == MwSOUTH) {
|
|
p1[0].x = rect->x;
|
|
p1[0].y = rect->y;
|
|
|
|
p1[1].x = rect->x + c * border;
|
|
p1[1].y = rect->y + s * border;
|
|
|
|
p1[2].x = rect->x + rect->width - c * border;
|
|
p1[2].y = rect->y + s * border;
|
|
|
|
p1[3].x = rect->x + rect->width;
|
|
p1[3].y = rect->y;
|
|
|
|
p2[0].x = rect->x;
|
|
p2[0].y = rect->y;
|
|
|
|
p2[1].x = rect->x + c * border;
|
|
p2[1].y = rect->y + s * border;
|
|
|
|
p2[2].x = rect->x + rect->width / 2;
|
|
p2[2].y = rect->y + rect->height - border;
|
|
|
|
p2[3].x = rect->x + rect->width / 2;
|
|
p2[3].y = rect->y + rect->height;
|
|
|
|
p3[0].x = rect->x + rect->width;
|
|
p3[0].y = rect->y;
|
|
|
|
p3[1].x = rect->x + rect->width / 2;
|
|
p3[1].y = rect->y + rect->height;
|
|
|
|
p3[2].x = rect->x + rect->width / 2;
|
|
p3[2].y = rect->y + rect->height - border;
|
|
|
|
p3[3].x = rect->x + rect->width - c * border;
|
|
p3[3].y = rect->y + s * border;
|
|
|
|
MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter);
|
|
MwLLPolygon(handle->lowlevel, p2, 4, invert ? darker : lighter);
|
|
MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker);
|
|
|
|
p4[0].x = rect->x + c * border;
|
|
p4[0].y = rect->y + s * border;
|
|
|
|
p4[1].x = rect->x + rect->width - c * border;
|
|
p4[1].y = rect->y + s * border;
|
|
|
|
p4[2].x = rect->x + rect->width / 2;
|
|
p4[2].y = rect->y + rect->height - border;
|
|
} else if(direction == MwEAST) {
|
|
p1[0].x = rect->x;
|
|
p1[0].y = rect->y;
|
|
|
|
p1[1].x = rect->x + c * border;
|
|
p1[1].y = rect->y + s * border;
|
|
|
|
p1[2].x = rect->x + c * border;
|
|
p1[2].y = rect->y + rect->height - s * border;
|
|
|
|
p1[3].x = rect->x;
|
|
p1[3].y = rect->y + rect->height;
|
|
|
|
p2[0].x = rect->x;
|
|
p2[0].y = rect->y;
|
|
|
|
p2[1].x = rect->x + rect->width;
|
|
p2[1].y = rect->y + rect->height / 2;
|
|
|
|
p2[2].x = rect->x + rect->width - border;
|
|
p2[2].y = rect->y + rect->height / 2;
|
|
|
|
p2[3].x = rect->x + c * border;
|
|
p2[3].y = rect->y + s * border;
|
|
|
|
p3[0].x = rect->x + c * border;
|
|
p3[0].y = rect->y + rect->height - s * border;
|
|
|
|
p3[1].x = rect->x;
|
|
p3[1].y = rect->y + rect->height;
|
|
|
|
p3[2].x = rect->x + rect->width;
|
|
p3[2].y = rect->y + rect->height / 2;
|
|
|
|
p3[3].x = rect->x + rect->width - border;
|
|
p3[3].y = rect->y + rect->height / 2;
|
|
|
|
MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter);
|
|
MwLLPolygon(handle->lowlevel, p2, 4, invert ? darker : lighter);
|
|
MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker);
|
|
|
|
p4[0].x = rect->x + rect->width - border;
|
|
p4[0].y = rect->y + rect->height / 2;
|
|
|
|
p4[1].x = rect->x + c * border;
|
|
p4[1].y = rect->y + rect->height - s * border;
|
|
|
|
p4[2].x = rect->x + c * border;
|
|
p4[2].y = rect->y + s * border;
|
|
} else if(direction == MwWEST) {
|
|
p1[0].x = rect->x;
|
|
p1[0].y = rect->y + rect->height / 2;
|
|
|
|
p1[1].x = rect->x + border;
|
|
p1[1].y = rect->y + rect->height / 2;
|
|
|
|
p1[2].x = rect->x + rect->width - c * border;
|
|
p1[2].y = rect->y + s * border;
|
|
|
|
p1[3].x = rect->x + rect->width;
|
|
p1[3].y = rect->y;
|
|
|
|
p2[0].x = rect->x;
|
|
p2[0].y = rect->y + rect->height / 2;
|
|
|
|
p2[1].x = rect->x + border;
|
|
p2[1].y = rect->y + rect->height / 2;
|
|
|
|
p2[2].x = rect->x + rect->width - c * border;
|
|
p2[2].y = rect->y + rect->height - s * border;
|
|
|
|
p2[3].x = rect->x + rect->width;
|
|
p2[3].y = rect->y + rect->height;
|
|
|
|
p3[0].x = rect->x + rect->width;
|
|
p3[0].y = rect->y;
|
|
|
|
p3[1].x = rect->x + rect->width - c * border;
|
|
p3[1].y = rect->y + s * border;
|
|
|
|
p3[2].x = rect->x + rect->width - c * border;
|
|
p3[2].y = rect->y + rect->height - s * border;
|
|
|
|
p3[3].x = rect->x + rect->width;
|
|
p3[3].y = rect->y + rect->height;
|
|
|
|
MwLLPolygon(handle->lowlevel, p1, 4, invert ? darker : lighter);
|
|
MwLLPolygon(handle->lowlevel, p2, 4, invert ? lighter : darker);
|
|
MwLLPolygon(handle->lowlevel, p3, 4, invert ? lighter : darker);
|
|
|
|
p4[0].x = rect->x + border;
|
|
p4[0].y = rect->y + rect->height / 2;
|
|
|
|
p4[1].x = rect->x + rect->width - c * border;
|
|
p4[1].y = rect->y + rect->height - s * border;
|
|
|
|
p4[2].x = rect->x + rect->width - c * border;
|
|
p4[2].y = rect->y + s * border;
|
|
}
|
|
MwLLPolygon(handle->lowlevel, p4, 3, col);
|
|
|
|
if(color != col) MwLLFreeColor(col);
|
|
|
|
MwLLFreeColor(lighter);
|
|
MwLLFreeColor(darker);
|
|
}
|
|
|
|
#if defined(NO_IMAGE)
|
|
#elif !defined(USE_STB_IMAGE)
|
|
static void PNGCAPI user_error(png_structp png, const char* str) {
|
|
(void)str;
|
|
|
|
longjmp(png_jmpbuf(png), 1);
|
|
}
|
|
|
|
static void PNGCAPI user_warning(png_structp png, const char* str) {
|
|
(void)png;
|
|
(void)str;
|
|
}
|
|
|
|
static unsigned char* load_png(FILE* f, int* w, int* h) {
|
|
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
png_infop info = png_create_info_struct(png);
|
|
int depth, type, i;
|
|
unsigned char* data;
|
|
unsigned char* row;
|
|
|
|
if(setjmp(png_jmpbuf(png))) {
|
|
png_destroy_read_struct(&png, &info, NULL);
|
|
return NULL;
|
|
}
|
|
|
|
png_set_error_fn(png, NULL, user_error, user_warning);
|
|
|
|
png_init_io(png, f);
|
|
png_read_info(png, info);
|
|
|
|
*w = png_get_image_width(png, info);
|
|
*h = png_get_image_height(png, info);
|
|
depth = png_get_bit_depth(png, info);
|
|
type = png_get_color_type(png, info);
|
|
|
|
if(depth == 16) png_set_strip_16(png);
|
|
if(type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
|
|
if(type == PNG_COLOR_TYPE_GRAY && depth < 8) png_set_expand_gray_1_2_4_to_8(png);
|
|
if(png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png);
|
|
if(type == PNG_COLOR_TYPE_RGB || type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_PALETTE) png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
|
|
if(type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png);
|
|
png_read_update_info(png, info);
|
|
|
|
data = malloc((*w) * (*h) * 4);
|
|
|
|
row = malloc(png_get_rowbytes(png, info));
|
|
for(i = 0; i < (*h); i++) {
|
|
png_read_row(png, row, NULL);
|
|
memcpy(&data[i * (*w) * 4], row, png_get_rowbytes(png, info));
|
|
}
|
|
free(row);
|
|
|
|
png_destroy_read_struct(&png, &info, NULL);
|
|
|
|
return data;
|
|
}
|
|
|
|
static void jpeg_err(j_common_ptr cinfo) {
|
|
jmp_buf* j = cinfo->client_data;
|
|
|
|
longjmp(*j, 1);
|
|
}
|
|
|
|
static unsigned char* load_jpeg(FILE* f, int* w, int* h) {
|
|
struct jpeg_decompress_struct cinfo;
|
|
struct jpeg_error_mgr jerr;
|
|
jmp_buf* j = malloc(sizeof(*j));
|
|
unsigned char* data;
|
|
unsigned char* row;
|
|
int i;
|
|
|
|
if(setjmp(*j)) {
|
|
jpeg_destroy_decompress(&cinfo);
|
|
free(j);
|
|
return NULL;
|
|
}
|
|
|
|
cinfo.client_data = j;
|
|
cinfo.err = jpeg_std_error(&jerr);
|
|
jerr.error_exit = jpeg_err;
|
|
|
|
jpeg_create_decompress(&cinfo);
|
|
jpeg_stdio_src(&cinfo, f);
|
|
jpeg_read_header(&cinfo, TRUE);
|
|
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
*w = cinfo.output_width;
|
|
*h = cinfo.output_height;
|
|
|
|
data = malloc((*w) * (*h) * 4);
|
|
row = malloc((*h) * cinfo.num_components);
|
|
for(i = 0; i < (*h); i++) {
|
|
int j;
|
|
jpeg_read_scanlines(&cinfo, &row, 1);
|
|
|
|
for(j = 0; j < (*w); j++) {
|
|
unsigned char* from = &row[j * cinfo.num_components];
|
|
unsigned char* to = &data[(i * (*w) + j) * 4];
|
|
|
|
memcpy(to, from, 3);
|
|
to[3] = 255;
|
|
}
|
|
}
|
|
free(row);
|
|
|
|
jpeg_finish_decompress(&cinfo);
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
free(j);
|
|
|
|
return data;
|
|
}
|
|
#endif
|
|
|
|
static unsigned char* load_image(const char* path, int* w, int* h) {
|
|
#if defined(NO_IMAGE)
|
|
return NULL;
|
|
#elif defined(USE_STB_IMAGE)
|
|
int ch;
|
|
|
|
return stbi_load(path, w, h, &ch, 4);
|
|
#else
|
|
FILE* f = fopen(path, "rb");
|
|
unsigned char* d;
|
|
if(f == NULL) return NULL;
|
|
|
|
if((d = load_png(f, w, h)) != NULL) return d;
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
if((d = load_jpeg(f, w, h)) != NULL) return d;
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
fclose(f);
|
|
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
MwLLPixmap MwLoadImage(MwWidget handle, const char* path) {
|
|
int width, height;
|
|
unsigned char* rgb = load_image(path, &width, &height);
|
|
MwLLPixmap px;
|
|
|
|
if(rgb == NULL) return NULL;
|
|
|
|
px = MwLoadRaw(handle, rgb, width, height);
|
|
|
|
free(rgb);
|
|
|
|
return px;
|
|
}
|
|
|
|
MwLLPixmap MwLoadRaw(MwWidget handle, unsigned char* rgb, int width, int height) {
|
|
MwLLPixmap px = MwLLCreatePixmap(handle->lowlevel, rgb, width, height);
|
|
|
|
px->common.user = handle;
|
|
MwPixmapReloadRaw(px, rgb);
|
|
|
|
return px;
|
|
}
|
|
|
|
void MwPixmapReloadRaw(MwLLPixmap px, unsigned char* rgb) {
|
|
int i;
|
|
MwWidget handle = px->common.user;
|
|
MwLLColor base = handle->bgcolor == NULL ? MwParseColor(handle, MwGetText(handle, MwNbackground)) : handle->bgcolor;
|
|
|
|
memset(px->common.raw, 0, px->common.width * px->common.height * 4);
|
|
for(i = 0; i < px->common.width * px->common.height; i++) {
|
|
unsigned char* pin = &rgb[i * 4];
|
|
unsigned char* pout = &px->common.raw[i * 4];
|
|
double a = pin[3];
|
|
|
|
a /= 255;
|
|
if(a != 0) {
|
|
pout[0] = pin[0] * a;
|
|
pout[1] = pin[1] * a;
|
|
pout[2] = pin[2] * a;
|
|
|
|
pout[0] += base->common.red * (1 - a);
|
|
pout[1] += base->common.green * (1 - a);
|
|
pout[2] += base->common.blue * (1 - a);
|
|
pout[3] = 255;
|
|
}
|
|
}
|
|
|
|
if(handle->bgcolor == NULL) MwLLFreeColor(base);
|
|
|
|
MwLLPixmapUpdate(px);
|
|
}
|
|
|
|
unsigned char* MwPixmapGetRaw(MwLLPixmap pixmap) {
|
|
return pixmap->common.raw;
|
|
}
|
|
|
|
void MwPixmapGetSize(MwLLPixmap pixmap, MwRect* rect) {
|
|
rect->width = pixmap->common.width;
|
|
rect->height = pixmap->common.height;
|
|
}
|
|
|
|
void MwColorGet(MwLLColor color, int* red, int* green, int* blue) {
|
|
*red = color->common.red;
|
|
*green = color->common.green;
|
|
*blue = color->common.blue;
|
|
}
|
|
|
|
MwLLPixmap MwLoadIcon(MwWidget handle, MwU32* data) {
|
|
int width = (data[0] >> 16) & 0xffff;
|
|
int height = (data[0]) & 0xffff;
|
|
unsigned char* rgba = malloc(width * height * 4);
|
|
MwLLPixmap px;
|
|
int i;
|
|
|
|
memset(rgba, 0, width * height * 4);
|
|
|
|
for(i = 0; i < width * height; i++) {
|
|
unsigned char* px = &rgba[i * 4];
|
|
|
|
px[0] = (data[i + 1] >> 24) & 0xff;
|
|
px[1] = (data[i + 1] >> 16) & 0xff;
|
|
px[2] = (data[i + 1] >> 8) & 0xff;
|
|
px[3] = data[i + 1] & 0xff;
|
|
}
|
|
|
|
px = MwLoadRaw(handle, rgba, width, height);
|
|
|
|
free(rgba);
|
|
|
|
return px;
|
|
}
|
|
|
|
typedef struct color {
|
|
char* key;
|
|
char* value;
|
|
int r;
|
|
int g;
|
|
int b;
|
|
int a;
|
|
} color_t;
|
|
|
|
MwLLPixmap MwLoadXPM(MwWidget handle, char** data) {
|
|
int col, row, colors, cpp;
|
|
unsigned char* rgb;
|
|
MwLLPixmap px;
|
|
color_t* c = NULL;
|
|
int i, y, x;
|
|
char* comp;
|
|
|
|
sh_new_strdup(c);
|
|
|
|
sscanf(data[0], "%d %d %d %d", &col, &row, &colors, &cpp);
|
|
|
|
for(i = 0; i < colors; i++) {
|
|
char k[128];
|
|
char* v = data[i + 1] + cpp + 3;
|
|
int ind;
|
|
if(strcmp(v, "None") == 0) {
|
|
memcpy(k, data[i + 1], cpp);
|
|
k[cpp] = 0;
|
|
|
|
shput(c, k, v);
|
|
ind = shgeti(c, k);
|
|
|
|
c[ind].r = 0;
|
|
c[ind].g = 0;
|
|
c[ind].b = 0;
|
|
c[ind].a = 0;
|
|
} else {
|
|
MwLLColor color = MwParseColor(handle, v);
|
|
|
|
memcpy(k, data[i + 1], cpp);
|
|
k[cpp] = 0;
|
|
|
|
shput(c, k, v);
|
|
ind = shgeti(c, k);
|
|
|
|
c[ind].r = color->common.red;
|
|
c[ind].g = color->common.green;
|
|
c[ind].b = color->common.blue;
|
|
c[ind].a = 255;
|
|
|
|
MwLLFreeColor(color);
|
|
}
|
|
}
|
|
|
|
rgb = malloc(row * col * 4);
|
|
comp = malloc(cpp + 1);
|
|
comp[cpp] = 0;
|
|
for(y = 0; y < row; y++) {
|
|
for(x = 0; x < col; x++) {
|
|
unsigned char* pout = &rgb[(y * col + x) * 4];
|
|
color_t colent;
|
|
memcpy(comp, &data[1 + colors + y][x * cpp], cpp);
|
|
|
|
colent = shgets(c, comp);
|
|
|
|
pout[0] = colent.r;
|
|
pout[1] = colent.g;
|
|
pout[2] = colent.b;
|
|
pout[3] = colent.a;
|
|
}
|
|
}
|
|
free(comp);
|
|
|
|
px = MwLoadRaw(handle, rgb, col, row);
|
|
|
|
free(rgb);
|
|
|
|
shfree(c);
|
|
|
|
return px;
|
|
}
|