room101/PICTURE.CPP

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);
}
}