Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

Commits (2)
  • Deucе's avatar
    Many X11 scaling improvements... · 767cbb9a
    Deucе authored
    1) Initialize the r2y array for xBR so it actually works.
    2) Add a vertical (only) interpolation scaler for aspect ratio enforcement
    3) Add a simple muliplier scaler, so that can be removed from x_event.c
    4) Use a new graphics buffer free list, which allows tracking last
       drawn screen instead of last bitmap rectangle, removing various hacks
    5) Share the Y'CbCr <-> R'dG'dB'd tables between xBR and scale.c
    767cbb9a
  • Deucе's avatar
    Align into columns, and add aspect ratios for more modes. · fc6a8fa6
    Deucе authored
    I really need to do a sweep through and update all the aspect
    ratios now that the data actually matters.
    fc6a8fa6
......@@ -11,6 +11,7 @@
#include "genwrap.h"
#include "dirwrap.h"
#include "xpbeep.h"
#include "scale.h"
#if (defined CIOLIB_IMPORTS)
#undef CIOLIB_IMPORTS
......@@ -1664,6 +1665,7 @@ int bitmap_drv_init(void (*drawrect_cb) (struct rectlist *data)
pthread_mutex_init(&screenb.screenlock, NULL);
pthread_mutex_init(&free_rect_lock, NULL);
pthread_mutex_lock(&vstatlock);
init_r2y();
vstat.vmem=NULL;
vstat.flags = VIDMODES_FLAG_PALETTE_VMEM;
pthread_mutex_lock(&screena.screenlock);
......
#include "scale.h"
#include "xbr.h"
uint32_t r2y[1<<24];
uint32_t y2r[1<<24];
static int r2y_inited;
static void pointy_scale3(uint32_t* src, uint32_t* dest, int width, int height);
static void pointy_scale5(uint32_t* src, uint32_t* dest, int width, int height);
static void interpolate_height(uint32_t* src, uint32_t* dst, int width, int height, int newheight);
static void multiply_scale(uint32_t* src, uint32_t* dst, int width, int height, int xmult, int ymult);
static struct graphics_buffer *free_list;
#define CLAMP(x) do { \
if (x < 0) \
x = 0; \
else if (x > 255) \
x = 255; \
} while(0)
void
init_r2y(void)
{
int r, g, b;
int y, u, v;
const double luma = 255.0 / 219;
const double col = 255.0 / 224;
if (r2y_inited)
return;
for (r = 0; r < 256; r++) {
for (g = 0; g < 256; g++) {
for (b = 0; b < 256; b++) {
y = 16 + ( 65.738 * r + 129.057 * g + 25.064 * b + 128) / 256;
CLAMP(y);
u = 128 + (-37.945 * r - 74.494 * g + 112.439 * b + 128) / 256;
CLAMP(u);
v = 128 + (112.439 * r - 94.154 * g - 18.285 * b + 128) / 256;
CLAMP(v);
r2y[(r<<16) | (g<<8) | b] = (y<<16)|(u<<8)|v;
}
}
}
for (y = 0; y < 256; y++) {
for (u = 0; u < 256; u++) {
for (v = 0; v < 256; v++) {
const int c = y - 16;
const int d = u - 128;
const int e = v - 128;
r = luma * c + col * 1.402 * e;
CLAMP(r);
g = luma * c - col * 1.772 * (0.114 / 0.587) * d - col * 1.402 * (0.299 / 0.587) * e;
CLAMP(g);
b = luma * c + col * 1.772 * d;
CLAMP(b);
uint32_t*
do_scale(struct rectlist* rect, uint32_t **target, size_t *targetsz, int* xscale, int* yscale, int* w, int* h)
y2r[(y<<16) | (u<<8) | v] = (r<<16)|(g<<8)|b;
}
}
}
r2y_inited = 1;
}
struct graphics_buffer *
get_buffer(void)
{
struct graphics_buffer* ret = NULL;
if (free_list) {
ret = free_list;
free_list = free_list->next;
ret->next = NULL;
return ret;
}
ret = calloc(1, sizeof(struct graphics_buffer));
return ret;
}
void
release_buffer(struct graphics_buffer *buf)
{
buf->next = free_list;
free_list = buf;
}
struct graphics_buffer *
do_scale(struct rectlist* rect, int* xscale, int* yscale, double ratio)
{
struct graphics_buffer* ret1 = get_buffer();
struct graphics_buffer* ret2 = get_buffer();
int pointy5 = 0;
int pointy3 = 0;
int xbr2 = 0;
int xbr4 = 0;
int ymult = 1;
int xmult = 1;
int newscale = 1;
int total_scaling = 1;
static uint32_t *tmptarget = NULL;
static size_t tmptargetsz = 0;
uint32_t *ctarget;
uint32_t *csrc = rect->data;
int total_xscaling = 1;
int total_yscaling = 1;
struct graphics_buffer *ctarget;
struct graphics_buffer *csrc;
uint32_t* nt;
int swidth = rect->rect.width;
int sheight = rect->rect.height;
*w = rect->rect.width;
*h = rect->rect.height;
// As a first pass, only do equal integer scaling
if (*xscale != *yscale)
return rect->data;
int fheight;
switch (*xscale) {
case 1:
return rect->data;
break;
case 2:
xbr2 = 1;
break;
......@@ -45,105 +124,155 @@ do_scale(struct rectlist* rect, uint32_t **target, size_t *targetsz, int* xscale
pointy3 = 1;
xbr2 = 1;
break;
case 7: // TODO: Do we want a pointy7 and pointy11?
xmult = 7;
ymult = 7;
break;
default:
total_scaling = *xscale;
total_xscaling = *xscale;
*xscale = 1;
while (total_scaling > 1 && ((total_scaling % 5) == 0)) {
total_yscaling = *yscale;
*yscale = 1;
while (total_xscaling > 1 && ((total_xscaling % 5) == 0) && ((total_yscaling % 5) == 0)) {
pointy5++;
total_scaling /= 5;
total_xscaling /= 5;
*xscale *= 5;
total_yscaling /= 5;
*yscale *= 5;
}
while (total_scaling > 1 && ((total_scaling % 3) == 0)) {
while (total_xscaling > 1 && ((total_xscaling % 3) == 0) && ((total_yscaling % 3) == 0)) {
pointy3++;
total_scaling /= 3;
total_xscaling /= 3;
*xscale *= 3;
total_yscaling /= 3;
*yscale *= 3;
}
while (total_scaling > 1 && ((total_scaling % 4) == 0)) {
while (total_xscaling > 1 && ((total_xscaling % 4) == 0) && ((total_yscaling % 4) == 0)) {
xbr4++;
total_scaling /= 4;
total_xscaling /= 4;
*xscale *= 4;
total_yscaling /= 4;
*yscale *= 4;
}
while (total_scaling > 1 && ((total_scaling % 2) == 0)) {
while (total_xscaling > 1 && ((total_xscaling % 2) == 0) && ((total_yscaling % 2) == 0)) {
xbr2++;
total_scaling /= 2;
total_xscaling /= 2;
*xscale *= 2;
total_yscaling /= 2;
*yscale *= 2;
}
if (*xscale == 1)
return rect->data;
break;
}
if (*xscale != *yscale) {
if (*yscale == *xscale * 2)
ymult *= 2;
else
return NULL;
}
// Calculate the scaled height from ratio...
fheight = lround((double)(rect->rect.height * (*yscale)) / ratio);
// Now make sure target is big enough...
size_t needsz = rect->rect.width * rect->rect.height * (*xscale) * (*xscale) * sizeof(uint32_t);
if (needsz > *targetsz) {
nt = realloc(*target, needsz);
size_t needsz = rect->rect.width * (*xscale) * fheight * sizeof(uint32_t);
if (needsz > ret1->sz) {
nt = realloc(ret1->data, needsz);
if (nt == NULL)
return rect->data;
*target = nt;
*targetsz = needsz;
return NULL;
ret1->data = nt;
ret1->sz = needsz;
}
ctarget = *target;
// And if we need an extra target, do the same there...
if (pointy3 + pointy5 + xbr4 + xbr2 > 1) {
if (needsz > tmptargetsz) {
nt = realloc(tmptarget, needsz);
if (nt == NULL)
return rect->data;
tmptarget = nt;
tmptargetsz = needsz;
}
if (needsz > ret2->sz) {
nt = realloc(ret2->data, needsz);
if (nt == NULL)
return NULL;
ret2->data = nt;
ret2->sz = needsz;
}
// And finally, scale...
// Copy rect into first buffer
// TODO: Unify bitmap rects and scaling buffers so this can just whomp on over.
csrc = ret1;
ctarget = ret2;
memcpy(csrc->data, rect->data, rect->rect.width * rect->rect.height * sizeof(rect->data[0]));
csrc->w = rect->rect.width;
csrc->h = rect->rect.height;
// And scale...
if (ymult != 1 || xmult != 1) {
multiply_scale(csrc->data, ctarget->data, csrc->w, csrc->h, xmult, ymult);
ctarget->w = csrc->w * xmult;
ctarget->h = csrc->h * ymult;
ymult = 1;
xmult = 1;
csrc = ctarget;
if (ctarget == ret1)
ctarget = ret2;
else
ctarget = ret1;
}
while (xbr4 > 0) {
xbr_filter(csrc, ctarget, swidth, sheight, 4);
xbr_filter(csrc->data, ctarget->data, csrc->w, csrc->h, 4);
xbr4--;
swidth *= 4;
sheight *= 4;
ctarget->w = csrc->w * 4;
ctarget->h = csrc->h * 4;
csrc = ctarget;
if (ctarget == tmptarget)
ctarget = *target;
if (ctarget == ret1)
ctarget = ret2;
else
ctarget = tmptarget;
ctarget = ret1;
}
while (xbr2 > 0) {
xbr_filter(csrc, ctarget, swidth, sheight, 2);
xbr_filter(csrc->data, ctarget->data, csrc->w, csrc->h, 2);
xbr2--;
swidth *= 2;
sheight *= 2;
ctarget->w = csrc->w * 2;
ctarget->h = csrc->h * 2;
csrc = ctarget;
if (ctarget == tmptarget)
ctarget = *target;
if (ctarget == ret1)
ctarget = ret2;
else
ctarget = tmptarget;
ctarget = ret1;
}
while (pointy5 > 0) {
pointy_scale5(csrc, ctarget, swidth, sheight);
pointy_scale5(csrc->data, ctarget->data, csrc->w, csrc->h);
pointy5--;
swidth *= 5;
sheight *= 5;
ctarget->w = csrc->w * 5;
ctarget->h = csrc->h * 5;
csrc = ctarget;
if (ctarget == tmptarget)
ctarget = *target;
if (ctarget == ret1)
ctarget = ret2;
else
ctarget = tmptarget;
ctarget = ret1;
}
while (pointy3 > 0) {
pointy_scale3(csrc, ctarget, swidth, sheight);
pointy_scale3(csrc->data, ctarget->data, csrc->w, csrc->h);
pointy3--;
swidth *= 3;
sheight *= 3;
ctarget->w = csrc->w * 3;
ctarget->h = csrc->h * 3;
csrc = ctarget;
if (ctarget == tmptarget)
ctarget = *target;
if (ctarget == ret1)
ctarget = ret2;
else
ctarget = tmptarget;
ctarget = ret1;
}
*w *= *xscale;
*h *= *xscale;
// And finally, interpolate if needed
if (ratio != 1) {
interpolate_height(csrc->data, ctarget->data, csrc->w, csrc->h, fheight);
ctarget->h = fheight;
ctarget->w = csrc->w;
csrc = ctarget;
if (ctarget == ret1)
ctarget = ret2;
else
ctarget = ret1;
}
*xscale = newscale;
*yscale = newscale;
release_buffer(ctarget);
return csrc;
}
......@@ -339,3 +468,93 @@ pointy_scale3(uint32_t* src, uint32_t* dest, int width, int height)
prevline = -width;
}
}
static __attribute__((always_inline))
uint32_t blend(const uint32_t c1, const uint32_t c2, const double weight)
{
uint8_t yuv1[4];
uint8_t yuv2[4];
int y, u, v;
const double iw = 1.0 - weight;
*(uint32_t *)yuv1 = r2y[c1];
*(uint32_t *)yuv2 = r2y[c2];
#ifdef __BIG_ENDIAN__
y = yuv1[1] * iw + yuv2[1] * weight;
u = yuv1[2] * iw + yuv2[2] * weight;
v = yuv1[3] * iw + yuv2[3] * weight;
#else
y = yuv1[2] * iw + yuv2[2] * weight;
u = yuv1[1] * iw + yuv2[1] * weight;
v = yuv1[0] * iw + yuv2[0] * weight;
#endif
CLAMP(y);
CLAMP(u);
CLAMP(v);
return y2r[(y<<16)|(u<<8)|v];
}
/*
* This does non-integer *height* scaling. It does not scale in the other
* direction. This does the interpolation using Y'UV to prevent dimming of
* pixels.
*/
static void
interpolate_height(uint32_t* src, uint32_t* dst, int width, int height, int newheight)
{
int x, y;
const double mult = (double)height / newheight;
for (y = 0; y < newheight; y++) {
for (x = 0; x < width; x++) {
// First, calculate which two pixels this is between.
const double ypos = mult * y;
const int yposi = ypos;
if (y == ypos) {
// Exact match!
*dst = src[width * yposi + x];
}
else {
const double weight = ypos - yposi;
// Now pick the two pixels
const uint32_t pix1 = src[yposi * width + x] & 0xffffff;
uint32_t pix2;
if (yposi < height - 1)
pix2 = src[(yposi + 1) * width + x] & 0xffffff;
else
pix2 = src[yposi * width + x] & 0xffffff;
if (pix1 == pix2)
*dst = pix1;
else {
*dst = blend(pix1, pix2, weight);
}
}
dst++;
}
}
}
static void
multiply_scale(uint32_t* src, uint32_t* dst, int width, int height, int xmult, int ymult)
{
int nheight = height * ymult;
int nwidth = width * xmult;
int x, y;
int mx, my;
uint32_t* slstart;
for (y = 0; y < height; y++) {
slstart = src;
for (my = 0; my < ymult; my++) {
src = slstart;
for (x = 0; x < width; x++) {
for (mx = 0; mx < xmult; mx++) {
*dst = *src;
dst++;
}
src++;
}
}
}
}
#include "bitmap_con.h"
uint32_t* do_scale(struct rectlist* rect, uint32_t **target, size_t *targetsz, int* xscale, int* yscale, int* w, int* h);
struct graphics_buffer {
uint32_t* data;
size_t sz;
size_t w;
size_t h;
struct graphics_buffer *next;
};
extern uint32_t r2y[1<<24];
extern uint32_t y2r[1<<24];
struct graphics_buffer * get_buffer(void);
void release_buffer(struct graphics_buffer *);
void init_r2y(void);
struct graphics_buffer * do_scale(struct rectlist* rect, int* xscale, int* yscale, double ratio);
......@@ -11,112 +11,112 @@
// TODO: Pretty much all the 1:1 aspect ratios are wrong...
struct video_params vparams[] = {
/* BW 40x25 */
{BW40, GREYSCALE_PALETTE, 40, 25, 14, 15, 16, 8, 1, 7, 0, 1, 1, 320, 200},
{BW40, GREYSCALE_PALETTE, 40, 25, 14, 15, 16, 8, 1, 7, 0, 833, 1000, 320, 200},
/* CO 40x25 */
{C40, COLOUR_PALETTE, 40, 25, 14, 15, 16, 8, 1, 7, 0, 1, 1, 320, 200},
{C40, COLOUR_PALETTE, 40, 25, 14, 15, 16, 8, 1, 7, 0, 833, 1000, 320, 200},
/* BW 80x25 */
{BW80, GREYSCALE_PALETTE, 80, 25, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 400},
{BW80, GREYSCALE_PALETTE, 80, 25, 14, 15, 16, 8, 1, 7, 0, 833, 1000, 640, 400},
/* CO 80x25 */
{C80, COLOUR_PALETTE, 80, 25, 14, 15, 16, 8, 1, 7, 0, 833, 1000, 640, 400},
{C80, COLOUR_PALETTE, 80, 25, 14, 15, 16, 8, 1, 7, 0, 833, 1000, 640, 400},
/* MONO */
{MONO, 0, 80, 25, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 400},
{MONO, 0, 80, 25, 14, 15, 16, 8, 1, 7, 0, 833, 1000, 640, 400},
/* CO 40x14 */
{C40X14, COLOUR_PALETTE, 40, 14, 14, 15, 16, 8, 1, 7, 0, 1, 1, 320, 224},
{C40X14, COLOUR_PALETTE, 40, 14, 14, 15, 16, 8, 1, 7, 0, 1, 1, 320, 224},
/* CO 40x21 */
{C40X21, COLOUR_PALETTE, 40, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 320, 336},
{C40X21, COLOUR_PALETTE, 40, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 320, 336},
/* CO 40x28 */
{C40X28, COLOUR_PALETTE, 40, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 320, 392},
{C40X28, COLOUR_PALETTE, 40, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 320, 392},
/* CO 40x43 */
{C40X43, COLOUR_PALETTE, 40, 43, 7, 7, 8, 8, 1, 7, 0, 1, 1, 320, 774},
{C40X43, COLOUR_PALETTE, 40, 43, 7, 7, 8, 8, 1, 7, 0, 1, 1, 320, 774},
/* CO 40x50 */
{C40X50, COLOUR_PALETTE, 40, 50, 7, 7, 8, 8, 1, 7, 0, 1, 1, 320, 400},
{C40X50, COLOUR_PALETTE, 40, 50, 7, 7, 8, 8, 1, 7, 0, 1, 1, 320, 400},
/* CO 40x60 */
{C40X60, COLOUR_PALETTE, 40, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 320, 480},
{C40X60, COLOUR_PALETTE, 40, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 320, 480},
/* CO 80x14 */
{C80X14, COLOUR_PALETTE, 80, 14, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 224},
{C80X14, COLOUR_PALETTE, 80, 14, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 224},
/* CO 80x21 */
{C80X21, COLOUR_PALETTE, 80, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 336},
{C80X21, COLOUR_PALETTE, 80, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 336},
/* CO 80x28 */
{C80X28, COLOUR_PALETTE, 80, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 640, 392},
{C80X28, COLOUR_PALETTE, 80, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 640, 392},
/* CO 80x30 */
{C80X30, COLOUR_PALETTE, 80, 30, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 480},
{C80X30, COLOUR_PALETTE, 80, 30, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 480},
/* CO 80x43 */
{C80X43, COLOUR_PALETTE, 80, 43, 7, 7, 8, 8, 1, 7, 0, 729, 1000, 640, 350},
{C80X43, COLOUR_PALETTE, 80, 43, 7, 7, 8, 8, 1, 7, 0, 729, 1000, 640, 350},
/* EGA 80x25 */
{EGA80X25, COLOUR_PALETTE, 80, 25, 12, 13, 14, 8, 1, 7, 0, 729, 1000, 640, 350},
{EGA80X25, COLOUR_PALETTE, 80, 25, 12, 13, 14, 8, 1, 7, 0, 729, 1000, 640, 350},
/* CO 80x50 */
{C80X50, COLOUR_PALETTE, 80, 50, 7, 7, 8, 8, 1, 7, 0, 1, 1, 640, 400},
{C80X50, COLOUR_PALETTE, 80, 50, 7, 7, 8, 8, 1, 7, 0, 833, 1000, 640, 400},
/* CO 80x60 */
{C80X60, COLOUR_PALETTE, 80, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 640, 480},
{C80X60, COLOUR_PALETTE, 80, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 640, 480},
/* B 40x14 */
{BW40X14, GREYSCALE_PALETTE, 40, 14, 14, 15, 16, 8, 1, 7, 0, 1, 1, 320, 224},
{BW40X14, GREYSCALE_PALETTE, 40, 14, 14, 15, 16, 8, 1, 7, 0, 1, 1, 320, 224},
/* BW 40x21 */
{BW40X21, GREYSCALE_PALETTE, 40, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 320, 336},
{BW40X21, GREYSCALE_PALETTE, 40, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 320, 336},
/* BW 40x28 */
{BW40X28, GREYSCALE_PALETTE, 40, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 320, 392},
{BW40X28, GREYSCALE_PALETTE, 40, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 320, 392},
/* BW 40x43 */
{BW40X43, GREYSCALE_PALETTE, 40, 43, 7, 7, 14, 8, 1, 7, 0, 1, 1, 320, 350},
{BW40X43, GREYSCALE_PALETTE, 40, 43, 7, 7, 14, 8, 1, 7, 0, 1, 1, 320, 350},
/* BW 40x50 */
{BW40X50, GREYSCALE_PALETTE, 40, 50, 7, 7, 8, 8, 1, 7, 0, 1, 1, 320, 400},
{BW40X50, GREYSCALE_PALETTE, 40, 50, 7, 7, 8, 8, 1, 7, 0, 1, 1, 320, 400},
/* BW 40x60 */
{BW40X60, GREYSCALE_PALETTE, 40, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 320, 480},
{BW40X60, GREYSCALE_PALETTE, 40, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 320, 480},
/* BW 80x14 */
{BW80X14, GREYSCALE_PALETTE, 80, 14, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 224},
{BW80X14, GREYSCALE_PALETTE, 80, 14, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 224},
/* BW 80x21 */
{BW80X21, GREYSCALE_PALETTE, 80, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 336},
{BW80X21, GREYSCALE_PALETTE, 80, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 336},
/* BW 80x28 */
{BW80X28, GREYSCALE_PALETTE, 80, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 640, 392},
{BW80X28, GREYSCALE_PALETTE, 80, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 640, 392},
/* BW 80x43 */
{BW80X43, GREYSCALE_PALETTE, 80, 43, 7, 7, 14, 8, 1, 7, 0, 1, 1, 640, 350},
{BW80X43, GREYSCALE_PALETTE, 80, 43, 7, 7, 14, 8, 1, 7, 0, 1, 1, 640, 350},
/* BW 80x50 */
{BW80X50, GREYSCALE_PALETTE, 80, 50, 7, 7, 8, 8, 1, 7, 0, 1, 1, 640, 400},
{BW80X50, GREYSCALE_PALETTE, 80, 50, 7, 7, 8, 8, 1, 7, 0, 833, 1000, 640, 400},
/* BW 80x60 */
{BW80X60, GREYSCALE_PALETTE, 80, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 640, 480},
{BW80X60, GREYSCALE_PALETTE, 80, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 640, 480},
/* MONO 80x14 */
{MONO14, MONO_PALETTE, 80, 14, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 224},
{MONO14, MONO_PALETTE, 80, 14, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 224},
/* MONO 80x21 */
{MONO21, MONO_PALETTE, 80, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 336},
{MONO21, MONO_PALETTE, 80, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 640, 336},
/* MONO 80x28 */
{MONO28, MONO_PALETTE, 80, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 640, 392},
{MONO28, MONO_PALETTE, 80, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 640, 392},
/* MONO 80x43 */
{MONO43, MONO_PALETTE, 80, 43, 7, 7, 14, 8, 1, 7, 0, 1, 1, 640, 350},
{MONO43, MONO_PALETTE, 80, 43, 7, 7, 14, 8, 1, 7, 0, 1, 1, 640, 350},
/* MONO 80x50 */
{MONO50, MONO_PALETTE, 80, 50, 7, 7, 8, 8, 1, 7, 0, 1, 1, 640, 400},
{MONO50, MONO_PALETTE, 80, 50, 7, 7, 8, 8, 1, 7, 0, 833, 1000, 640, 400},
/* MONO 80x60 */
{MONO60, MONO_PALETTE, 80, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 640, 480},
{MONO60, MONO_PALETTE, 80, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 640, 480},
/* Magical C4350 Mode */
{C4350, COLOUR_PALETTE, 80, 50, 7, 7, 8, 8, 1, 7, 0, 1, 1, 640, 400},
{C4350, COLOUR_PALETTE, 80, 50, 7, 7, 8, 8, 1, 7, 0, 833, 1000, 640, 400},
/* Commodore 64 40x25 mode */
{C64_40X25, C64_PALETTE, 40, 25, 0, 7, 8, 8, 1, 0x6e, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 1, 1, 320, 200},
{C64_40X25, C64_PALETTE, 40, 25, 0, 7, 8, 8, 1, 0x6e, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 1, 1, 320, 200},
/* Commodore 128 40x25 mode */
{C128_40X25, C64_PALETTE, 40, 25, 0, 7, 8, 8, 1, 0xbd, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 1, 1, 320, 200},
{C128_40X25, C64_PALETTE, 40, 25, 0, 7, 8, 8, 1, 0xbd, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 1, 1, 320, 200},
/* Commodore 128 80x25 mode */
{C128_80X25, COLOUR_PALETTE, 80, 25, 0, 7, 8, 8, 2, 7, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 1, 1, 640, 200},
{C128_80X25, COLOUR_PALETTE, 80, 25, 0, 7, 8, 8, 2, 7, CIOLIB_VIDEO_BGBRIGHT|CIOLIB_VIDEO_NOBLINK, 1, 1, 640, 200},
/* Atari 800 40x24 mode */
{ATARI_40X24, ATARI_PALETTE, 40, 24, 0, 7, 8, 8, 1, 7, 0, 1, 1, 320, 192},
{ATARI_40X24, ATARI_PALETTE, 40, 24, 0, 7, 8, 8, 1, 7, 0, 1, 1, 320, 192},
/* Atari 800 XEP80 80x25 mode */
{ATARI_80X25, GREYSCALE_PALETTE, 80, 25, 0, 15, 16, 8, 1, 7, 0, 1, 1, 640, 400},
{ATARI_80X25, GREYSCALE_PALETTE, 80, 25, 0, 15, 16, 8, 1, 7, 0, 833, 1000, 640, 400},
/* VESA 21x132 mode */
{VESA_132X21, COLOUR_PALETTE, 132, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 1056, 336},
{VESA_132X21, COLOUR_PALETTE, 132, 21, 14, 15, 16, 8, 1, 7, 0, 1, 1, 1056, 336},
/* VESA 25x132 mode */
{VESA_132X25, COLOUR_PALETTE, 132, 25, 14, 15, 16, 8, 1, 7, 0, 1, 1, 1056, 400},
{VESA_132X25, COLOUR_PALETTE, 132, 25, 14, 15, 16, 8, 1, 7, 0, 1, 1, 1056, 400},
/* VESA 28x132 mode */
{VESA_132X28, COLOUR_PALETTE, 132, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 1056, 392},
{VESA_132X28, COLOUR_PALETTE, 132, 28, 12, 13, 14, 8, 1, 7, 0, 1, 1, 1056, 392},
/* VESA 30x132 mode */
{VESA_132X30, COLOUR_PALETTE, 132, 30, 14, 15, 16, 8, 1, 7, 0, 1, 1, 1056, 480},
{VESA_132X30, COLOUR_PALETTE, 132, 30, 14, 15, 16, 8, 1, 7, 0, 1, 1, 1056, 480},
/* VESA 34x132 mode */
{VESA_132X34, COLOUR_PALETTE, 132, 34, 12, 13, 14, 8, 1, 7, 0, 1, 1, 1056, 476},
{VESA_132X34, COLOUR_PALETTE, 132, 34, 12, 13, 14, 8, 1, 7, 0, 1, 1, 1056, 476},
/* VESA 43x132 mode */
{VESA_132X43, COLOUR_PALETTE, 132, 43, 7, 7, 14, 8, 1, 7, 0, 1, 1, 1056, 350},
{VESA_132X43, COLOUR_PALETTE, 132, 43, 7, 7, 14, 8, 1, 7, 0, 1, 1, 1056, 350},
/* VESA 50x132 mode */
{VESA_132X50, COLOUR_PALETTE, 132, 50, 7, 7, 8, 8, 1, 7, 0, 1, 1, 1056, 400},
{VESA_132X50, COLOUR_PALETTE, 132, 50, 7, 7, 8, 8, 1, 7, 0, 1, 1, 1056, 400},
/* VESA 60x132 mode */
{VESA_132X60, COLOUR_PALETTE, 132, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 1056, 480},
{VESA_132X60, COLOUR_PALETTE, 132, 60, 7, 7, 8, 8, 1, 7, 0, 1, 1, 1056, 480},
/* Awesome modes */
{ST132X37_16_9, COLOUR_PALETTE, 132, 37, 14, 15, 16, 8, 1, 7, 0, 1, 1, 1056, 600},
{ST132X52_5_4, COLOUR_PALETTE, 132, 52, 14, 15, 16, 8, 1, 7, 0, 1, 1, 1056},
{ST132X37_16_9, COLOUR_PALETTE, 132, 37, 14, 15, 16, 8, 1, 7, 0, 1, 1, 1056, 600},
{ST132X52_5_4, COLOUR_PALETTE, 132, 52, 14, 15, 16, 8, 1, 7, 0, 1, 1, 1056, 823},
/* Custom mode */
{CIOLIB_MODE_CUSTOM, COLOUR_PALETTE, 80, 25, 14, 15, 16, 8, 1, 7, 0, 1, 1, -1, -1},
{CIOLIB_MODE_CUSTOM, COLOUR_PALETTE, 80, 25, 14, 15, 16, 8, 1, 7, 0, 1, 1, -1, -1},
};
uint32_t palettes[5][16] = {
......
......@@ -85,7 +85,7 @@ static unsigned long base_pixel;
static int r_shift;
static int g_shift;
static int b_shift;
static struct rectlist *last = NULL;
static struct graphics_buffer *last = NULL;
/* Array of Graphics Contexts */
static GC gc;
......@@ -208,9 +208,13 @@ static struct {
static void resize_xim(void)
{
int width = bitmap_width * x_cvstat.scaling;
double ratio = (double)x_cvstat.scale_numerator / x_cvstat.scale_denominator;
int height = lround((double)(bitmap_height * x_cvstat.scaling * x_cvstat.vmultiplier) / ratio);
if (xim) {
if (bitmap_width*x_cvstat.scaling == xim->width
&& bitmap_height*x_cvstat.scaling*x_cvstat.vmultiplier == xim->height) {
if (width == xim->width
&& height == xim->height) {
return;
}
#ifdef XDestroyImage
......@@ -220,11 +224,11 @@ static void resize_xim(void)
#endif
}
if (last) {
bitmap_drv_free_rect(last);
release_buffer(last);
last = NULL;
}
xim=x11.XCreateImage(dpy,&visual,depth,ZPixmap,0,NULL,bitmap_width*x_cvstat.scaling,bitmap_height*x_cvstat.scaling*x_cvstat.vmultiplier,32,0);
xim->data=(char *)malloc(xim->bytes_per_line*xim->height);
xim = x11.XCreateImage(dpy, &visual, depth, ZPixmap, 0, NULL, width, height, 32, 0);
xim->data=(char *)calloc(1, xim->bytes_per_line*xim->height);
}
/* Swiped from FreeBSD libc */
......@@ -346,6 +350,7 @@ static int init_window()
static void map_window()
{
XSizeHints *sh;
int scaled_height;
sh = x11.XAllocSizeHints();
if (sh == NULL) {
......@@ -357,7 +362,9 @@ static void map_window()
sh->base_height = bitmap_height*x_cvstat.scaling*x_cvstat.vmultiplier;
sh->min_width = sh->width_inc = sh->min_aspect.x = sh->max_aspect.x = bitmap_width;
sh->min_height = sh->height_inc = sh->min_aspect.y = sh->max_aspect.y = bitmap_height;
scaled_height = ceil((double)bitmap_height*x_cvstat.vmultiplier / ((double)x_cvstat.scale_numerator / x_cvstat.scale_denominator));
sh->min_height = sh->height_inc = sh->min_aspect.y = sh->max_aspect.y = scaled_height;
sh->flags = USSize | PMinSize | PSize | PResizeInc | PAspect;
x11.XSetWMNormalHints(dpy, win, sh);
......@@ -371,10 +378,11 @@ static void map_window()
/* Resize the window. This function is called after a mode change. */
static void resize_window()
{
x11.XResizeWindow(dpy, win, bitmap_width*x_cvstat.scaling, bitmap_height*x_cvstat.scaling*x_cvstat.vmultiplier);
resize_xim();
int scaled_height = ceil((double)bitmap_height*x_cvstat.scaling*x_cvstat.vmultiplier / ((double)x_cvstat.scale_numerator / x_cvstat.scale_denominator));
x11.XResizeWindow(dpy, win, bitmap_width*x_cvstat.scaling, scaled_height);
resize_xim();
return;
return;
}
static void init_mode_internal(int mode)
......@@ -386,7 +394,7 @@ static void init_mode_internal(int mode)
pthread_mutex_lock(&blinker_lock);
pthread_mutex_lock(&vstatlock);
if (last) {
bitmap_drv_free_rect(last);
release_buffer(last);
last = NULL;
}
bitmap_drv_init_mode(mode, &bitmap_width, &bitmap_height);
......@@ -451,7 +459,6 @@ static void local_draw_rect(struct rectlist *rect)
{
int x,y,xscale,yscale,xoff=0,yoff=0;
int xscaling, yscaling;
int rxscaling, ryscaling;
unsigned int r, g, b;
unsigned long pixel;
int cleft;
......@@ -459,14 +466,9 @@ static void local_draw_rect(struct rectlist *rect)
int ctop;
int cbottom = -1;
int idx;
int ridx;
int ridx_part;
uint32_t last_pixel = 0x55555555;
static uint32_t* target = NULL;
size_t targetsz = 0;
uint32_t* source;
int width, height;
int lheight, lines;
struct graphics_buffer *source;
int lines;
if (bitmap_width != rect->rect.width || bitmap_height != rect->rect.height)
return;
......@@ -481,23 +483,32 @@ static void local_draw_rect(struct rectlist *rect)
// Scale...
xscaling = x_cvstat.scaling;
yscaling = x_cvstat.scaling*x_cvstat.vmultiplier;
source = do_scale(rect, &target, &targetsz, &xscaling, &yscaling, &width, &height);
rxscaling = width / rect->rect.width;
ryscaling = height / rect->rect.height;
cleft = width;
ctop = height;
source = do_scale(rect, &xscaling, &yscaling, (double)x_cvstat.scale_numerator / x_cvstat.scale_denominator);
bitmap_drv_free_rect(rect);
if (source == NULL)
return;
cleft = source->w;
ctop = source->h;
lines = 0;
lheight = x_cvstat.charheight * ryscaling;
xoff = (x11_window_width - source->w) / 2;
if (xoff < 0)
xoff = 0;
yoff = (x11_window_height - source->h) / 2;
if (yoff < 0)
yoff = 0;
if (last && (last->w != source->w || last->h != source->h)) {
release_buffer(last);
last = NULL;
}
/* TODO: Translate into local colour depth */
for(y=0;y<height;y++) {
idx = y * width;
ridx = y / ryscaling * rect->rect.width;
ridx_part = 0;
for(x=0; x<width; x++) {
idx = 0;
for (y = 0; y < source->h; y++) {
for (x = 0; x < source->w; x++) {
if (last) {
// TODO: Based on source pixel, not target pixel. :(
if (last->data[ridx] != rect->data[ridx]) {
if (last->data[idx] != source->data[idx]) {
if (x < cleft)
cleft = x;
if (x > cright)
......@@ -508,29 +519,15 @@ static void local_draw_rect(struct rectlist *rect)
cbottom = y;
}
else {
if (source == rect->data) {
idx += (rxscaling);
x += (rxscaling - 1);
ridx++;
continue;
}
else {
if (cright < x - rxscaling * 2
&& (x >= width - (rxscaling * 3)
|| last->data[ridx + 1] == rect->data[ridx + 1])) {
idx += (rxscaling);
x += (rxscaling - 1);
ridx++;
continue;
}
}
idx++;
continue;
}
}
if (last_pixel != source[idx]) {
last_pixel = source[idx];
r = source[idx] >> 16 & 0xff;
g = source[idx] >> 8 & 0xff;
b = source[idx] & 0xff;
if (last_pixel != source->data[idx]) {
last_pixel = source->data[idx];
r = source->data[idx] >> 16 & 0xff;
g = source->data[idx] >> 8 & 0xff;
b = source->data[idx] & 0xff;
r = (r<<8)|r;
g = (g<<8)|g;
b = (b<<8)|b;
......@@ -548,6 +545,7 @@ static void local_draw_rect(struct rectlist *rect)
else
pixel |= (b >> (0-b_shift)) & visual.blue_mask;
}
// TODO: These loops shouldn't be necessary anymore...
for(yscale=0; yscale<yscaling; yscale++) {
for(xscale=0; xscale<xscaling; xscale++) {
#ifdef XPutPixel
......@@ -560,54 +558,36 @@ static void local_draw_rect(struct rectlist *rect)
}
}
idx++;
ridx_part++;
if (ridx_part >= rxscaling) {
ridx_part = 0;
ridx++;
}
}
lines++;
/* This line was changed */
if (last && ((lines == lheight) || (y == height - 1)) && cright >= 0) {
#ifdef USE_XBRZ
if (source != rect->data) {
cleft -= 2 * rxscaling;
if (cleft < 0)
cleft = 0;
cright += 2 * rxscaling;
if (cright >= width)
cright = width - 1;
}
#endif
// TODO: Previously this did one update per display line...
if (last && (cbottom != y || y == source->h - 1) && cright >= 0) {
lines = 0;
x11.XPutImage(dpy, win, gc, xim, cleft * xscaling, ctop * yscaling
, cleft * xscaling + xoff, ctop * yscaling + yoff
, (cright - cleft + 1) * xscaling, (cbottom - ctop + 1) * yscaling);
cleft = width;
cleft = source->w;
cright = cbottom = -100;
ctop = height;
ctop = source->h;
}
}
if (last == NULL)
x11.XPutImage(dpy, win, gc, xim, rect->rect.x*xscaling, rect->rect.y*yscaling, rect->rect.x*xscaling + xoff, rect->rect.y*yscaling + yoff, width * xscaling, height * yscaling);
x11.XPutImage(dpy, win, gc, xim, rect->rect.x*xscaling, rect->rect.y*yscaling, rect->rect.x*xscaling + xoff, rect->rect.y*yscaling + yoff, source->w * xscaling, source->h * yscaling);
else
bitmap_drv_free_rect(last);
last = rect;
release_buffer(last);
last = source;
}
static void handle_resize_event(int width, int height)
{
int newFSH=1;
int newFSW=1;
// No change
if((width == x_cvstat.charwidth * x_cvstat.cols * x_cvstat.scaling)
&& (height == x_cvstat.charheight * x_cvstat.rows * x_cvstat.scaling*x_cvstat.vmultiplier))
return;
double ratio = (double)x_cvstat.scale_numerator / x_cvstat.scale_denominator;
newFSH=width/bitmap_width;
newFSW=height/bitmap_height;
newFSW=floor((double)height / bitmap_height * ratio);
if(newFSW<1)
newFSW=1;
if(newFSH<1)
......@@ -627,9 +607,11 @@ static void handle_resize_event(int width, int height)
*/
if (newFSH != newFSW)
resize_window();
#if 0 // TODO: Is this even worth looking at?
else if((width % (x_cvstat.charwidth * x_cvstat.cols) != 0)
|| (height % (x_cvstat.charheight * x_cvstat.rows) != 0))
resize_window();
#endif
else
resize_xim();
bitmap_drv_request_pixels();
......@@ -680,7 +662,7 @@ static void expose_rect(int x, int y, int width, int height)
/* Since we're exposing, we *have* to redraw */
if (last) {
bitmap_drv_free_rect(last);
release_buffer(last);
last = NULL;
bitmap_drv_request_some_pixels(sx, sy, ex-sx+1, ey-sy+1);
}
......
......@@ -30,6 +30,7 @@
#include <inttypes.h>
#include <stdlib.h>
#include "scale.h"
#define LB_MASK 0x00FEFEFE
#define RED_BLUE_MASK 0x00FF00FF
......@@ -39,8 +40,6 @@
#undef PI
#endif
uint32_t r2y[1<<24];
static uint32_t pixel_diff(uint32_t x, uint32_t y)
{
#define YMASK 0xff0000
......@@ -190,6 +189,13 @@ static uint32_t pixel_diff(uint32_t x, uint32_t y)
} \
} while (0)
#define CLAMP(x) do { \
if (x < 0) \
x = 0; \
else if (x > 255) \
x = 255; \
} while(0)
void
xbr_filter(uint32_t *data, uint32_t *out, int width, int height, int n)
{
......