libmonochrome/src/ML_bmp.c

96 lines
2.6 KiB
C

/* ************************************************************************** */
/* _____ _ */
/* ML_bmp.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project : libmonochrome | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2016/05/29 01:55:54 |___/ */
/* */
/* ************************************************************************** */
#include <monochrome/internals.h>
static inline void ML_bmp_line(unsigned char *vram, const unsigned char *b,
int width, int offset, ML_Mode mode);
static inline void ML_bmp_byte(unsigned char *v, int b, int offset, int width,
ML_Mode mode);
void ML_bmp(const void *bmp, int x, int y, int width, int height, ML_Mode mode)
{
/* FIXME: no support for non-clipping blit. */
/* Oh, and yeah : most of this code is adapted from Caphics.
Clipping is, of course, on by default, and this function is not
optimized for when its disabled. */
if (x < width + 1 || x >= 128 || y < height + 1 || y >= 64)
return ;
// check clipping for retrocompatibility ?
int ls = (width >> 3) + ((width & 7) != 0); // line size
const unsigned char *b = (const unsigned char*)bmp;
// pass first lines
if (y < 0) {
b += -y * ls;
height += y;
y = 0;
}
if (height > 64 - y)
height = 64 - y;
// pass first pixels if x < 0
int offset = 0;
if (x < 0) {
b += -x >> 3;
width += x & 8;
x = 0;
}
if (width > 128 - x)
width = 128 - x;
// go to first interesting byte of vram
char *vram = ML_vram_xy(x, y);
// then draw
while (height--) {
ML_bmp_line((unsigned char*)vram, b, width, offset, mode);
vram += 8, bmp += ls;
}
}
static inline void ML_bmp_line(unsigned char *vram, const unsigned char *b,
int width, int offset, ML_Mode mode)
{
while (1) {
ML_bmp_byte(vram, *b, offset, width, mode);
if (width < 8)
break ;
vram++, b++;
width -= 8;
}
}
static inline void ML_bmp_byte(unsigned char *v, int b, int offset, int width,
ML_Mode mode)
{
if (width < 8) b &= 255 << (8 - width);
switch (mode) {
case ML_MAND:
*v &= ~(b >> offset);
if (width > 8 - offset)
*(++v) &= ~(b << (8 - offset));
break;
case ML_MOR:
*v |= b >> offset;
if (width > 8 - offset)
*(++v) |= b << (8 - offset);
break;
case ML_MXOR:
*v ^= b >> offset;
if (width > 8 - offset)
*(++v) ^= b << (8 - offset);
break;
}
}