khanat-opennel-code/code/ryzom/common/src/game_share/bmp4image.h
2016-03-20 17:08:44 +01:00

404 lines
10 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef RY_BMP4IMAGE_H
#define RY_BMP4IMAGE_H
#include <math.h>
#include <vector>
#include <string>
#include <nel/misc/file.h>
template <unsigned int W, unsigned int H>
class CBMP4Image
{
public:
CBMP4Image(): hdr(W,H)
{
// nlassert((W&0xf)==0);
memset(Data,0,sizeof(Data));
}
void circle()
{
// a rough circle round the centre point of the grid
for (int j=0;j<H;j++)
for (int i=0;i<W;i++)
{
double pi=atan2(1.0,0.0)*2;
double angle=atan2(double(i)-double(W-1)/2,double(j)-double(H-1)/2);
double angle01=7.5*angle/pi;
if (angle01<0) angle01-=0.5;
else angle01+=0.5;
unsigned char colour=char(angle01+8)&0xf;
putpix(i,j,colour);
}
}
void gradient()
{
// colour progression
for (int j=0;j<H;j++)
for (int i=0;i<W;i++)
{
putpix(i,j,j*16/H);
}
}
/*bool write(char *filename)
{
FILE *outf=NLMISC::nlfopen(filename, "wb");
if (outf==NULL)
return false;
short BM=0x4D42;
fwrite((void *)&BM,1,sizeof(BM),outf);
fwrite((void *)&image,1,sizeof(image),outf); // ??
fclose(outf);
return true;
}*/
void putpix(int x, int y, unsigned char val)
{
int shift= ((x&1)^1)*4;
char mask= 0x0f<<(4-shift);
unsigned int idx= (W/2)*y+x/2;
Data[idx]=(Data[idx]&mask)|((val&0xf)<<shift);
}
// the image header data buffer
struct SHdr
{
SHdr(int w, int h)
{
// magicBM= 0x4D42;
width= w;
height= h;
bitdepth= 0x0004;
hdrsize= sizeof(CBMP4Image::SHdr)+sizeof(CBMP4Image::SPalette); // 0x00000076;
datasize= w*h/2;
filesize= hdrsize + datasize;
paloffs= 0x00000028;
unknown0= 0x00000000;
unknown1= 0x0001;
unknown2= 0x00000000;
unknown3= 0x00000EC4;
unknown4= 0x00000EC4;
unknown5= 0x00000000;
unknown6= 0x00000000;
}
// unsigned short magicBM; // must have value "BM" (0x4D42) if it's a .bmp
unsigned long filesize; // hdr size + data size
unsigned long unknown0; // 0x00000000 (00 00 00 00)
unsigned long hdrsize; // size of the header (0x76)
unsigned long paloffs; // offset from here to the start of the palette (0x28)
unsigned long width; // width in pixels
unsigned long height; // height in pixels
unsigned short unknown1; // 0x0001 (01 00)
unsigned short bitdepth; // number of bits per pixel (0x04)
unsigned long unknown2; // 0x00000000 (00 00 00 00)
unsigned long datasize; // size of data block (0x00000080 for 16x16 4bit image)
unsigned long unknown3; // 0x00000EC4 (C4 0E 00 00)
unsigned long unknown4; // 0x00000EC4 (C4 0E 00 00)
unsigned long unknown5; // 0x00000000 (00 00 00 00)
unsigned long unknown6; // 0x00000000 (00 00 00 00)
} hdr;
// the palette for the image
struct SPalette
{
SPalette()
{
setupHueCircle();
}
void setupHueCircle()
{
setEntry(0x0, 0x80, 0x00, 0x80, 0x00);
setEntry(0x1, 0xB0, 0x00, 0x50, 0x00);
setEntry(0x2, 0xE0, 0x00, 0x20, 0x00);
setEntry(0x3, 0xF0, 0x10, 0x00, 0x00);
setEntry(0x4, 0xC0, 0x40, 0x00, 0x00);
setEntry(0x5, 0x90, 0x70, 0x00, 0x00);
setEntry(0x6, 0x60, 0xA0, 0x00, 0x00);
setEntry(0x7, 0x30, 0xD0, 0x00, 0x00);
setEntry(0x8, 0x00, 0xFF, 0x00, 0x00);
setEntry(0x9, 0x00, 0xD0, 0x30, 0x00);
setEntry(0xa, 0x00, 0xA0, 0x60, 0x00);
setEntry(0xb, 0x00, 0x70, 0x90, 0x00);
setEntry(0xc, 0x00, 0x40, 0xC0, 0x00);
setEntry(0xd, 0x00, 0x10, 0xF0, 0x00);
setEntry(0xe, 0x20, 0x00, 0xE0, 0x00);
setEntry(0xf, 0x50, 0x00, 0xB0, 0x00);
}
void setupFrom0To4()
{
setEntry(0x0, 0x00, 0x00, 0x00, 0x00);
setEntry(0x1, 0x00, 0x00, 0xFF, 0x00);
setEntry(0x2, 0x00, 0xFF, 0xFF, 0x00);
setEntry(0x3, 0xFF, 0xFF, 0xFF, 0x00);
setEntry(0x4, 0xFF, 0xFF, 0x00, 0x00);
setEntry(0x5, 0xFF, 0x00, 0x00, 0x00);
setEntry(0x6, 0xFF, 0x00, 0x00, 0x00);
setEntry(0x7, 0xFF, 0x00, 0x00, 0x00);
setEntry(0x8, 0xFF, 0x00, 0x00, 0x00);
setEntry(0x9, 0xFF, 0x00, 0x00, 0x00);
setEntry(0xa, 0xFF, 0x00, 0x00, 0x00);
setEntry(0xb, 0xFF, 0x00, 0x00, 0x00);
setEntry(0xc, 0xFF, 0x00, 0x00, 0x00);
setEntry(0xd, 0xFF, 0x00, 0x00, 0x00);
setEntry(0xe, 0xFF, 0x00, 0x00, 0x00);
setEntry(0xf, 0xFF, 0x00, 0x00, 0x00);
}
void setupForCol()
{
setEntry(0x0, 0x00, 0x00, 0x00, 0x00);
setEntry(0x1, 0x00, 0x00, 0x80, 0x00);
setEntry(0x2, 0x00, 0x80, 0xFF, 0x00);
setEntry(0x3, 0x00, 0xFF, 0xFF, 0x00);
setEntry(0x4, 0x40, 0x00, 0x00, 0x00);
setEntry(0x5, 0x40, 0x00, 0x80, 0x00);
setEntry(0x6, 0x40, 0x80, 0xFF, 0x00);
setEntry(0x7, 0x40, 0xFF, 0xFF, 0x00);
setEntry(0x8, 0xA0, 0x00, 0x00, 0x00);
setEntry(0x9, 0xA0, 0x00, 0x80, 0x00);
setEntry(0xa, 0xA0, 0x80, 0xFF, 0x00);
setEntry(0xb, 0xA0, 0xFF, 0xFF, 0x00);
setEntry(0xc, 0xFF, 0x00, 0x00, 0x00);
setEntry(0xd, 0xFF, 0x00, 0x80, 0x00);
setEntry(0xe, 0xFF, 0x80, 0xFF, 0x00);
setEntry(0xf, 0x00, 0x40, 0x00, 0x00);
}
void setupGreyScale()
{
setEntry(0x0, 0x00, 0x00, 0x00, 0x00);
setEntry(0x1, 0x11, 0x11, 0x11, 0x00);
setEntry(0x2, 0x22, 0x22, 0x22, 0x00);
setEntry(0x3, 0x33, 0x33, 0x33, 0x00);
setEntry(0x4, 0x44, 0x44, 0x44, 0x00);
setEntry(0x5, 0x55, 0x55, 0x55, 0x00);
setEntry(0x6, 0x66, 0x66, 0x66, 0x00);
setEntry(0x7, 0x77, 0x77, 0x77, 0x00);
setEntry(0x8, 0x88, 0x88, 0x88, 0x00);
setEntry(0x9, 0x99, 0x99, 0x99, 0x00);
setEntry(0xa, 0xaa, 0xaa, 0xaa, 0x00);
setEntry(0xb, 0xbb, 0xbb, 0xbb, 0x00);
setEntry(0xc, 0xcc, 0xcc, 0xcc, 0x00);
setEntry(0xd, 0xdd, 0xdd, 0xdd, 0x00);
setEntry(0xe, 0xee, 0xee, 0xee, 0x00);
setEntry(0xf, 0xff, 0xff, 0xff, 0x00);
}
void setEntry(int idx, int r, int g, int b, int a)
{
rgba[4*idx+0]=char(r);
rgba[4*idx+1]=char(g);
rgba[4*idx+2]=char(b);
rgba[4*idx+3]=char(a);
}
char rgba[16*4];
} ColourPalette;
// the main image data buffer
char Data[W*H/2];
};
class CTGAImage
{
public:
// Header
uint8 IdLength; // 0
uint8 ColourMapType; // 1
uint8 DataTypeCode; // 2
uint16 ColourMapOrigin; // 3
uint16 ColourMapLength; // 5
uint8 ColourMapDepth; // 7
uint16 XOrigin; // 8
uint16 YOrigin; // 10
uint16 Width; // 12
uint16 Height; // 16
uint8 BitsPerPixel; // 18
uint8 ImageDescriptor; // 19
std::vector<uint16> Line;
std::vector<uint16> ColorMap;
NLMISC::COFile File;
CTGAImage() : IdLength(0), ColourMapType(0), DataTypeCode(2),
ColourMapOrigin(0), ColourMapLength(0), ColourMapDepth(0),
XOrigin(0), YOrigin(0), BitsPerPixel(16),
ImageDescriptor(0)
{
}
void setup(uint16 width, uint16 height, const std::string &filename, uint16 xorigin, uint16 yorigin)
{
Width = width;
Height = height;
XOrigin = xorigin;
YOrigin = yorigin;
Line.resize(Width);
File.open(filename);
File.serial(IdLength);
File.serial(ColourMapType);
File.serial(DataTypeCode);
File.serial(ColourMapOrigin);
File.serial(ColourMapLength);
File.serial(ColourMapDepth);
File.serial(XOrigin);
File.serial(YOrigin);
File.serial(Width);
File.serial(Height);
File.serial(BitsPerPixel);
File.serial(ImageDescriptor);
}
static uint16 getColor16(uint blue, uint green, uint red)
{
return ((red>>3)<<10) + ((green>>3)<<5) + (blue>>3);
}
static uint16 getBlue( uint16 color16 )
{
return (color16 & 31) << 3;
}
static uint16 getGreen( uint16 color16 )
{
return ((color16 & 0x3E0) >> 5) << 3;
}
static uint16 getRed( uint16 color16 )
{
return ((color16 & 0x7C00) >> 10) << 3;
}
void setupForCol()
{
ColorMap.resize(16);
ColorMap[0] = getColor16(0x00, 0x00, 0x00);
ColorMap[1] = getColor16(0x00, 0x00, 0x80);
ColorMap[2] = getColor16(0x00, 0x80, 0xFF);
ColorMap[3] = getColor16(0x00, 0xFF, 0xFF);
ColorMap[4] = getColor16(0x40, 0x00, 0x00);
ColorMap[5] = getColor16(0x40, 0x00, 0x80);
ColorMap[6] = getColor16(0x40, 0x80, 0xFF);
ColorMap[7] = getColor16(0x40, 0xFF, 0xFF);
ColorMap[8] = getColor16(0xA0, 0x00, 0x00);
ColorMap[9] = getColor16(0xA0, 0x00, 0x80);
ColorMap[10] = getColor16(0xA0, 0x80, 0xFF);
ColorMap[11] = getColor16(0xA0, 0xFF, 0xFF);
ColorMap[12] = getColor16(0xFF, 0x00, 0x00);
ColorMap[13] = getColor16(0xFF, 0x00, 0x80);
ColorMap[14] = getColor16(0xFF, 0x80, 0xFF);
ColorMap[15] = getColor16(0x00, 0x40, 0x00);
}
void setup4BitGreyScale()
{
ColorMap.clear();
for (uint32 i=0;i<0x10;++i)
{
uint32 value= 0x11*i;
ColorMap.push_back(getColor16(value, value, value));
}
}
void setup8BitGreyScale()
{
ColorMap.clear();
for (uint32 i=0;i<256;++i)
{
ColorMap.push_back(getColor16(i, i, i));
}
}
void set(uint col, uint idx)
{
nlassert(!ColorMap.empty());
Line[col] = ColorMap[idx%ColorMap.size()];
}
void set(uint col, uint r, uint g, uint b)
{
Line[col] = getColor16(r, g, b);
}
void set16(uint col, uint16 color16)
{
Line[col] = color16;
}
void writeLine()
{
File.serialBuffer((uint8*)(&(Line[0])), (uint)Line.size()*2);
}
};
class CTGAImageGrey: public CTGAImage
{
public:
struct SGreyPixel { uint8 r,g,b; };
std::vector<SGreyPixel> GreyLine;
CTGAImageGrey()
{
BitsPerPixel= 24;
// ImageDescriptor= 32;
}
void set(uint32 x, uint32 greyValue)
{
if (GreyLine.size()<Line.size())
GreyLine.resize(Line.size());
nlassert(GreyLine.size()>x);
GreyLine[x].r = (uint8)greyValue;
GreyLine[x].g = (uint8)greyValue;
GreyLine[x].b = (uint8)greyValue;
}
void writeLine()
{
File.serialBuffer((uint8*)(&(GreyLine[0])), (uint)GreyLine.size()*sizeof(GreyLine[0]));
}
};
#endif // RY_BMP4IMAGE_H