mirror of https://github.com/aap/librw.git
implemented BMP reader
This commit is contained in:
parent
2d345499d2
commit
60450ec6f7
225
src/bmp.cpp
225
src/bmp.cpp
|
@ -19,11 +19,189 @@
|
|||
|
||||
namespace rw {
|
||||
|
||||
// NB: this has padding and cannot be streamed directly!
|
||||
struct BMPheader
|
||||
{
|
||||
uint16 magic;
|
||||
uint32 size;
|
||||
uint16 reserved[2];
|
||||
uint32 offset;
|
||||
|
||||
bool32 read(Stream *stream);
|
||||
void write(Stream *stream);
|
||||
};
|
||||
|
||||
// This one is aligned and can be streamed directly
|
||||
struct DIBheader
|
||||
{
|
||||
uint32 headerSize;
|
||||
int32 width;
|
||||
int32 height;
|
||||
int16 numPlanes;
|
||||
int16 depth;
|
||||
uint32 compression;
|
||||
uint32 imgSize;
|
||||
int32 hres;
|
||||
int32 vres;
|
||||
int32 paletteLen;
|
||||
int32 numImportant;
|
||||
// end of 40 btyes
|
||||
|
||||
uint32 rmask, gmask, bmask, amask;
|
||||
};
|
||||
|
||||
bool32
|
||||
BMPheader::read(Stream *stream)
|
||||
{
|
||||
magic = stream->readU16();
|
||||
size = stream->readU32();
|
||||
reserved[0] = stream->readU16();
|
||||
reserved[1] = stream->readU16();
|
||||
offset = stream->readU32();
|
||||
return magic == 0x4D42;
|
||||
}
|
||||
|
||||
void
|
||||
BMPheader::write(Stream *stream)
|
||||
{
|
||||
|
||||
stream->writeU16(magic);
|
||||
stream->writeU32(size);
|
||||
stream->writeU16(reserved[0]);
|
||||
stream->writeU16(reserved[1]);
|
||||
stream->writeU32(offset);
|
||||
}
|
||||
|
||||
Image*
|
||||
readBMP(const char *afilename)
|
||||
{
|
||||
Image *image;
|
||||
char *filename;
|
||||
uint32 length;
|
||||
uint8 *data;
|
||||
StreamMemory file;
|
||||
int i, x, y;
|
||||
|
||||
filename = Image::getFilename(afilename);
|
||||
if(filename == nil)
|
||||
return nil;
|
||||
data = getFileContents(filename, &length);
|
||||
rwFree(filename);
|
||||
if(data == nil)
|
||||
return nil;
|
||||
file.open(data, length);
|
||||
|
||||
/* read headers */
|
||||
BMPheader bmp;
|
||||
DIBheader dib;
|
||||
if(!bmp.read(&file))
|
||||
goto lose;
|
||||
file.read(&dib, sizeof(dib));
|
||||
file.seek(dib.headerSize-sizeof(dib)); // skip the part of the header we're ignoring
|
||||
if(dib.headerSize <= 16){
|
||||
dib.compression = 0;
|
||||
dib.paletteLen = 0;
|
||||
}
|
||||
|
||||
bool32 noalpha = true;
|
||||
|
||||
// Recognize 32 bit formats
|
||||
if(dib.compression == 3){
|
||||
if(dib.rmask != 0xFF0000 ||
|
||||
dib.gmask != 0x00FF00 ||
|
||||
dib.bmask != 0x0000FF)
|
||||
goto lose;
|
||||
dib.compression = 0;
|
||||
if(dib.headerSize > 52 && dib.amask == 0xFF000000)
|
||||
noalpha = false;
|
||||
}
|
||||
|
||||
if(dib.compression != 0)
|
||||
goto lose;
|
||||
|
||||
image = Image::create(dib.width, dib.height, dib.depth);
|
||||
image->allocate();
|
||||
|
||||
|
||||
if(image->palette){
|
||||
int len = 1<<dib.depth;
|
||||
uint8 (*color)[4] = (uint8 (*)[4])image->palette;
|
||||
for(i = 0; i < len; i++){
|
||||
color[i][2] = file.readU8(); // blue
|
||||
color[i][1] = file.readU8(); // green
|
||||
color[i][0] = file.readU8(); // red
|
||||
color[i][3] = file.readU8(); // alpha
|
||||
if(noalpha)
|
||||
color[i][3] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
file.seek(bmp.offset, 0);
|
||||
|
||||
int pad = image->width*image->bpp % 4;
|
||||
|
||||
uint8 *px, *line;
|
||||
line = image->pixels + (image->height-1)*image->stride;
|
||||
for(y = 0; y < image->height; y++){
|
||||
px = line;
|
||||
for(x = 0; x < image->width; x++){
|
||||
switch(image->depth){
|
||||
case 4:
|
||||
i = file.readU8();;
|
||||
px[x+0] = (i>>4)&0xF;
|
||||
px[x+1] = i&0xF;
|
||||
x++;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
px[x] = file.readU8();
|
||||
break;
|
||||
|
||||
case 16:
|
||||
// TODO: what format is this even? and what does Image expect?
|
||||
px[x*2 + 0] = file.readU8();
|
||||
px[x*2 + 1] = file.readU8();
|
||||
break;
|
||||
|
||||
case 24:
|
||||
px[x*3 + 2] = file.readU8();
|
||||
px[x*3 + 1] = file.readU8();
|
||||
px[x*3 + 0] = file.readU8();
|
||||
break;
|
||||
|
||||
case 32:
|
||||
px[x*4 + 2] = file.readU8();
|
||||
px[x*4 + 1] = file.readU8();
|
||||
px[x*4 + 0] = file.readU8();
|
||||
px[x*4 + 3] = file.readU8();
|
||||
if(noalpha)
|
||||
px[x*4 + 3] = 0xFF;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto lose;
|
||||
}
|
||||
}
|
||||
|
||||
line -= image->stride;
|
||||
file.seek(pad);
|
||||
}
|
||||
|
||||
|
||||
file.close();
|
||||
rwFree(data);
|
||||
return image;
|
||||
|
||||
lose:
|
||||
file.close();
|
||||
rwFree(data);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* can't write alpha */
|
||||
void
|
||||
writeBMP(Image *image, const char *filename)
|
||||
{
|
||||
uint8 buf[54];
|
||||
uint8 *p;
|
||||
StreamFile file;
|
||||
if(!file.open(filename, "wb")){
|
||||
|
@ -37,35 +215,34 @@ writeBMP(Image *image, const char *filename)
|
|||
int32 depth = image->depth == 32 ? 24 : image->depth;
|
||||
stride = stride+3 & ~3;
|
||||
|
||||
// File header
|
||||
p = buf;
|
||||
*p++ = 'B';
|
||||
*p++ = 'M';
|
||||
*(uint32*)p = 0x36 + 4*pallen + image->height*stride; p += 4;
|
||||
*(uint16*)p = 0; p += 2; // reserved
|
||||
*(uint16*)p = 0; p += 2;
|
||||
*(uint32*)p = 0x36 + 4*pallen; p += 4; // data offset
|
||||
// File headers
|
||||
BMPheader bmp;
|
||||
bmp.magic = 0x4D42; // BM
|
||||
bmp.size = 0x36 + 4*pallen + image->height*stride;
|
||||
bmp.reserved[0] = 0;
|
||||
bmp.reserved[1] = 0;
|
||||
bmp.offset = 0x36 + 4*pallen;
|
||||
bmp.write(&file);
|
||||
|
||||
// DIB header
|
||||
*(uint32*)p = 0x28; p += 4; // header size
|
||||
*(int32*)p = image->width; p += 4;
|
||||
*(int32*)p = image->height; p += 4;
|
||||
*(int16*)p = 1; p += 2; // number of planes
|
||||
*(int16*)p = depth; p += 2;
|
||||
*(uint32*)p = 0; p += 4; // compression: none
|
||||
*(int32*)p = 0; p += 4; // size, not needed in our case
|
||||
*(int32*)p = 2835; p += 4; // x resolution, 72dpi
|
||||
*(int32*)p = 2835; p += 4; // y resolution
|
||||
*(int32*)p = 0; p += 4; // number of used palette colors: max
|
||||
*(int32*)p = 0; p += 4; // important pixels
|
||||
|
||||
file.write(buf, 54);
|
||||
DIBheader dib;
|
||||
dib.headerSize = 0x28;
|
||||
dib.width = image->width;
|
||||
dib.height = image->height;
|
||||
dib.numPlanes = 1;
|
||||
dib.depth = depth;
|
||||
dib.compression = 0;
|
||||
dib.imgSize = 0;
|
||||
dib.hres = 2835; // 72dpi
|
||||
dib.vres = 2835; // 72dpi
|
||||
dib.paletteLen = 0;
|
||||
dib.numImportant = 0;
|
||||
file.write(&dib, dib.headerSize);
|
||||
|
||||
for(int i = 0; i < pallen; i++){
|
||||
file.writeU8(image->palette[i*4+2]);
|
||||
file.writeU8(image->palette[i*4+1]);
|
||||
file.writeU8(image->palette[i*4+0]);
|
||||
file.writeU8(0);
|
||||
file.writeU8(0xFF);
|
||||
}
|
||||
|
||||
uint8 *line = image->pixels + (image->height-1)*image->stride;
|
||||
|
|
|
@ -392,6 +392,7 @@ rasterCreateTexture(Raster *raster)
|
|||
natras->texture = createTexture(raster->width, raster->height,
|
||||
raster->format & Raster::MIPMAP ? levels : 1,
|
||||
format);
|
||||
assert(natras->texture && "couldn't create d3d texture");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -495,6 +496,7 @@ rasterFromImage(Raster *raster, Image *image)
|
|||
if(image->depth <= 8 && !isP8supported){
|
||||
truecolimg = Image::create(image->width, image->height, image->depth);
|
||||
truecolimg->pixels = image->pixels;
|
||||
truecolimg->stride = image->stride;
|
||||
truecolimg->palette = image->palette;
|
||||
truecolimg->unindex();
|
||||
image = truecolimg;
|
||||
|
|
|
@ -149,6 +149,7 @@ struct Image
|
|||
|
||||
Image *readTGA(const char *filename);
|
||||
void writeTGA(Image *image, const char *filename);
|
||||
Image *readBMP(const char *filename);
|
||||
void writeBMP(Image *image, const char *filename);
|
||||
|
||||
// used to emulate d3d and xbox textures
|
||||
|
|
|
@ -263,6 +263,7 @@ defaultFindCB(const char *name)
|
|||
}
|
||||
|
||||
|
||||
// TODO: no hardcoded file endings
|
||||
// TODO: actually read the mask!
|
||||
static Texture*
|
||||
defaultReadCB(const char *name, const char *mask)
|
||||
|
@ -273,6 +274,11 @@ defaultReadCB(const char *name, const char *mask)
|
|||
strcpy(n, name);
|
||||
strcat(n, ".tga");
|
||||
img = readTGA(n);
|
||||
if(img == nil){
|
||||
strcpy(n, name);
|
||||
strcat(n, ".bmp");
|
||||
img = readBMP(n);
|
||||
}
|
||||
rwFree(n);
|
||||
if(img){
|
||||
tex = Texture::create(Raster::createFromImage(img));
|
||||
|
|
|
@ -170,6 +170,7 @@ InitRW(void)
|
|||
|
||||
initFont();
|
||||
|
||||
rw::d3d::isP8supported = false;
|
||||
tex = rw::Texture::read("maze", nil);
|
||||
tex2 = rw::Texture::read("checkers", nil);
|
||||
|
||||
|
@ -264,13 +265,15 @@ im2dtest(void)
|
|||
verts[i].setScreenZ(rw::im2d::GetNearZ());
|
||||
verts[i].setCameraZ(Scene.camera->nearPlane);
|
||||
verts[i].setRecipCameraZ(recipZ);
|
||||
// verts[i].setColor(vs[i].r, vs[i].g, vs[i].b, vs[i].a);
|
||||
verts[i].setColor(vs[i].r, vs[i].g, vs[i].b, vs[i].a);
|
||||
if(dosoftras)
|
||||
verts[i].setColor(255, 255, 255, 255);
|
||||
verts[i].setU(vs[i].u + 0.5f/640.0f, recipZ);
|
||||
verts[i].setV(vs[i].v + 0.5f/448.0f, recipZ);
|
||||
}
|
||||
|
||||
// rw::SetRenderStatePtr(rw::TEXTURERASTER, tex2->raster);
|
||||
rw::SetRenderStatePtr(rw::TEXTURERASTER, tex->raster);
|
||||
if(dosoftras)
|
||||
rw::SetRenderStatePtr(rw::TEXTURERASTER, testras);
|
||||
rw::SetRenderState(rw::TEXTUREADDRESS, rw::Texture::WRAP);
|
||||
rw::SetRenderState(rw::TEXTUREFILTER, rw::Texture::NEAREST);
|
||||
|
@ -347,8 +350,8 @@ void drawtest(void);
|
|||
extern void endSoftras(void);
|
||||
if(dosoftras){
|
||||
endSoftras();
|
||||
im2dtest();
|
||||
}
|
||||
im2dtest();
|
||||
|
||||
// Scene.clump->render();
|
||||
// im3dtest();
|
||||
|
|
Loading…
Reference in New Issue