Переглянути джерело

image: we can now write Oric .tap files.

undefined
Sam Hocevar 10 роки тому
джерело
коміт
93a6b1b75b
1 змінених файлів з 81 додано та 103 видалено
  1. +81
    -103
      src/image/codec/oric-image.cpp

+ 81
- 103
src/image/codec/oric-image.cpp Переглянути файл

@@ -1,7 +1,7 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
// Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
@@ -24,7 +24,6 @@ namespace lol
* DEPTH = 3 gives good quality, and higher values may improve the results
* even more but at the cost of significantly longer computation times. */
#define WIDTH 240
#define HEIGHT 200
#define DEPTH 2

/*
@@ -39,6 +38,7 @@ public:

private:
static String ReadScreen(char const *name);
static void WriteScreen(Image &image, Array<uint8_t> &result);
};

DECLARE_IMAGE_CODEC(OricImageCodec, 100)
@@ -110,7 +110,41 @@ bool OricImageCodec::Load(Image *image, char const *path)

bool OricImageCodec::Save(Image *image, char const *path)
{
return false;
int len = strlen(path);
if (len < 4 || path[len - 4] != '.'
|| toupper(path[len - 3]) != 'T'
|| toupper(path[len - 2]) != 'A'
|| toupper(path[len - 1]) != 'P')
return false;

Array<uint8_t> result;

result << 0x16 << 0x16 << 0x16 << 0x16 << 0x24;
result << 0 << 0xff << 0x80 << 0 << 0xbf << 0x3f << 0xa0 << 0;

/* Add filename, except the last 4 characters */
for (char const *name = path; name[4]; ++name)
result << (uint8_t)name[0];
result << 0;

Image tmp;
ivec2 size = image->GetSize();
if (size.x != WIDTH)
{
size.y = (int)((float)size.y * WIDTH / size.x);
size.x = WIDTH;
tmp = image->Resize(size, ResampleAlgorithm::Bresenham);
image = &tmp;
}

WriteScreen(*image, result);

File f;
f.Open(path, FileAccess::Write);
f.Write(result.Data(), result.Bytes());
f.Close();

return true;
}

String OricImageCodec::ReadScreen(char const *name)
@@ -144,61 +178,6 @@ String OricImageCodec::ReadScreen(char const *name)
return data.Sub(filename_end + 1);
}

#if 0

pipi_image_t *pipi_load_oric(char const *name)
{
}

int pipi_save_oric(pipi_image_t *img, char const *name)
{
pipi_image_t *tmp = NULL;
pipi_pixels_t *p;
float *data;
uint8_t *screen;
FILE *fp;
size_t len;

len = strlen(name);
if (len < 4 || name[len - 4] != '.'
|| toupper(name[len - 3]) != 'T'
|| toupper(name[len - 2]) != 'A'
|| toupper(name[len - 1]) != 'P')
return -1;

fp = fopen(name, "w");
if (!fp)
return -1;

fwrite("\x16\x16\x16\x16\x24", 1, 5, fp);
fwrite("\x00\xff\x80\x00\xbf\x3f\xa0\x00\x00", 1, 9, fp);
fwrite(name, 1, len - 4, fp);
fwrite("\x00", 1, 1, fp);

if (img->w != WIDTH || img->h != HEIGHT)
tmp = pipi_resize_bicubic(img, WIDTH, HEIGHT);
else
tmp = img;
p = pipi_get_pixels(tmp, PIPI_PIXELS_RGBA_F32);
data = p->pixels;
screen = malloc(WIDTH * HEIGHT / 6);
write_screen(data, screen);
pipi_release_pixels(tmp, p);
if (tmp != img)
pipi_free(tmp);

fwrite(screen, 1, WIDTH * HEIGHT / 6, fp);
fclose(fp);

free(screen);

return 0;
}

/*
* XXX: The following functions are local.
*/

/* Error diffusion table, similar to Floyd-Steinberg. I choose not to
* propagate 100% of the error, because doing so creates awful artifacts
* (full lines of the same colour, massive colour bleeding) for unclear
@@ -251,7 +230,7 @@ static inline void domove(uint8_t command, uint8_t *bg, uint8_t *fg)
/* Clamp pixel value to avoid colour bleeding. Deactivated because it
* does not give satisfactory results. */
#define CLAMP 0x1000
static inline int clamp(int p)
static inline int myclamp(int p)
{
#if 0
/* FIXME: doesn’t give terribly good results on eg. eatme.png */
@@ -283,7 +262,7 @@ static inline int geterror(int const *in, int const *inerr,
for (c = 0; c < 3; c++)
{
/* Experiment shows that this is important at small depths */
int a = clamp(in[i * 3 + c] + tmperr[c]);
int a = myclamp(in[i * 3 + c] + tmperr[c]);
int b = out[i * 3 + c];
tmperr[c] = (a - b) * FS0 / FSX;
tmperr[c + (i * 3 + 3)] += (a - b) * FS1 / FSX;
@@ -430,30 +409,30 @@ static uint8_t bestmove(int const *in, uint8_t bg, uint8_t fg,

for (i = 0; i < 6; i++)
{
int vec1[3], vec2[3];
int veca[3], vecb[3];
int smalle1 = 0, smalle2 = 0;

memcpy(vec1, tmpvec, 3 * sizeof(int));
memcpy(vec2, tmpvec, 3 * sizeof(int));
memcpy(veca, tmpvec, 3 * sizeof(int));
memcpy(vecb, tmpvec, 3 * sizeof(int));
for (c = 0; c < 3; c++)
{
int delta1, delta2;
delta1 = clamp(in[i * 3 + c] + tmpvec[c]) - bgcolor[c];
vec1[c] = delta1 * FS0 / FSX;
delta1 = myclamp(in[i * 3 + c] + tmpvec[c]) - bgcolor[c];
veca[c] = delta1 * FS0 / FSX;
smalle1 += delta1 / 256 * delta1;
delta2 = clamp(in[i * 3 + c] + tmpvec[c]) - fgcolor[c];
vec2[c] = delta2 * FS0 / FSX;
delta2 = myclamp(in[i * 3 + c] + tmpvec[c]) - fgcolor[c];
vecb[c] = delta2 * FS0 / FSX;
smalle2 += delta2 / 256 * delta2;
}

if (smalle1 < smalle2)
{
memcpy(tmpvec, vec1, 3 * sizeof(int));
memcpy(tmpvec, veca, 3 * sizeof(int));
memcpy(tmprgb + i * 3, bgcolor, 3 * sizeof(int));
}
else
{
memcpy(tmpvec, vec2, 3 * sizeof(int));
memcpy(tmpvec, vecb, 3 * sizeof(int));
memcpy(tmprgb + i * 3, fgcolor, 3 * sizeof(int));
command |= (1 << (5 - i));
}
@@ -509,72 +488,71 @@ static uint8_t bestmove(int const *in, uint8_t bg, uint8_t fg,
return bestcommand;
}

static void write_screen(float const *data, uint8_t *screen)
void OricImageCodec::WriteScreen(Image &image, Array<uint8_t> &result)
{
int *src, *srcl, *dst, *dstl;
int stride, x, y, depth, c;
ivec2 size = image.GetSize();
vec4 *pixels = image.Lock<PixelFormat::RGBA_F32>();

stride = (WIDTH + 1) * 3;
int stride = (size.x + 1);

src = malloc((WIDTH + 1) * (HEIGHT + 1) * 3 * sizeof(int));
memset(src, 0, (WIDTH + 1) * (HEIGHT + 1) * 3 * sizeof(int));
ivec3 *src = (ivec3 *)malloc((size.x + 1) * (size.y + 1) * sizeof(ivec3));
memset(src, 0, (size.x + 1) * (size.y + 1) * sizeof(ivec3));

dst = malloc((WIDTH + 1) * (HEIGHT + 1) * 3 * sizeof(int));
memset(dst, 0, (WIDTH + 1) * (HEIGHT + 1) * 3 * sizeof(int));
ivec3 *dst = (ivec3 *)malloc((size.x + 1) * (size.y + 1) * sizeof(ivec3));
memset(dst, 0, (size.x + 1) * (size.y + 1) * sizeof(ivec3));

/* Import pixels into our custom format */
for (y = 0; y < HEIGHT; y++)
for (x = 0; x < WIDTH; x++)
for (c = 0; c < 3; c++)
src[y * stride + x * 3 + c] =
0xffff * data[(y * WIDTH + x) * 4 + (2 - c)];
for (int y = 0; y < size.y; y++)
for (int x = 0; x < size.x; x++)
for (int c = 0; c < 3; c++)
src[y * stride + x][c] = 0xffff * pixels[y * size.x + x][2 - c];

/* Let the fun begin */
for (y = 0; y < HEIGHT; y++)
for (int y = 0; y < size.y; y++)
{
uint8_t bg = 0, fg = 7;

//fprintf(stderr, "\rProcessing... %i%%", (y * 100 + 99) / HEIGHT);
//fprintf(stderr, "\rProcessing... %i%%", (y * 100 + 99) / size.y);

for (x = 0; x < WIDTH; x += 6)
for (int x = 0; x < size.x; x += 6)
{
int errvec[3] = { 0, 0, 0 };
int dummy, i;
int dummy;
uint8_t command;

depth = (x + DEPTH < WIDTH) ? DEPTH : (WIDTH - x) / 6 - 1;
srcl = src + y * stride + x * 3;
dstl = dst + y * stride + x * 3;
int depth = (x + DEPTH < size.x) ? DEPTH : (size.x - x) / 6 - 1;
ivec3 *srcl = src + y * stride + x;
ivec3 *dstl = dst + y * stride + x;

/* Recursively compute and apply best command */
command = bestmove(srcl, bg, fg, errvec, depth, 0x7fffff,
&dummy, dstl);
command = bestmove((int *)srcl, bg, fg, errvec, depth, 0x7fffff,
&dummy, (int *)dstl);
/* Propagate error */
for (c = 0; c < 3; c++)
for (int c = 0; c < 3; c++)
{
for (i = 0; i < 6; i++)
for (int i = 0; i < 6; i++)
{
int error = srcl[i * 3 + c] - dstl[i * 3 + c];
srcl[i * 3 + c + 3] =
clamp(srcl[i * 3 + c + 3] + error * FS0 / FSX);
srcl[i * 3 + c + stride - 3] += error * FS1 / FSX;
srcl[i * 3 + c + stride] += error * FS2 / FSX;
srcl[i * 3 + c + stride + 3] += error * FS3 / FSX;
int error = srcl[i][c] - dstl[i][c];
srcl[i + 1][c] = myclamp(srcl[i + 1][c] + error * FS0 / FSX);
srcl[i + stride - 1][c] += error * FS1 / FSX;
srcl[i + stride][c] += error * FS2 / FSX;
srcl[i + stride + 1][c] += error * FS3 / FSX;
}

for (i = -1; i < 7; i++)
srcl[i * 3 + c + stride] = clamp(srcl[i * 3 + c + stride]);
for (int i = -1; i < 7; i++)
srcl[i + stride][c] = myclamp(srcl[i + stride][c]);
}
/* Iterate */
domove(command, &bg, &fg);
/* Write byte to file */
screen[y * (WIDTH / 6) + (x / 6)] = command;
result << command;
}
}

image.Unlock(pixels);

//fprintf(stderr, " done.\n");
}
#endif

} /* namespace lol */


Завантаження…
Відмінити
Зберегти