//============================================================================== // ■ Bitmap //------------------------------------------------------------------------------ // ビットマップのクラス。ビットマップは、いわゆる画像そのものを表わします。 // 画面にビットマップを表示するためにはスプライト (Sprite) などを使う必要があります。(RGGSヘルプより) //============================================================================== #ifndef RPG2K_Bitmap #define RPG2K_Bitmap #include "Color.h" #include "Rect.h" // あらかじめ以下のファイルにパスを通しておいてください(全てpng.hからincludeされます) // ・png.h // ・pngconf.h // ・zlib.h // ・zconf.h #include // zlib展開の設定 #define INBUFSIZ 1024 // 入力バッファサイズ(任意) #define OUTBUFSIZ 1024 // 出力バッファサイズ(任意) // PNG読み込みに必要なコールバック関数 void PngReadFunc(png_struct *pPng, png_bytep buf, png_size_t size){ pspBasicStream* pFile = (pspBasicStream*)png_get_io_ptr(pPng); pFile->read(buf, (int)size); } class Bitmap{ unsigned short width; unsigned short height; bool disposed; unsigned int* bmpixels; public: unsigned int transparency; // コンストラクタ Bitmap(unsigned short w = 0, unsigned short h = 0){ bmpixels = (unsigned int*)calloc(w*h, sizeof(unsigned int)); width = w; height = h; disposed = false; transparency = 0; } Bitmap(const char* path){ disposed = false; fileopen(path); } // デストラクタ ~Bitmap(){ dispose(); } unsigned short getWidth() const{ return width;} unsigned short getHeight() const{ return height;} //解放 void dispose(){ if(!disposed){ free(bmpixels); disposed = true; width = 0; height = 0; } } bool isDisposed() const { return disposed;} // ファイルから開く 注:開発中のため独自形式のみ対応 bool fileopen(const char* path){ if(disposed) return false; // 拡張子を調べる const char* szExt = path + strlen(path) - 3; // 拡張子から自動的に判別する if(stricmp(szExt,"bmp")==0) return LoadBmp(path); else if(stricmp(szExt,"png")==0) return LoadPng(path); else if(stricmp(szExt,"xyz")==0) return LoadXyz(path); return false; /* if(disposed) return false; unsigned short w; pspBasicStream file; // ファイルオープン if(!file.fileopen(path, false)) return false; // 画像幅取得 (独自形式の先頭2バイト) file.read(&w, 2); width = (unsigned short)w; // 画像高さ取得 (ファイルサイズ-2 /幅) height = (file.getLength()-2)/width; // ビットマップを開放 free(bmpixels); // 画像読み込み bmpixels = (unsigned int*)calloc(width*height, sizeof(unsigned int)); unsigned short x,y; for (y = 0; y < height; ++y){ // ファイルから1ライン読み込み unsigned int* line = &bmpixels[y * width]; file.read(line, width*4); for (x = 0; x < width; ++x) { line[x] = 0xFF000000 + RGBcode(line[x]); } } file.close(); return true; */ } // ビットマップをクリア bool clear(unsigned int ccolor = 0){ if(disposed) return false; unsigned short x,y; for (y = 0; y < height; ++y){ unsigned int* line = &bmpixels[y * width]; for (x = 0; x < width; ++x) { if(ccolor==0) line[x] = transparency; else line[x] = ccolor; } } return true; } // ピクセル取得/設定 unsigned int get_pixel(unsigned short x, unsigned short y){ if(x > width || y > height || disposed) return false; return bmpixels[y*width+x]; } bool set_pixel(unsigned short x, unsigned short y, unsigned int pix){ if(x > width || y > height || disposed) return false; bmpixels[y*width+x] = pix; return true; } void get_rect(Rect* rec){ rec->width = width; rec->height = height; } // src_bitmap の矩形 src_rect (Rect) から、このビットマップの座標 (x, y) にブロック転送 bool blt(unsigned short x, unsigned short y, Bitmap* src_bitmap, Rect* src_rect, float opacity = 255){ if(x > width || y > height || disposed) return false; unsigned short a,b; for (a = 0; a < src_rect->height; ++a) { if(a >= height) break; unsigned int* line = &bmpixels[(y + a) * width]; for (b = 0; b < src_rect->width; ++b) { if(b >= width) break; if(opacity == 0 || src_bitmap->get_pixel(src_rect->x + b, src_rect->y + a) == src_bitmap->transparency) break; if(opacity == 255){ line[b+x] = src_bitmap->get_pixel(src_rect->x + b, src_rect->y + a); }else{ Color C1,C2; C1.setBGRcode(line[b+x]); C2.setBGRcode(src_bitmap->get_pixel(src_rect->x + b, src_rect->y + a)); C2.opacity = opacity; C1.conposit(&C2); line[b+x] = C1.getPSPBGRcode(); } } } return true; } // X方向に反転 // ※この関数は、自分自身を反転させるのか、それとも自分自身はそのまま残しておいて反転させたBitmapを // 戻り値として返すのか分からなかったので、自分自身を反転という前提で作っておきました(reversalYも同様) Bitmap* reversalX(){ unsigned short i; unsigned int* pixel = bmpixels; for(i = 0; i < height; i++){ // 1行ずつ反転 MemoryReverse(pixel, width); // get_pixelでその都度乗算を行うと遅くなるので使わない pixel += width; } return this; } Bitmap* reversalY(){ unsigned short i; unsigned short max = height / 2; // forで除算を使うと遅くなるので変数として確保しておく unsigned int* pixel1 = bmpixels; // 一番上の行 unsigned int* pixel2 = &bmpixels[width*(height-1)]; ; // 一番下の行 unsigned int* tmp = (unsigned int*)calloc(width, sizeof(unsigned int)); // 作業用の一時領域 unsigned int linesize = width * sizeof(unsigned int); // forの中で(ry for(i = 0; i < max; i++){ memcpy(tmp , pixel1, linesize); memcpy(pixel1, pixel2, linesize); memcpy(pixel2, tmp , linesize); pixel1 += width; pixel2 -= width; } free(tmp); return this; } private: // メモリの中身を反転する void MemoryReverse(void* pData, unsigned int dwSize) { if(pData==NULL || dwSize<2) return; unsigned char* p = (unsigned char*)pData; unsigned char c; unsigned int max = dwSize / 2; unsigned int i; for(i = 0; i < max; i++){ c = p[i]; p[i] = p[dwSize-1-i]; p[dwSize-1-i] = c; } } //////////////////////////////////////////////////////////////////// // BMPZ読み込み関連 //////////////////////////////////////////////////////////////////// // BMP 構造体 typedef struct tagBITMAP_FILE_HEADER { unsigned short bfType; // 2 "BM" unsigned long bfSize; // 4 ファイルサイズ unsigned short bfReserved1; // 2 予約 Zero unsigned short bfReserved2; // 2 予約 Zero unsigned long bfOffBits; // 4 先頭からイメージデータまでのオフセット } BITMAPFILEHEADER; // イメージデータ情報 typedef struct tagBITMAP_INFO_HEADER { unsigned long biSize; // この構造体のサイズ long biWidth; // 画像の横幅 long biHeight; // 画像の高さ unsigned short biPlanes; // 予約 1 unsigned short biBitCount; // 色数 unsigned long biCompression; // 圧縮の種類 unsigned long biSizeImage; // イメージのバイト数 long biXPelsPerMeter; // 水平解像度 long biYPelsPerMeter; // 垂直解像度 unsigned long biClrUsed; // 使用するカラーインデックスの数 unsigned long biClrImportant; // 減色しないカラーインデックス数 } BITMAPINFOHEADER; // カラーテーブル要素 typedef struct tagRGBQUAD { unsigned char rgbBlue; unsigned char rgbGreen; unsigned char rgbRed; unsigned char rgbReserved; } RGBQUAD; // ヘッダ情報 typedef struct tagBITMAP_INFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; // カラーテーブルの一番目 } BITMAPINFO; // ========= OS/2 BMP/DIB FORMAT // OS/2 イメージデータ情報 typedef struct tagBITMAP_CORE_HEADER { unsigned long biSize; // この構造体のサイズ unsigned short biWidth; // 画像の横幅 unsigned short biHeight; // 画像の高さ unsigned short biPlanes; // 予約 1 unsigned short biBitCount; // 色数 } BITMAPCOREHEADER; // OS/2 カラーテーブル要素 typedef struct tagRGBTRIPLE { unsigned char rgbBlue; unsigned char rgbGreen; unsigned char rgbRed; } RGBTRIPLE; // OS/2 ヘッダ情報 typedef struct tagBITMAP_CORE_INFO { BITMAPCOREHEADER bmiHeader; RGBTRIPLE bmiColors[1]; // カラーテーブルの一番目 } BITMAPCOREINFO; // BMPを開く(8bits only) bool LoadBmp(const char* path){ pspBasicStream file; BITMAPFILEHEADER header; BITMAPINFOHEADER info; RGBQUAD palette[256]; unsigned short x, y; // ファイルオープン if(!file.fileopen(path, false)) return false; file.read(&header, sizeof(header)); // BMPヘッダが一致しない if(memcmp(&header.bfType,"BM", 2)!=0){ // ひょっとしてオブジェクト解放時に自動的にcloseされる? // その辺が分からないので一応自分でcloseしておく file.close(); return false; } // WIN if(info.biSize==sizeof(BITMAPINFOHEADER)){ // 扱えない形式 if(info.biBitCount!=8 || info.biWidth>65535 || info.biHeight>65535){ file.close(); return false; } width = (unsigned short)info.biWidth; height = (unsigned short)info.biHeight; // ビットマップを開放 free(bmpixels); // 画像読み込み bmpixels = (unsigned int*)calloc(width*height, sizeof(unsigned int)); // パレットを読み込む file.read(&palette, sizeof(palette)); } // OS/2 else if(info.biSize==sizeof(BITMAPCOREHEADER)){ BITMAPCOREHEADER core; // WINではなかったので読み込みしなおす // ※pspBasicStreamでの読み込み位置セットの関数が分からなかったのでそれっぽい関数名にしています // 実際に使う時はそちらで正しい名前に修正してください(他にもいくつか使ってます) file.seek(sizeof(BITMAPFILEHEADER), SEEK_SET); file.read(&core, sizeof(core)); // 扱えない形式 if(core.biBitCount!=8){ file.close(); return false; } width = core.biWidth; height = core.biHeight; // ビットマップを開放 free(bmpixels); // 画像読み込み bmpixels = (unsigned int*)calloc(width*height, sizeof(unsigned int)); // パレットを読み込む for(x = 0; x < 256; x++){ file.read(&palette[x], sizeof(RGBTRIPLE)); } } else{ file.close(); return false; } // 念のために自分で読み込み位置をセットする file.seek(header.bfOffBits, SEEK_SET); // BMPファイルは左下のピクセルから始まっているので、逆から格納する unsigned char c; for(y = height-1; y >= 0; y--){ unsigned int* line = &bmpixels[y * width]; for(x = 0; x < width; x++){ file.read(&c, 1); // RGBの順番が不明なので適当にやってますw line[x] = 0xFF000000 + (palette[c].rgbRed<<16) + (palette[c].rgbGreen<<8) + (palette[c].rgbBlue); } // 4バイト境界を読み飛ばす if(width%4!=0){ file.seek(4-width%4, SEEK_CUR); } } file.close(); return true; } //////////////////////////////////////////////////////////////////// // PNG読み込み関連 // <参考URL>http://www.kcrt.net/program/uselibpng_read.html //////////////////////////////////////////////////////////////////// // PNGを開く(8bits only) bool LoaPng(const char* path){ pspBasicStream file; RGBQUAD palette[256]; unsigned short x, y; // ファイルオープン if(!file.fileopen(path, false)) return false; char buf[8]; file.read(buf, 8); if(!png_check_sig(buf, 8)){ file.close(); return false; } png_struct *pPng; png_info *pInfo; if(!(pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))){ file.close(); return false; } if(!(pInfo = png_create_info_struct(pPng))){ png_destroy_read_struct(&pPng, (png_infopp)NULL, (png_infopp)NULL); file.close(); return false; } file.seek(0, SEEK_SET); // 読み込み位置をファイル先頭にセットする png_set_read_fn(png_ptr,(png_voidp)&file,(png_rw_ptr)PngReadFunc); png_read_info(pPng, pInfo); png_uint_32 PngWidth; png_uint_32 PngHeight; int bpp; int ColorType; png_get_IHDR(pPng, pInfo, &PngWidth, &PngHeight, &bpp, &ColorType, NULL, NULL, NULL); // 対応していない形式 if(bpp!=8 || PngWidth>65535 || PngHeight>65535){ png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); file.close(); return false; } if(png_get_valid(pPng, pInfo, PNG_INFO_tRNS)) png_set_expand(pPng); if(ColorType == PNG_COLOR_TYPE_PALETTE) png_set_expand(pPng); if(ColorType == PNG_COLOR_TYPE_GRAY && bpp < 8) png_set_expand(pPng); if(bpp > 8) png_set_strip_16(pPng); if(ColorType == PNG_COLOR_TYPE_GRAY) png_set_gray_to_rgb(pPng); width = (unsigned short)PngWidth; height = (unsigned short)PngHeight; // ビットマップを開放 free(bmpixels); // 画像読み込み bmpixels = (unsigned int*)calloc(width*height, sizeof(unsigned int)); unsigned char **Lines; Lines = (unsigned char **)malloc(PngHeight, sizeof(unsigned char*)); for(int i = 0; i < PngHeight; i++){ Lines[i] = (unsigned char*)&bmpixels[i * PngWidth]; } if(!(ColorType & PNG_COLOR_MASK_ALPHA)) png_set_filler(pPng, 0, 1); png_set_bgr(pPng); png_read_image(pPng, Lines); free(Lines); png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); file.close(); return true; } //////////////////////////////////////////////////////////////////// // XYZ読み込み関連 //////////////////////////////////////////////////////////////////// // XYZのファイルヘッダ struct XYZ_FILEHEADER{ unsigned char cID[4]; // 識別用ID unsigned short shWidth; // 画像の幅 unsigned short shHeight; // 画像の高さ }; // XYZのパレット情報 struct XYZ_RGB{ unsigned char rgbRed; unsigned char rgbGreen; unsigned char rgbBlue; }; // XYZを開く bool LoadXyz(const char* path){ pspBasicStream file; XYZ_FILEHEADER header; unsigned short x, y; // ファイルオープン if(!file.fileopen(path, false)) return false; file.read(&header, sizeof(header)); // ヘッダが一致しない if(memcmp(header.cID,"XYZ1",4)!=0){ file.close(); return false; } width = header.shWidth; height = header.shHeight; // ビットマップを開放 free(bmpixels); // 画像読み込み bmpixels = (unsigned int*)calloc(width*height, sizeof(unsigned int)); // zlib展開用のバッファを確保 unsigned char* tmp = (unsigned char*)calloc(width*height+sizeof(XYZ_RGB)*256, sizeof(unsigned char)); // zlib展開 if(!Decompress_zlib(&file, tmp)){ free(tmp); file.close(); return false; } // パレット const XYZ_RGB* palette = tmp; // 画像データ unsigned char* pData = tmp + sizeof(XYZ_RGB)*256; unsigned char c; for(y = 0; y < height; y++){ unsigned int* line = &bmpixels[y * width]; for(x = 0; x < width; x++){ c = *pData++; // RGBの順番が不明なので適当にやってますw line[x] = 0xFF000000 + (palette[c].rgbRed<<16) + (palette[c].rgbGreen<<8) + (palette[c].rgbBlue); } } free(tmp); file.close(); return true; } // zlibで展開する bool Decompress_zlib(pspBasicStream* pFile, unsigned char* pDst) { z_stream z; // ライブラリとやりとりするための構造体 unsigned char inbuf[INBUFSIZ]; // 入力バッファ unsigned char outbuf[OUTBUFSIZ]; // 出力バッファ int count, status; int offset = 0; // すべてのメモリ管理をライブラリに任せる z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; // 初期化 z.next_in = Z_NULL; z.avail_in = 0; if (inflateInit(&z) != Z_OK) { return false; } z.next_out = outbuf; // 出力ポインタ z.avail_out = OUTBUFSIZ; // 出力バッファ残量 status = Z_OK; while(status != Z_STREAM_END) { if(z.avail_in==0){ // 入力残量がゼロになれば入力ポインタを元に戻す z.next_in = inbuf; z.avail_in = pFile->read(inbuf, sizeof(inbuf)); // 実際に読み込んだサイズを取得する } status = inflate(&z, Z_NO_FLUSH); // 展開 if(status == Z_STREAM_END) break; // 完了 if(status != Z_OK){ return false; } if(z.avail_out==0){ // 出力バッファが尽きればまとめて書き出す memcpy(pDst+offset, outbuf, OUTBUFSIZ); offset += OUTBUFSIZ; z.next_out = outbuf; // 出力ポインタを元に戻す z.avail_out = OUTBUFSIZ; // 出力バッファ残量を元に戻す } } // 残りを吐き出す if((count = OUTBUFSIZ - z.avail_out) != 0){ memcpy(pDst+offset, outbuf, count); } // 後始末 if(inflateEnd(&z) != Z_OK){ return false; } return true; } }; #endif