X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fdraw%2Fao_blt.c;fp=src%2Fdraw%2Fao_blt.c;h=2060f00756c6a5adde1f919b6179b92ae909e475;hb=e6518cf1ddfc087ca25fa1494f993ce03e43e138;hp=0000000000000000000000000000000000000000;hpb=86f1c4b04946956f40755286bd9554828d5c8728;p=fw%2Faltos diff --git a/src/draw/ao_blt.c b/src/draw/ao_blt.c new file mode 100644 index 00000000..2060f007 --- /dev/null +++ b/src/draw/ao_blt.c @@ -0,0 +1,293 @@ +/* + * Copyright © 2016 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" + +#define O 0 +#define I AO_ALLONES + +struct ao_merge_rop { + uint32_t ca1, cx1, ca2, cx2; +}; + +const struct ao_merge_rop ao_merge_rop[16] = { + {O, O, O, O}, /* clear 0x0 0 */ + {I, O, O, O}, /* and 0x1 src AND dst */ + {I, O, I, O}, /* andReverse 0x2 src AND NOT dst */ + {O, O, I, O}, /* copy 0x3 src */ + {I, I, O, O}, /* andInverted 0x4 NOT src AND dst */ + {O, I, O, O}, /* noop 0x5 dst */ + {O, I, I, O}, /* xor 0x6 src XOR dst */ + {I, I, I, O}, /* or 0x7 src OR dst */ + {I, I, I, I}, /* nor 0x8 NOT src AND NOT dst */ + {O, I, I, I}, /* equiv 0x9 NOT src XOR dst */ + {O, I, O, I}, /* invert 0xa NOT dst */ + {I, I, O, I}, /* orReverse 0xb src OR NOT dst */ + {O, O, I, I}, /* copyInverted 0xc NOT src */ + {I, O, I, I}, /* orInverted 0xd NOT src OR dst */ + {I, O, O, I}, /* nand 0xe NOT src OR NOT dst */ + {O, O, O, I}, /* set 0xf 1 */ +}; + +#define ao_do_merge_rop(src, dst) \ + (((dst) & (((src) & _ca1) ^ _cx1)) ^ (((src) & _ca2) ^ _cx2)) + +#define ao_do_dst_invarient_merge_rop(src) (((src) & _ca2) ^ _cx2) + +#define ao_do_mask_merge_rop(src, dst, mask) \ + (((dst) & ((((src) & _ca1) ^ _cx1) | ~(mask))) ^ ((((src) & _ca2) ^ _cx2) & (mask))) + +#define ao_dst_invarient_merge_rop() (_ca1 == 0 && _cx1 == 0) + +void +ao_blt(uint32_t *src_line, + int16_t src_stride, + int16_t src_x, + uint32_t *dst_line, + int16_t dst_stride, + int16_t dst_x, + int16_t width, + int16_t height, + uint8_t rop, + uint8_t reverse, + uint8_t upsidedown) +{ + uint32_t *src, *dst; + uint32_t _ca1, _cx1, _ca2, _cx2; + uint8_t dst_invarient; + uint32_t startmask, endmask; + int16_t nmiddle, n; + uint32_t bits1, bits; + int16_t left_shift, right_shift; + + _ca1 = ao_merge_rop[rop].ca1; + _cx1 = ao_merge_rop[rop].cx1; + _ca2 = ao_merge_rop[rop].ca2; + _cx2 = ao_merge_rop[rop].cx2; + dst_invarient = ao_dst_invarient_merge_rop(); + + if (upsidedown) { + src_line += (height - 1) * src_stride; + dst_line += (height - 1) * dst_stride; + src_stride = -src_stride; + dst_stride = -dst_stride; + } + + ao_mask_bits(dst_x, width, startmask, nmiddle, endmask); + if (reverse) { + src_line += ((src_x + width - 1) >> AO_SHIFT) + 1; + dst_line += ((dst_x + width - 1) >> AO_SHIFT) + 1; + src_x = (src_x + width - 1) & AO_MASK; + dst_x = (dst_x + width - 1) & AO_MASK; + } else { + src_line += src_x >> AO_SHIFT; + dst_line += dst_x >> AO_SHIFT; + src_x &= AO_MASK; + dst_x &= AO_MASK; + } + if (src_x == dst_x) { + while (height--) { + src = src_line; + src_line += src_stride; + dst = dst_line; + dst_line += dst_stride; + if (reverse) { + if (endmask) { + bits = *--src; + --dst; + *dst = ao_do_mask_merge_rop(bits, *dst, endmask); + } + n = nmiddle; + if (dst_invarient) { + while (n--) + *--dst = ao_do_dst_invarient_merge_rop(*--src); + } + else { + while (n--) { + bits = *--src; + --dst; + *dst = ao_do_merge_rop(bits, *dst); + } + } + if (startmask) { + bits = *--src; + --dst; + *dst = ao_do_mask_merge_rop(bits, *dst, startmask); + } + } + else { + if (startmask) { + bits = *src++; + *dst = ao_do_mask_merge_rop(bits, *dst, startmask); + dst++; + } + n = nmiddle; + if (dst_invarient) { + while (n--) + *dst++ = ao_do_dst_invarient_merge_rop(*src++); + } + else { + while (n--) { + bits = *src++; + *dst = ao_do_merge_rop(bits, *dst); + dst++; + } + } + if (endmask) { + bits = *src; + *dst = ao_do_mask_merge_rop(bits, *dst, endmask); + } + } + } + } else { + if (src_x > dst_x) { + left_shift = src_x - dst_x; + right_shift = AO_UNIT - left_shift; + } else { + right_shift = dst_x - src_x; + left_shift = AO_UNIT - right_shift; + } + while (height--) { + src = src_line; + src_line += src_stride; + dst = dst_line; + dst_line += dst_stride; + + bits1 = 0; + if (reverse) { + if (src_x < dst_x) + bits1 = *--src; + if (endmask) { + bits = ao_right(bits1, right_shift); + if (ao_right(endmask, left_shift)) { + bits1 = *--src; + bits |= ao_left(bits1, left_shift); + } + --dst; + *dst = ao_do_mask_merge_rop(bits, *dst, endmask); + } + n = nmiddle; + if (dst_invarient) { + while (n--) { + bits = ao_right(bits1, right_shift); + bits1 = *--src; + bits |= ao_left(bits1, left_shift); + --dst; + *dst = ao_do_dst_invarient_merge_rop(bits); + } + } else { + while (n--) { + bits = ao_right(bits1, right_shift); + bits1 = *--src; + bits |= ao_left(bits1, left_shift); + --dst; + *dst = ao_do_merge_rop(bits, *dst); + } + } + if (startmask) { + bits = ao_right(bits1, right_shift); + if (ao_right(startmask, left_shift)) { + bits1 = *--src; + bits |= ao_left(bits1, left_shift); + } + --dst; + *dst = ao_do_mask_merge_rop(bits, *dst, startmask); + } + } + else { + if (src_x > dst_x) + bits1 = *src++; + if (startmask) { + bits = ao_left(bits1, left_shift); + if (ao_left(startmask, right_shift)) { + bits1 = *src++; + bits |= ao_right(bits1, right_shift); + } + *dst = ao_do_mask_merge_rop(bits, *dst, startmask); + dst++; + } + n = nmiddle; + if (dst_invarient) { + while (n--) { + bits = ao_left(bits1, left_shift); + bits1 = *src++; + bits |= ao_right(bits1, right_shift); + *dst = ao_do_dst_invarient_merge_rop(bits); + dst++; + } + } + else { + while (n--) { + bits = ao_left(bits1, left_shift); + bits1 = *src++; + bits |= ao_right(bits1, right_shift); + *dst = ao_do_merge_rop(bits, *dst); + dst++; + } + } + if (endmask) { + bits = ao_left(bits1, left_shift); + if (ao_left(endmask, right_shift)) { + bits1 = *src; + bits |= ao_right(bits1, right_shift); + } + *dst = ao_do_mask_merge_rop(bits, *dst, endmask); + } + } + } + } +} + +void +ao_solid(uint32_t and, + uint32_t xor, + uint32_t *dst, + int16_t dst_stride, + int16_t dst_x, + int16_t width, + int16_t height) +{ + uint32_t startmask, endmask; + int16_t nmiddle; + int16_t n; + + dst += dst_x >> AO_SHIFT; + dst_x &= AO_MASK; + + ao_mask_bits(dst_x, width, startmask, nmiddle, endmask); + + if (startmask) + dst_stride--; + + dst_stride -= nmiddle; + while (height--) { + if (startmask) { + *dst = ao_do_mask_rrop(*dst, and, xor, startmask); + dst++; + } + n = nmiddle; + if (!and) + while (n--) + *dst++ = xor; + else + while (n--) { + *dst = ao_do_rrop(*dst, and, xor); + dst++; + } + if (endmask) + *dst = ao_do_mask_rrop(*dst, and, xor, endmask); + dst += dst_stride; + } +}