irrlicht/source/Irrlicht/CMY3DHelper.h

446 lines
14 KiB
C++

// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
//
// This file was originally written by ZDimitor.
//----------------------------------------------------------------------
// somefuncs.h - part of the My3D Tools
//
// This tool was created by Zhuck Dmitry (ZDimitor).
// Everyone can use it as wants ( i'll be happy if it helps to someone :) ).
//----------------------------------------------------------------------
//**********************************************************************
// some useful functions
//**********************************************************************
#ifndef __C_MY3D_HELPER_H_INCLUDED__
#define __C_MY3D_HELPER_H_INCLUDED__
#include "irrTypes.h"
namespace irr
{
namespace scene
{
//**********************************************************************
// MY3D stuff
//**********************************************************************
// byte-align structures
#include "irrpack.h"
struct SMyVector3
{ SMyVector3 () {;}
SMyVector3 (f32 __X, f32 __Y, f32 __Z)
: X(__X), Y(__Y), Z(__Z) {}
f32 X, Y, Z;
} PACK_STRUCT;
struct SMyVector2
{ SMyVector2 () {;}
SMyVector2(f32 __X, f32 __Y)
: X(__X), Y(__Y) {}
f32 X, Y;
} PACK_STRUCT;
struct SMyVertex
{ SMyVertex () {;}
SMyVertex (SMyVector3 _Coord, SMyColor _Color, SMyVector3 _Normal)
:Coord(_Coord), Color(_Color), Normal(_Normal) {;}
SMyVector3 Coord;
SMyColor Color;
SMyVector3 Normal;
} PACK_STRUCT;
struct SMyTVertex
{ SMyTVertex () {;}
SMyTVertex (SMyVector2 _TCoord)
: TCoord(_TCoord) {;}
SMyVector2 TCoord;
} PACK_STRUCT;
struct SMyFace
{ SMyFace() {;}
SMyFace(u32 __A, u32 __B, u32 __C)
: A(__A), B(__B), C(__C) {}
u32 A, B, C;
} PACK_STRUCT;
// file header (6 bytes)
struct SMyFileHeader
{ u32 MyId; // MY3D
u16 Ver; // Version
} PACK_STRUCT;
// scene header
struct SMySceneHeader
{ SMyColor BackgrColor; // background color
SMyColor AmbientColor; // ambient color
s32 MaterialCount; // material count
s32 MeshCount; // mesh count
} PACK_STRUCT;
// mesh header
struct SMyMeshHeader
{ c8 Name[256]; // material name
u32 MatIndex; // index of the mesh material
u32 TChannelCnt; // mesh mapping channels count
} PACK_STRUCT;
// texture data header
struct SMyTexDataHeader
{ c8 Name[256]; // texture name
u32 ComprMode; //compression mode
u32 PixelFormat;
u32 Width; // image width
u32 Height; // image height
} PACK_STRUCT;
// pixel color 24bit (R8G8B8)
struct SMyPixelColor24
{ SMyPixelColor24() {;}
SMyPixelColor24(u8 __r, u8 __g, u8 __b)
: r(__r), g(__g), b(__b) {}
u8 r, g, b;
} PACK_STRUCT;
// pixel color 16bit (A1R5G5B5)
struct SMyPixelColor16
{ SMyPixelColor16() {;}
SMyPixelColor16(s16 _argb): argb(_argb) {;}
SMyPixelColor16(u8 r, u8 g, u8 b)
{ argb = ((r&0x1F)<<10) | ((g&0x1F)<<5) | (b&0x1F);
}
s16 argb;
} PACK_STRUCT;
// RLE Header
struct SMyRLEHeader
{ SMyRLEHeader() {}
u32 nEncodedBytes;
u32 nDecodedBytes;
} PACK_STRUCT;
// Default alignment
#include "irrunpack.h"
} // end namespace
} // end namespace
//-----------------------------------------------------------------------------
namespace irr
{
namespace core
{
//-----------------RLE stuff-----------------------------------------
int rle_encode (
unsigned char *in_buf, int in_buf_size,
unsigned char *out_buf, int out_buf_size
);
unsigned long process_comp(
unsigned char *buf, int buf_size,
unsigned char *out_buf, int out_buf_size
);
void process_uncomp(
unsigned char, unsigned char *out_buf, int out_buf_size
);
void flush_outbuf(
unsigned char *out_buf, int out_buf_size
);
unsigned long get_byte (
unsigned char *ch,
unsigned char *in_buf, int in_buf_size,
unsigned char *out_buf, int out_buf_size
);
void put_byte(
unsigned char ch, unsigned char *out_buf, int out_buf_size
);
//-----------------------------------------------------------
const unsigned long LIMIT = 1; // was #define LIMIT 1
const unsigned long NON_MATCH = 2; // was: #define NON_MATCH 2
const unsigned long EOD_FOUND = 3; // was: #define EOD_FOUND 3
const unsigned long EOD = 0x00454f44; // was: #define EOD 'EOD'
//-----------------------------------------------------------
// number of decoded bytes
static int nDecodedBytes=0;
// number of coded bytes
static int nCodedBytes=0;
// number of read bytes
static int nReadedBytes=0;
// table used to look for sequences of repeating bytes
static unsigned char tmpbuf[4]; // we use subscripts 1 - 3
static int tmpbuf_cnt;
// output buffer for non-compressed output data
static unsigned char outbuf[128];
static int outbuf_cnt;
//-----------------------------------------------------------
int rle_encode (
unsigned char *in_buf, int in_buf_size,
unsigned char *out_buf, int out_buf_size
)
{
unsigned long ret_code;
unsigned char ch=0;
nCodedBytes=0;
nReadedBytes=0;
tmpbuf_cnt = 0; // no. of char's in tmpbuf
outbuf_cnt = 0; // no. of char's in outbuf
while (1)
{
if (get_byte(&ch, in_buf, in_buf_size,
out_buf, out_buf_size) == (int)EOD) // read next byte into ch
break;
tmpbuf[++tmpbuf_cnt] = (unsigned char) ch;
if (tmpbuf_cnt == 3)
{
// see if all 3 match each other
if ((tmpbuf[1] == tmpbuf[2]) && (tmpbuf[2] == tmpbuf[3]))
{
// they do - add compression
// this will process all bytes in input file until
// a non-match occurs, or 128 bytes are processed,
// or we find eod */
ret_code = process_comp(in_buf, in_buf_size, out_buf, out_buf_size);
if (ret_code == (int)EOD_FOUND)
break; // stop compressing
if (ret_code == (int)NON_MATCH)
tmpbuf_cnt=1; /* save the char that didn't match */
else
// we just compressed the max. of 128 bytes
tmpbuf_cnt=0; /* start over for next chunk */
}
else
{
// we know the first byte doesn't match 2 or more
// others, so just send it out as uncompressed. */
process_uncomp(tmpbuf[1], out_buf, out_buf_size);
// see if the last 2 bytes in the buffer match
if (tmpbuf[2] == tmpbuf[3])
{
// move byte 3 to position 1 and pretend we just
// have 2 bytes -- note that the first byte was
// already sent to output */
tmpbuf[1]=tmpbuf[3];
tmpbuf_cnt=2;
}
else
{
// send byte 2 and keep byte 3 - it may match the
// next byte. Move byte 3 to position 1 and set
// count to 1. Note that the first byte was
// already sent to output
process_uncomp(tmpbuf[2], out_buf, out_buf_size);
tmpbuf[1]=tmpbuf[3];
tmpbuf_cnt=1;
}
}
}
} // end while
flush_outbuf(out_buf, out_buf_size);
return nCodedBytes;
}
//------------------------------------------------------------------
// This flushes any non-compressed data not yet sent, then it processes
// repeating bytes until > 128, or EOD, or non-match.
// return values: LIMIT, EOD_FOUND, NON_MATCH
// Prior to ANY return, it writes out the 2 byte compressed code.
// If a NON_MATCH was found, this returns with the non-matching char
// residing in tmpbuf[0].
// Inputs: tmpbuf[0], input file
// Outputs: tmpbuf[0] (sometimes), output file, and return code
//------------------------------------------------------------------
unsigned long process_comp(
unsigned char *buf, int buf_size,
unsigned char *out_buf, int out_buf_size)
{
// we start out with 3 repeating bytes
int len = 3;
unsigned char ch = 0;
// we're starting a repeating chunk - end the non-repeaters
flush_outbuf(out_buf, out_buf_size);
while (get_byte(&ch, buf, buf_size, out_buf, out_buf_size) != (int)EOD)
{
if (ch != tmpbuf[1])
{
// send no. of repeated bytes to be encoded
put_byte((unsigned char)((--len) | 0x80), out_buf, out_buf_size);
// send the byte's value being repeated
put_byte((unsigned char)tmpbuf[1], out_buf, out_buf_size);
/* save the non-matching character just read */
tmpbuf[1]=(unsigned char) ch;
return NON_MATCH;
}
/* we know the new byte is part of the repeating seq */
len++;
if (len == 128)
{
// send no. of repeated bytes to be encoded
put_byte((unsigned char)((--len) | 0x80), out_buf, out_buf_size);
// send the byte's value being repeated
put_byte((unsigned char)tmpbuf[1], out_buf, out_buf_size);
return LIMIT;
}
} // end while
// if flow comes here, we just read an EOD
// send no. of repeated bytes to be encoded
put_byte((unsigned char)((--len) | 0x80), out_buf, out_buf_size);
// send the byte's value being repeated
put_byte((unsigned char)tmpbuf[1], out_buf, out_buf_size);
return EOD_FOUND;
}
//----------------------------------------------------------------
// This adds 1 non-repeating byte to outbuf. If outbuf becomes full
// with 128 bytes, it flushes outbuf.
// There are no return codes and no bytes are read from the input.
//----------------------------------------------------------------
void process_uncomp(
unsigned char char1, unsigned char *out_buf, int out_buf_size
)
{
outbuf[outbuf_cnt++] = char1;
if (outbuf_cnt == 128)
flush_outbuf(out_buf, out_buf_size);
}
//-----------------------------------------------------------
// This flushes any non-compressed data not yet sent.
// On exit, outbuf_cnt will equal zero.
//-----------------------------------------------------------
void flush_outbuf(unsigned char *out_buf, int out_buf_size)
{
if (!outbuf_cnt)
return; // nothing to do */
// send no. of unencoded bytes to be sent
put_byte((unsigned char)(outbuf_cnt - 1), out_buf, out_buf_size);
for (int pos=0; outbuf_cnt; outbuf_cnt--)
put_byte((unsigned char)outbuf[pos++], out_buf, out_buf_size);
}
//---------------------------------------------------
void put_byte(unsigned char b, unsigned char *out_buf, int out_buf_size)
{
if (nCodedBytes<=(out_buf_size-1))
{
out_buf[nCodedBytes++] = b;
out_buf[nCodedBytes] = 0;
}
}
//---------------------------------------------------
// This reads the next byte into ch. It returns EOD
// at end-of-data
//---------------------------------------------------
unsigned long get_byte(
unsigned char *ch,
unsigned char *in_buf, int in_buf_size,
unsigned char *out_buf, int out_buf_size
)
{
if (nReadedBytes>=in_buf_size)
{
// there are either 0, 1, or 2 char's to write before we quit
if (tmpbuf_cnt == 1)
process_uncomp(tmpbuf[1], out_buf, out_buf_size);
else
{
if (tmpbuf_cnt == 2)
{
process_uncomp(tmpbuf[1], out_buf, out_buf_size);
process_uncomp(tmpbuf[2], out_buf, out_buf_size);
}
}
nReadedBytes =0;
return EOD;
}
(*ch) = (unsigned char)in_buf[nReadedBytes++];
return 0;
}
//-----------------------------------------------------------
int rle_decode (
unsigned char *in_buf, int in_buf_size,
unsigned char *out_buf, int out_buf_size
)
{
nDecodedBytes=0;
nReadedBytes=0;
int ch, i;
while (1)
{
if (nReadedBytes>=in_buf_size)
break;
else
ch=in_buf[nReadedBytes];
nReadedBytes++;
if (ch > 127)
{
i = ch - 127; // i is the number of repetitions
// get the byte to be repeated
if (nReadedBytes>=in_buf_size)
break;
else
ch=in_buf[nReadedBytes];
nReadedBytes++;
// uncompress a chunk
for (; i; --i)
{
if (nDecodedBytes<out_buf_size)
out_buf[nDecodedBytes] = ch;
nDecodedBytes++;
}
}
else
{
// copy out some uncompressed bytes
// i is the no. of bytes
for (i = ch + 1; i; --i)
{
if (nReadedBytes>=in_buf_size)
break;
else
ch=in_buf[nReadedBytes];
nReadedBytes++;
if (nDecodedBytes<out_buf_size)
out_buf[nDecodedBytes] = ch;
nDecodedBytes++;
}
}
} // end while
return nDecodedBytes;
}
} //end namespace core
} //end namespace irr
#endif // __C_MY3D_HELPER_H_INCLUDED__