#include "stdio.h"
#include "sys/stat.h"//required for setting file permissions
#include "fcntl.h"//required for setting create/readwrite/read only etc.
#include <cstring>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
using namespace std;
#include "BMP.h" ///// note for other viewers: doesn't have anything other than function prototypes
void saveBMP(const char *filepath, OGL_Surface *Surface, int bpp, uint8_t compression)
{
if (bpp==32 || bpp==4){bpp=24;}//do not support 32bit
if (bpp==3){bpp=24;}
int palettecols =0;// (should be included as function arg)
uint32_t imgbytes = (Surface->w*Surface->h*bpp)/8;
int padding = (Surface->w*3)%4;
if (padding != 0){padding=4-padding; imgbytes += Surface->h*padding;}
uint32_t data = 0;
int file = open(filepath, O_CREAT | O_RDWR, S_IRWXU);
if (file < 0 ){perror("ERROR CREATING/OPENING BMP FILE");exit(1);}
lseek(file, 0, SEEK_SET);
/// file header (14 bytes)
//BitMap declaraction
write(file, "BM", 2);
//complete file size in bytes. 14+40 + num bytes for image data + (palette)
if (bpp>8){data = imgbytes + 54;}
else{data = imgbytes + 54 + palettecols*4;}
write(file, &data, 4);
//reserved nulls
data=0;
write(file, &data, 4);
//offset to actual pixel data (again 14+40) + (palette)
if (bpp>8){data=54;}
else{data = 54 + palettecols*4;}
write(file, &data, 4);
/// file info (40 bytes)
//size of info data
data=40;
write(file, &data, 4);
//image width, height
data=Surface->w;
write(file, &data, 4);
data=Surface->h;
write(file, &data, 4);
//must be set to 1
data=1;
write(file, &data, 2);
//bits per pixel (MAX 24!)
data= min(bpp,24);
write(file, &data, 2);
//compression, compression notes: http://netghost.narod.ru/gff/vendspec/micbmp/bmp.txt
data=0;
write(file, &data, 4);
//image size in bytes
data=imgbytes;
write(file, &data, 4);
//x,y pixels per meter (set to 0)
data=0;
write(file, &data, 4);
write(file, &data, 4);
/// palette (only for 1,4 and 8 bit images, 4 bytes per colour, min 8 bytes)
//colours used (0=autodetect from bpp, for 8bpp or less palette will only use the amount of colours)
write(file, &data, 4);
//important colours (0=all are important)
write(file, &data, 4);
//palette (should be included as function arg)
uint32_t *palette = NULL;
uint8_t r,g,b;
if (bpp<24){
for (uint8_t i = 0; i<palettecols; i++){
r=(palette[i]&0x000000FF);
g=(palette[i]&0x0000FF00)>>8;
b=(palette[i]&0x00FF0000)>>16;
write(file, &b, 1);//b
write(file, &g, 1);//g
write(file, &r, 1);//r
write(file, 0, 1);//null
}
}
/// pixeldata
uint8_t *buffer = new uint8_t[imgbytes];
memset(buffer, 0, imgbytes);
int datawidth = (Surface->w*3)+padding;
int pos = 0;
int buf_pos = imgbytes-datawidth;
for (uint32_t y = 0; y<Surface->h; y++){
for (uint32_t x = 0; x<Surface->w; x++){
buffer[buf_pos] = Surface->PixData[pos];
buffer[buf_pos+1]= Surface->PixData[pos+1];
buffer[buf_pos+2]= Surface->PixData[pos+2];
buf_pos+=3;
pos+=Surface->bpp;
}
//return buffer to start of line then up one line
buf_pos += padding;
buf_pos -= datawidth+datawidth;
}
write(file, buffer, imgbytes);
close(file);
delete [] buffer;
}
void loadBMP(const char *filepath, OGL_Surface *Surface)
{
char BMP[3]= {0,0};
int dataoffset=0;
int imgbytes=0;
int compression=0;
char bpp= 0;
int file = open(filepath, O_RDONLY, S_IRWXU);
if (file < 0 ){perror("ERROR LOADING BMP FILE");exit(1);}
/// file header
//BitMap declaraction
lseek(file, 0, SEEK_SET);
read(file, BMP, 2);
if (BMP[0] != 'B' || BMP[1] != 'M'){printf("UNSUPPORTED FILE TYPE (not BMP)");exit(1);}
//skip file size, 4
//skip reserved nulls, 4
//offset to actual pixel data
lseek(file, 10, SEEK_SET);
read(file, &dataoffset, 4);
//skip headersize, 4
//width & height
lseek(file, 18, SEEK_SET);
read(file, &Surface->w, 4);
read(file, &Surface->h, 4);
//skip "planes", 2
//bits per pixel
lseek(file, 28, SEEK_SET);
read(file, &bpp, 2);
//compression
read(file, &compression, 4);
if (compression != 0){printf("FILE USING UNSUPPORTED COMPRESSION");exit(1);}
//size of image data in bytes
read(file, &imgbytes, 4);
//skip hres, 4
//skip vres, 4
/// palette (only for 1,4 and 8 bit images)
uint32_t *palette;
if (bpp<24){
//colours used
lseek(file, 46, SEEK_SET);
int palettecols;
read(file, &palettecols, 4);
//skip important colours, 4
if (palettecols != 0){
palette = new uint32_t[palettecols];
memset(palette, 0, palettecols*4);
}
for (int i = 0; i<palettecols; i++){
read(file, &palette[i], 4);
}
}
/// pixeldata
lseek(file, dataoffset, SEEK_SET);
uint8_t *buffer = new uint8_t[imgbytes];
memset(buffer, 0, imgbytes);
read(file, buffer, imgbytes);
close(file);
/// convert data to rgb format
if (Surface->PixData != NULL){delete [] Surface->PixData;}
Surface->PixData = new uint8_t[Surface->w*Surface->h*Surface->bpp];
memset(Surface->PixData, 255, Surface->w*Surface->h*Surface->bpp);
int padding = (Surface->w*3)%4;
if (padding != 0){padding=4-padding;}
int datawidth = (Surface->w*3)+padding;
int pos = 0;
int buf_pos = imgbytes-datawidth;
for (uint32_t y = 0; y<Surface->h; y++){
for (uint32_t x = 0; x<Surface->w; x++){
Surface->PixData[pos] = buffer[buf_pos];
Surface->PixData[pos+1]= buffer[buf_pos+1];
Surface->PixData[pos+2]= buffer[buf_pos+2];
//if supporting alpha, set 255,0,255 to transparent
if(Surface->bpp==4 && buffer[buf_pos] == 255 && buffer[buf_pos+1] == 0 && buffer[buf_pos+2] == 255){Surface->PixData[pos+3]= 0;}
buf_pos+=3;
pos+=Surface->bpp;
}
//return buffer to start of line then up one line
buf_pos += padding;
buf_pos -= datawidth+datawidth;
}
delete [] buffer;
}
void loadBMP(const char *filepath, OGL_Texture *Texture)
{
OGL_Surface *Surface = new OGL_Surface;
Surface->Create_Surface(1,1,4);
loadBMP(filepath, Surface);
Texture->gen_texture(Surface->w, Surface->h, Surface->PixData);
delete Surface;
}