aboutsummaryrefslogtreecommitdiff
path: root/externals/gridflow/base/bitpacking.c
diff options
context:
space:
mode:
authorN.N. <matju@users.sourceforge.net>2005-10-04 02:02:15 +0000
committerN.N. <matju@users.sourceforge.net>2005-10-04 02:02:15 +0000
commit5e2a1bc9e56003349e533f7e5841041ba5c04e28 (patch)
treead040f6894d9383b732423a74420e732f62a66a5 /externals/gridflow/base/bitpacking.c
parent520a243c297175386ab31c78c84693a664934a69 (diff)
starting to commit gridflow 0.8.0 ...
if you know how to use "cvs import" please mail me and i'll use it for 0.8.1 svn path=/trunk/; revision=3646
Diffstat (limited to 'externals/gridflow/base/bitpacking.c')
-rw-r--r--externals/gridflow/base/bitpacking.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/externals/gridflow/base/bitpacking.c b/externals/gridflow/base/bitpacking.c
new file mode 100644
index 00000000..143f6edb
--- /dev/null
+++ b/externals/gridflow/base/bitpacking.c
@@ -0,0 +1,309 @@
+/*
+ $Id: bitpacking.c,v 1.1 2005-10-04 02:02:13 matju Exp $
+
+ GridFlow
+ Copyright (c) 2001,2002,2003,2004 by Mathieu Bouchard
+
+ 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.
+
+ See file ../COPYING for further informations on licensing terms.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "grid.h.fcs"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define CONVERT1 t = \
+ (((in[0] << hb[0]) >> 7) & mask[0]) | \
+ (((in[1] << hb[1]) >> 7) & mask[1]) | \
+ (((in[2] << hb[2]) >> 7) & mask[2])
+
+#define CONVERT2 \
+ for (t=0,i=0; i<self->size; i++) t |= (((in[i] << hb[i]) >> 7) & mask[i]);
+
+#define CONVERT3 \
+ for (t=0,i=0; i<self->size; i++) { \
+ t |= ((in[i]>>(7-hb[i]))|(in[i]<<(hb[i]-7))) & mask[i]; \
+ }
+
+#define WRITE_LE \
+ for (int bytes = self->bytes; bytes; bytes--, t>>=8) *out++ = t;
+
+#define WRITE_BE { int bytes; \
+ bytes = self->bytes; \
+ while (bytes--) { out[bytes] = t; t>>=8; }\
+ out += self->bytes; }
+
+/* this macro would be faster if the _increment_
+ was done only once every loop. or maybe gcc does it, i dunno */
+#define NTIMES(_x_) \
+ for (; n>=4; n-=4) { _x_ _x_ _x_ _x_ } \
+ for (; n; n--) { _x_ }
+
+/* this could be faster (use asm) */
+void swap32 (int n, Pt<uint32> data) {
+ NTIMES({
+ uint32 x = *data;
+ x = (x<<16) | (x>>16);
+ x = ((x&0xff00ff)<<8) | ((x>>8)&0xff00ff);
+ *data++ = x;
+ })
+}
+
+/* this could be faster (use asm or do it in int32 chunks) */
+void swap16 (int n, Pt<uint16> data) {
+ NTIMES({ uint16 x = *data; *data++ = (x<<8) | (x>>8); })
+}
+
+/* **************************************************************** */
+
+template <class T>
+static void default_pack(BitPacking *self, int n, Pt<T> in, Pt<uint8> out) {
+ uint32 t;
+ int i;
+ int hb[4];
+ uint32 mask[4];
+ int sameorder = self->endian==2 || self->endian==::is_le();
+ int size = self->size;
+
+ for (i=0; i<self->size; i++) hb[i] = highest_bit(self->mask[i]);
+ memcpy(mask,self->mask,size*sizeof(uint32));
+
+ if (sameorder && size==3) {
+ switch(self->bytes) {
+ case 2: NTIMES(t=CONVERT1; *((int16 *)out)=t; out+=2; in+=3;) return;
+ case 4: NTIMES(t=CONVERT1; *((int32 *)out)=t; out+=4; in+=3;) return;
+ }
+ }
+ if (self->is_le()) {
+ switch (size) {
+ case 3: for (; n--; in+=3) {CONVERT1; WRITE_LE;} break;
+ case 4: for (; n--; in+=4) {CONVERT3; WRITE_LE;} break;
+ default:for (; n--; in+=size) {CONVERT2; WRITE_LE;}}
+ } else {
+ switch (size) {
+ case 3: for (; n--; in+=3) {CONVERT1; WRITE_BE;} break;
+ case 4: for (; n--; in+=4) {CONVERT3; WRITE_BE;} break;
+ default:for (; n--; in+=size) {CONVERT2; WRITE_BE;}}
+ }
+}
+
+#define LOOP_UNPACK(_reader_) \
+ for (; n; n--) { \
+ int bytes=0; uint32 temp=0; _reader_; \
+ for (int i=0; i<self->size; i++, out++) { \
+ uint32 t=temp&self->mask[i]; \
+ *out = (t<<(7-hb[i]))|(t>>(hb[i]-7)); \
+ } \
+ }
+// *out++ = ((temp & self->mask[i]) << 7) >> hb[i];
+
+template <class T>
+static void default_unpack(BitPacking *self, int n, Pt<uint8> in, Pt<T> out) {
+ int hb[4];
+ for (int i=0; i<self->size; i++) hb[i] = highest_bit(self->mask[i]);
+ if (is_le()) { // smallest byte first
+ LOOP_UNPACK(
+ for(; self->bytes>bytes; bytes++, in++) temp |= *in<<(8*bytes);
+ )
+ } else { // biggest byte first
+ LOOP_UNPACK(
+ bytes=self->bytes; for (; bytes; bytes--, in++) temp=(temp<<8)|*in;
+ )
+ }
+}
+
+/* **************************************************************** */
+
+template <class T>
+static void pack2_565(BitPacking *self, int n, Pt<T> in, Pt<uint8> out) {
+ const int hb[3] = {15,10,4};
+ const uint32 mask[3] = {0x0000f800,0x000007e0,0x0000001f};
+ uint32 t;
+ NTIMES( t=CONVERT1; *((short *)out)=t; out+=2; in+=3; )
+}
+
+template <class T>
+static void pack3_888(BitPacking *self, int n, Pt<T> in, Pt<uint8> out) {
+ Pt<int32> o32 = (Pt<int32>)out;
+ while (n>=4) {
+ o32[0] = (in[5]<<24) | (in[ 0]<<16) | (in[ 1]<<8) | in[2];
+ o32[1] = (in[7]<<24) | (in[ 8]<<16) | (in[ 3]<<8) | in[4];
+ o32[2] = (in[9]<<24) | (in[10]<<16) | (in[11]<<8) | in[6];
+ o32+=3; in+=12;
+ n-=4;
+ }
+ out = (Pt<uint8>)o32;
+ NTIMES( out[2]=in[0]; out[1]=in[1]; out[0]=in[2]; out+=3; in+=3; )
+}
+
+/*
+template <>
+static void pack3_888(BitPacking *self, int n, Pt<uint8> in, Pt<uint8> out) {
+ Pt<uint32> o32 = Pt<uint32>((uint32 *)out.p,n*3/4);
+ Pt<uint32> i32 = Pt<uint32>((uint32 *)in.p,n*3/4);
+ while (n>=4) {
+#define Z(w,i) ((word##w>>(i*8))&255)
+ uint32 word0 = i32[0];
+ uint32 word1 = i32[1];
+ uint32 word2 = i32[2];
+ o32[0] = (Z(1,1)<<24) | (Z(0,0)<<16) | (Z(0,1)<<8) | Z(0,2);
+ o32[1] = (Z(1,3)<<24) | (Z(2,0)<<16) | (Z(0,3)<<8) | Z(1,0);
+ o32[2] = (Z(2,1)<<24) | (Z(2,2)<<16) | (Z(2,3)<<8) | Z(1,2);
+ o32+=3; i32+=3;
+ n-=4;
+ }
+#undef Z
+ out = (Pt<uint8>)o32;
+ in = (Pt<uint8>)i32;
+ NTIMES( out[2]=in[0]; out[1]=in[1]; out[0]=in[2]; out+=3; in+=3; )
+}
+*/
+
+template <class T>
+static void pack3_888b(BitPacking *self, int n, Pt<T> in, Pt<uint8> out) {
+ Pt<int32> o32 = (Pt<int32>)out;
+ while (n>=4) {
+ o32[0] = (in[0]<<16) | (in[1]<<8) | in[2];
+ o32[1] = (in[3]<<16) | (in[4]<<8) | in[5];
+ o32[2] = (in[6]<<16) | (in[7]<<8) | in[8];
+ o32[3] = (in[9]<<16) | (in[10]<<8) | in[11];
+ o32+=4; in+=12;
+ n-=4;
+ }
+ NTIMES( o32[0] = (in[0]<<16) | (in[1]<<8) | in[2]; o32++; in+=3; )
+}
+
+/* (R,G,B,?) -> B:8,G:8,R:8,0:8 */
+template <class T>
+static void pack3_bgrn8888(BitPacking *self, int n, Pt<T> in, Pt<uint8> out) {
+/* NTIMES( out[2]=in[0]; out[1]=in[1]; out[0]=in[2]; out+=4; in+=4; ) */
+ Pt<int32> i32 = (Pt<int32>)in;
+ Pt<int32> o32 = (Pt<int32>)out;
+ while (n>=4) {
+ o32[0] = ((i32[0]&0xff)<<16) | (i32[0]&0xff00) | ((i32[0]>>16)&0xff);
+ o32[1] = ((i32[1]&0xff)<<16) | (i32[1]&0xff00) | ((i32[1]>>16)&0xff);
+ o32[2] = ((i32[2]&0xff)<<16) | (i32[2]&0xff00) | ((i32[2]>>16)&0xff);
+ o32[3] = ((i32[3]&0xff)<<16) | (i32[3]&0xff00) | ((i32[3]>>16)&0xff);
+ o32+=4; i32+=4; n-=4;
+ }
+ NTIMES( o32[0] = ((i32[0]&0xff)<<16) | (i32[0]&0xff00) | ((i32[0]>>16)&0xff); o32++; i32++; )
+}
+
+static uint32 bp_masks[][4] = {
+ {0x0000f800,0x000007e0,0x0000001f,0},
+ {0x00ff0000,0x0000ff00,0x000000ff,0},
+};
+
+static Packer bp_packers[] = {
+ {default_pack, default_pack, default_pack},
+ {pack2_565, pack2_565, pack2_565},
+ {pack3_888, pack3_888, pack3_888},
+ {pack3_888b, default_pack, default_pack},
+ {pack3_bgrn8888, default_pack, default_pack},
+};
+
+static Unpacker bp_unpackers[] = {
+ {default_unpack, default_unpack, default_unpack},
+};
+
+static BitPacking builtin_bitpackers[] = {
+ BitPacking(2, 2, 3, bp_masks[0], &bp_packers[1], &bp_unpackers[0]),
+ BitPacking(1, 3, 3, bp_masks[1], &bp_packers[2], &bp_unpackers[0]),
+ BitPacking(1, 4, 3, bp_masks[1], &bp_packers[3], &bp_unpackers[0]),
+ BitPacking(1, 4, 4, bp_masks[1], &bp_packers[4], &bp_unpackers[0]),
+};
+
+/* **************************************************************** */
+
+bool BitPacking::eq(BitPacking *o) {
+ if (!(bytes == o->bytes)) return false;
+ if (!(size == o->size)) return false;
+ for (int i=0; i<size; i++) {
+ if (!(mask[i] == o->mask[i])) return false;
+ }
+ if (endian==o->endian) return true;
+ /* same==little on a little-endian; same==big on a big-endian */
+ return (endian ^ o->endian ^ ::is_le()) == 2;
+}
+
+BitPacking::BitPacking(int endian, int bytes, int size, uint32 *mask,
+Packer *packer, Unpacker *unpacker) {
+ this->endian = endian;
+ this->bytes = bytes;
+ this->size = size;
+ for (int i=0; i<size; i++) this->mask[i] = mask[i];
+ if (packer) {
+ this->packer = packer;
+ this->unpacker = unpacker;
+ return;
+ }
+ int packeri=-1;
+ this->packer = &bp_packers[0];
+ this->unpacker = &bp_unpackers[0];
+
+ for (int i=0; i<(int)(sizeof(builtin_bitpackers)/sizeof(BitPacking)); i++) {
+ BitPacking *bp = &builtin_bitpackers[i];
+ if (this->eq(bp)) {
+ this->packer = bp->packer;
+ this->unpacker = bp->unpacker;
+ packeri=i;
+ goto end;
+ }
+ }
+end:;
+/*
+ ::gfpost("Bitpacking: endian=%d bytes=%d size=%d packeri=%d",
+ endian, bytes, size, packeri);
+ ::gfpost(" packer=0x%08x unpacker=0x%08x",this->packer,this->unpacker);
+ ::gfpost(" mask=[0x%08x,0x%08x,0x%08x,0x%08x]",mask[0],mask[1],mask[2],mask[3]);
+*/
+}
+
+bool BitPacking::is_le() {
+ return endian==1 || (endian ^ ::is_le())==3;
+}
+
+template <class T>
+void BitPacking::pack(int n, Pt<T> in, Pt<uint8> out) {
+ switch (NumberTypeE_type_of(*in)) {
+ case uint8_e: packer->as_uint8(this,n,(Pt<uint8>)in,out); break;
+ case int16_e: packer->as_int16(this,n,(Pt<int16>)in,out); break;
+ case int32_e: packer->as_int32(this,n,(Pt<int32>)in,out); break;
+ default: RAISE("argh");
+ }
+}
+
+template <class T>
+void BitPacking::unpack(int n, Pt<uint8> in, Pt<T> out) {
+ switch (NumberTypeE_type_of(*out)) {
+ case uint8_e: unpacker->as_uint8(this,n,in,(Pt<uint8>)out); break;
+ case int16_e: unpacker->as_int16(this,n,in,(Pt<int16>)out); break;
+ case int32_e: unpacker->as_int32(this,n,in,(Pt<int32>)out); break;
+ default: RAISE("argh");
+ }
+}
+
+// i'm sorry... see the end of grid.c for an explanation...
+//static
+void make_hocus_pocus () {
+// exit(1);
+#define FOO(S) \
+ ((BitPacking*)0)->pack(0,Pt<S>(),Pt<uint8>()); \
+ ((BitPacking*)0)->unpack(0,Pt<uint8>(),Pt<S>());
+EACH_NUMBER_TYPE(FOO)
+#undef FOO
+}