476 lines
14 KiB
C++
476 lines
14 KiB
C++
|
|
#include "picture.hpp"
|
|
#include "file.hpp"
|
|
#include "math.hpp"
|
|
#include "main.hpp"
|
|
|
|
#define BUFFER 8
|
|
/*******************************************************************************
|
|
** PictureSavePPM
|
|
*******************************************************************************/
|
|
void
|
|
PictureSavePPM(Picture* picture, char* filename)
|
|
{
|
|
assert(picture && filename);
|
|
|
|
FILE* file = fopen(filename, "wb");
|
|
|
|
ThrowIf(file == NULL, "Could not open PPM file");
|
|
|
|
fprintf(file, "P3\n%d %d 31\n", picture->width, picture->height);
|
|
|
|
for (int y = 0; y < picture->height; y++)
|
|
{
|
|
for (int x = 0; x < picture->width; x++)
|
|
{
|
|
fprintf(file, "%d %d %d\n",
|
|
PixelRed (picture->pixels[y][x]),
|
|
PixelGreen(picture->pixels[y][x]),
|
|
PixelBlue (picture->pixels[y][x]));
|
|
}
|
|
}
|
|
fclose(file);
|
|
}
|
|
/*******************************************************************************
|
|
** PicturePixelAddress
|
|
*******************************************************************************/
|
|
Pixel*
|
|
PicturePixelAddress(Picture* src, int x, int y)
|
|
{
|
|
return src->pixels[y] + x;
|
|
}
|
|
/*******************************************************************************
|
|
** PictureWindow
|
|
*******************************************************************************/
|
|
void
|
|
PictureWindow(Picture* dst, Picture* src, int x, int y, int width, int height)
|
|
{
|
|
PictureCreate(dst, width, height, PicturePixelAddress(src, x, y), src->pitch);
|
|
}
|
|
/*******************************************************************************
|
|
** PictureCreate
|
|
*******************************************************************************/
|
|
void
|
|
PictureCreate(Picture* dst, int width, int height, Pixel* surface, int pitch)
|
|
{
|
|
int i;
|
|
|
|
assert(dst);
|
|
|
|
memset(dst, 0, sizeof(Picture));
|
|
|
|
dst->rect = RectCreate(0, 0, width, height);
|
|
dst->width = width;
|
|
dst->height = height;
|
|
dst->pitch = pitch;
|
|
|
|
dst->table = (Pixel**) calloc((height + BUFFER * 2), sizeof(Pixel*));
|
|
|
|
ThrowIf(!dst->table, "Could not allocate picture table");
|
|
|
|
if (surface == NULL)
|
|
{
|
|
dst->pitch = pitch = width;
|
|
dst->surface = surface = (Pixel*) calloc(width * height, sizeof(Pixel));
|
|
}
|
|
ThrowIf(!surface, "Could not allocate picture surface");
|
|
|
|
dst->pixels = &dst->table[BUFFER];
|
|
|
|
for (i = 0; i < height; i++, surface += pitch)
|
|
{
|
|
dst->pixels[i] = surface;
|
|
}
|
|
|
|
for (i = 0; i < BUFFER; i++)
|
|
{
|
|
dst->pixels[i - BUFFER] = dst->pixels[0];
|
|
dst->pixels[i + height] = dst->pixels[height - 1];
|
|
}
|
|
}
|
|
/*******************************************************************************
|
|
** PictureDelete
|
|
*******************************************************************************/
|
|
void
|
|
PictureDelete(Picture* picture)
|
|
{
|
|
assert(picture);
|
|
|
|
if (picture->surface) free(picture->surface);
|
|
if (picture->table) free(picture->table);
|
|
}
|
|
/*******************************************************************************
|
|
** PictureClear
|
|
*******************************************************************************/
|
|
void
|
|
PictureClear(Picture* picture, Pixel pixel)
|
|
{
|
|
assert(picture);
|
|
|
|
for (int i = 0; i < picture->height; i++)
|
|
{
|
|
memset(picture->pixels[i], pixel, picture->width * sizeof(Pixel));
|
|
}
|
|
}
|
|
/*******************************************************************************
|
|
** PictureBlit
|
|
*******************************************************************************/
|
|
|
|
#define CHANNEL_BLITTER u = u1; w = x2 - x1; while (w--) {AFFINE;}
|
|
/*******************************************************************************
|
|
** PictureBlitRect
|
|
*******************************************************************************/
|
|
void
|
|
PictureBlitRect(Picture* dst, Rect r, Pixel pixel)
|
|
{
|
|
RectAND(&r, &dst->rect, &r);
|
|
|
|
if (RectIsVisible(&r))
|
|
{
|
|
for (;r.y1 < r.y2; r.y1++)
|
|
{
|
|
Pixel* p = &dst->pixels[r.y1][r.x1];
|
|
|
|
int w = r.x2 - r.x1; while (w--) *p++ = pixel;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define PICTURE_BLITTER \
|
|
for (;y1 < y2; y1++, v1 += vv) \
|
|
{ \
|
|
I = src->pixels[FIX_TO_INT(v1)]; \
|
|
O = &dst->pixels[y1][x1]; \
|
|
u = u1; \
|
|
w = x2 - x1; while (w--) {AFFINE;} \
|
|
}
|
|
|
|
/*******************************************************************************
|
|
** PictureCopy
|
|
*******************************************************************************/
|
|
void
|
|
PictureCopy(
|
|
int effect,
|
|
Picture* dst, int x1, int y1, int x2, int y2,
|
|
Picture* src, int u1, int v1, int u2, int v2,
|
|
Picture* zb, Pixel z, Pixel key)
|
|
{
|
|
int u, uu, v, vv, w, h;
|
|
Pixel* I;
|
|
Pixel* O;
|
|
Pixel* Z;
|
|
Pixel i;
|
|
Pixel pix;
|
|
|
|
if ((w = x2 - x1) <= 0 || (h = y2 - y1) <= 0) return;
|
|
|
|
u1 = INT_TO_FIX(u1); v1 = INT_TO_FIX(v1);
|
|
u2 = INT_TO_FIX(u2); v2 = INT_TO_FIX(v2);
|
|
|
|
uu = (u2 - u1) / w;
|
|
vv = (v2 - v1) / h;
|
|
|
|
if (x1 < 0 ) {u1 -= x1 * uu; x1 = 0;}
|
|
if (y1 < 0 ) {v1 -= y1 * vv; y1 = 0;}
|
|
if (x2 > dst->width ) {x2 = dst->width; }
|
|
if (y2 > dst->height) {y2 = dst->height; }
|
|
|
|
if ((w = x2 - x1) <= 0 || (h = y2 - y1) <= 0) return;
|
|
|
|
switch (effect)
|
|
{
|
|
case PICTURE_FILL:
|
|
{
|
|
for (;y1 < y2; y1++)
|
|
{
|
|
O = &dst->pixels[y1][x1];
|
|
|
|
w = x2 - x1;
|
|
while (w--) *O++ = dst->color;
|
|
}
|
|
break;
|
|
}
|
|
case PICTURE_COPY:
|
|
{
|
|
#undef AFFINE
|
|
#define AFFINE *O++ = I[FIX_TO_INT(u)]; u += uu;
|
|
|
|
if (uu == INT_TO_FIX(1))
|
|
{
|
|
for (;y1 < y2; y1++, v1 += vv)
|
|
{
|
|
memcpy(&dst->pixels[y1][x1], &src->pixels[FIX_TO_INT(v1)][FIX_TO_INT(u1)], w * sizeof(Pixel));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PICTURE_BLITTER
|
|
}
|
|
break;
|
|
}
|
|
case PICTURE_FX_OR:
|
|
{
|
|
for (;y1 < y2; y1++, v1 += vv)
|
|
{
|
|
I = src->pixels[FIX_TO_INT(v1)];
|
|
O = &dst->pixels[y1][x1];
|
|
Z = &zb->pixels[y1][x1];
|
|
|
|
#undef AFFINE
|
|
#define AFFINE \
|
|
if (z > *Z && I[FIX_TO_INT(u)] != key) \
|
|
{ \
|
|
pix = (I[FIX_TO_INT(u)] & 0x7BDE) + (*O & 0x7BDE); \
|
|
if (pix&0x0020) pix|=PIXEL_BLUE; \
|
|
if (pix&0x0400) pix|=PIXEL_GREEN; \
|
|
if (pix&0x8000) pix|=PIXEL_RED; \
|
|
*O = pix; \
|
|
} \
|
|
Z++; O++; u += uu;
|
|
|
|
//#undef AFFINE
|
|
//#define AFFINE *O += I[FIX_TO_INT(u)]; O++; u += uu;
|
|
|
|
CHANNEL_BLITTER;
|
|
}
|
|
break;
|
|
}
|
|
case PICTURE_BLEND:
|
|
{
|
|
#undef AFFINE
|
|
#define AFFINE *O = PIXEL_BLEND(I[FIX_TO_INT(u)], *O); O++; u += uu;
|
|
|
|
PICTURE_BLITTER
|
|
break;
|
|
}
|
|
case PICTURE_ADD:
|
|
{
|
|
#undef AFFINE
|
|
#define AFFINE \
|
|
pix = (unsigned)(*O & 0xF3DE) + (unsigned)(I[FIX_TO_INT(u)] & 0xF3DE); \
|
|
if (pix&0x0020) pix|=PIXEL_BLUE; \
|
|
if (pix&0x0400) pix|=PIXEL_GREEN; \
|
|
if (pix&0x10000) pix|=PIXEL_RED; \
|
|
*O = 0;/* | (*O & 0x8420);*/ \
|
|
O++; u += uu;
|
|
|
|
PICTURE_BLITTER
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*******************************************************************************
|
|
** PictureBlit
|
|
*******************************************************************************/
|
|
/*
|
|
void
|
|
PictureBlit(
|
|
Picture* dst, int x1, int y1, int x2, int y2,
|
|
Picture* src, int u1, int v1, int u2, int v2,
|
|
Pixel key,
|
|
Picture* zbuffer,
|
|
Pixel z)
|
|
{
|
|
int u, uu, v, vv, w, h;
|
|
Pixel* I;
|
|
Pixel* O;
|
|
Pixel* zb;
|
|
|
|
CHANNEL_CLIPPER
|
|
|
|
if (zbuffer)
|
|
{
|
|
if (key == PICTURE_NO_COLOUR_KEY)
|
|
{
|
|
for (;y1 < y2; y1++, v1 += vv)
|
|
{
|
|
I = src->pixels[FIX_TO_INT(v1)];
|
|
O = &dst->pixels[y1][x1];
|
|
zb = &zbuffer->pixels[y1][x1];
|
|
|
|
#undef AFFINE
|
|
#define AFFINE if (z < *zb) {*zb = z; *O = I[FIX_TO_INT(u)];} O++; zb++; u += uu;
|
|
|
|
CHANNEL_BLITTER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (;y1 < y2; y1++, v1 += vv)
|
|
{
|
|
I = src->pixels[FIX_TO_INT(v1)];
|
|
O = &dst->pixels[y1][x1];
|
|
zb = &zbuffer->pixels[y1][x1];
|
|
|
|
#undef AFFINE
|
|
#define AFFINE if (z < *zb && I[FIX_TO_INT(u)] != key) {*zb = z; *O = I[FIX_TO_INT(u)];} O++; zb++; u += uu;
|
|
|
|
CHANNEL_BLITTER;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (key == PICTURE_NO_COLOUR_KEY)
|
|
{
|
|
if (uu == INT_TO_FIX(1))
|
|
{
|
|
for (;y1 < y2; y1++, v1 += vv)
|
|
{
|
|
memcpy(&dst->pixels[y1][x1], &src->pixels[FIX_TO_INT(v1)][FIX_TO_INT(u1)], w * sizeof(Pixel));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (;y1 < y2; y1++, v1 += vv)
|
|
{
|
|
I = src->pixels[FIX_TO_INT(v1)];
|
|
O = &dst->pixels[y1][x1];
|
|
|
|
#undef AFFINE
|
|
#define AFFINE *O = I[FIX_TO_INT(u)]; O++; u += uu;
|
|
|
|
CHANNEL_BLITTER;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (;y1 < y2; y1++, v1 += vv)
|
|
{
|
|
I = src->pixels[FIX_TO_INT(v1)];
|
|
O = &dst->pixels[y1][x1];
|
|
|
|
#undef AFFINE
|
|
#define AFFINE if (I[FIX_TO_INT(u)] != key) *O = I[FIX_TO_INT(u)]; O++; u += uu;
|
|
|
|
CHANNEL_BLITTER;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
/*******************************************************************************
|
|
** PictureBlitSprite
|
|
*******************************************************************************/
|
|
/*
|
|
void
|
|
PictureBlitSprite(Picture* dst, Picture* src, int x, int y)
|
|
{
|
|
PictureBlit(
|
|
dst, x, y, x + src->width, y + src->height,
|
|
src, 0, 0, src->width, src->height,
|
|
src->pixels[0][0], 0, 0);
|
|
}
|
|
*/
|
|
/*******************************************************************************
|
|
** PictureRead
|
|
*******************************************************************************/
|
|
void
|
|
PictureRead(Picture* picture, FILE* file)
|
|
{
|
|
int w = IntRead(file);
|
|
int h = IntRead(file);
|
|
|
|
PictureCreate(picture, w, h);
|
|
|
|
for (int i = 0; i < picture->height; i++)
|
|
{
|
|
fread(picture->pixels[i], sizeof(Pixel), picture->width, file);
|
|
}
|
|
}
|
|
/*******************************************************************************
|
|
** PictureWrite
|
|
*******************************************************************************/
|
|
void
|
|
PictureWrite(Picture* picture, FILE* file)
|
|
{
|
|
fwrite(&picture->width , sizeof(int), 1, file);
|
|
fwrite(&picture->height, sizeof(int), 1, file);
|
|
|
|
for (int i = 0; i < picture->height; i++)
|
|
{
|
|
fwrite(picture->pixels[i], sizeof(Pixel), picture->width, file);
|
|
}
|
|
}
|
|
/*******************************************************************************
|
|
** PictureLoad
|
|
*******************************************************************************/
|
|
void
|
|
PictureLoad(Picture* dst, char* name)
|
|
{
|
|
FILE* file = fopen(name, "rb");
|
|
|
|
ThrowIf(!file, "Could not open picture file");
|
|
|
|
PictureRead(dst, file);
|
|
|
|
fclose(file);
|
|
}
|
|
/*******************************************************************************
|
|
** PictureSave
|
|
*******************************************************************************/
|
|
void
|
|
PictureSave(Picture* dst, char* name)
|
|
{
|
|
FILE* file = fopen(name, "wb");
|
|
|
|
ThrowIf(!file, "Could not open picture file");
|
|
|
|
PictureWrite(dst, file);
|
|
|
|
fclose(file);
|
|
}
|
|
/*******************************************************************************
|
|
** PictureArrayCreate
|
|
*******************************************************************************/
|
|
Picture*
|
|
PictureArrayCreate(int size)
|
|
{
|
|
Picture* array = (Picture*) MemoryAlloc(size, sizeof(Picture));
|
|
|
|
return array;
|
|
}
|
|
/*******************************************************************************
|
|
** PictureArrayDelete
|
|
*******************************************************************************/
|
|
void
|
|
PictureArrayDelete(Picture* pictures)
|
|
{
|
|
for (int i = 0; i < NumberOf(pictures); i++)
|
|
{
|
|
PictureDelete(&pictures[i]);
|
|
}
|
|
MemoryFree(pictures);
|
|
}
|
|
/*******************************************************************************
|
|
** PictureArrayRead
|
|
*******************************************************************************/
|
|
Picture*
|
|
PictureArrayRead(FILE* file)
|
|
{
|
|
Picture* pictures = PictureArrayCreate(IntRead(file));
|
|
|
|
for (int i = 0; i < NumberOf(pictures); i++)
|
|
{
|
|
PictureRead(&pictures[i], file);
|
|
}
|
|
|
|
return pictures;
|
|
}
|
|
/*******************************************************************************
|
|
** PictureArrayWrite
|
|
*******************************************************************************/
|
|
void
|
|
PictureArrayWrite(Picture* pictures, FILE* file)
|
|
{
|
|
IntWrite(NumberOf(pictures), file);
|
|
|
|
for (int i = 0; i < NumberOf(pictures); i++)
|
|
{
|
|
PictureWrite(&pictures[i], file);
|
|
}
|
|
}
|
|
|
|
|
|
|