bitmap.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 840 行 · 第 1/2 页
CPP
840 行
#include "StdAfx.h"
// Bitmap.cpp: implementation of the CBitmap class.
//
//////////////////////////////////////////////////////////////////////
#include "Rendering/GL/myGL.h"
#include <ostream>
#include <fstream>
#include "FileSystem/FileHandler.h"
#if defined(__APPLE__)
#include <QuickTime/ImageCompression.h>
#include <QuickTime/QuickTimeComponents.h>
#else
#include <IL/il.h>
#include <IL/ilu.h>
#endif
#include "Platform/FileSystem.h"
#include "Rendering/Textures/Bitmap.h"
#include "bitops.h"
#include "mmgr.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#if !defined(__APPLE__)
struct InitializeOpenIL {
InitializeOpenIL() {
ilInit();
iluInit();
}
~InitializeOpenIL() {
ilShutDown();
}
} static initOpenIL;
#endif
CBitmap::CBitmap()
: xsize(0), ysize(0)
{
mem=0;
ddsimage = 0;
type = BitmapTypeStandardRGBA;
}
CBitmap::~CBitmap()
{
delete[] mem;
delete ddsimage;
}
CBitmap::CBitmap(const CBitmap& old)
{
assert(old.type != BitmapTypeDDS);
ddsimage = 0;
type = old.type;
xsize=old.xsize;
ysize=old.ysize;
int size;
if(type == BitmapTypeStandardRGBA) size = xsize*ysize*4;
else size = xsize*ysize; // Alpha
mem=SAFE_NEW unsigned char[size];
memcpy(mem,old.mem,size);
}
CBitmap::CBitmap(unsigned char *data, int xsize, int ysize)
: xsize(xsize), ysize(ysize)
{
type = BitmapTypeStandardRGBA;
ddsimage = 0;
mem=SAFE_NEW unsigned char[xsize*ysize*4];
memcpy(mem,data,xsize*ysize*4);
}
CBitmap& CBitmap::operator=(const CBitmap& bm)
{
if( this != &bm ){
delete[] mem;
xsize=bm.xsize;
ysize=bm.ysize;
int size;
if(type == BitmapTypeStandardRGBA) size = xsize*ysize*4;
else size = xsize*ysize; // Alpha
mem=SAFE_NEW unsigned char[size];
memcpy(mem,bm.mem,size);
}
return *this;
}
void CBitmap::Alloc (int w,int h)
{
delete[] mem;
xsize=w;
ysize=h;
type=BitmapTypeStandardRGBA;
mem=SAFE_NEW unsigned char[w*h*4];
memset(mem, 0, w*h*4);
}
bool CBitmap::Load(string const& filename, unsigned char defaultAlpha)
{
bool noAlpha = true;
delete[] mem;
mem = NULL;
if(filename.find(".dds")!=string::npos){
ddsimage = SAFE_NEW nv_dds::CDDSImage();
type = BitmapTypeDDS;
return ddsimage->load(filename);
}
type = BitmapTypeStandardRGBA;
CFileHandler file(filename);
if(file.FileExists() == false)
{
Alloc(1,1);
return false;
}
unsigned char *buffer = SAFE_NEW unsigned char[file.FileSize()+2];
file.Read(buffer, file.FileSize());
#if defined(__APPLE__) // Use QuickTime to load images on Mac
mem = LoadTextureData(filename, buffer, file.FileSize(),
xsize, ysize, noAlpha);
// Chagne the *hasAlpha* used in LoadTextureData to *noAlpha*
noAlpha = !noAlpha;
delete[] buffer;
if (!mem) {
xsize = 1;
ysize = 1;
mem=SAFE_NEW unsigned char[4];
mem[0] = 255; // Red allows us to easily see textures that failed to load
mem[1] = 0;
mem[2] = 0;
mem[3] = 255; // Non Transparent
return;
}
// Because most of the algorithms that work on our texture are not generalized yet
// We have to convert the image into the same format (RGBA instead of ARGB[ppc] or BGRA[x86]).
// We then use the same OpenGL calls since they don't chagne between (windows or x86/ppc)
int max_pixels = xsize * ysize;
for (int i = 0; i < max_pixels; ++i) {
int base = i * 4;
// ARGB; temp = A; _RGB >> RGB_; A = temp; RGBA
char temp = mem[base + 0]; // A
mem[base + 0] = mem[base + 1]; // R
mem[base + 1] = mem[base + 2]; // G
mem[base + 2] = mem[base + 3]; // B
mem[base + 3] = temp; // A
}
#else // Use DevIL to load images on windows/linux/...
ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
ilEnable(IL_ORIGIN_SET);
ILuint ImageName = 0;
ilGenImages(1, &ImageName);
ilBindImage(ImageName);
const bool success = !!ilLoadL(IL_TYPE_UNKNOWN, buffer, file.FileSize());
delete [] buffer;
if(success == false)
{
xsize = 1;
ysize = 1;
mem=SAFE_NEW unsigned char[4];
mem[0] = 255; // Red allows us to easily see textures that failed to load
mem[1] = 0;
mem[2] = 0;
mem[3] = 255; // Non Transparent
return false;
}
noAlpha=ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL)!=4;
ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);
xsize = ilGetInteger(IL_IMAGE_WIDTH);
ysize = ilGetInteger(IL_IMAGE_HEIGHT);
mem = SAFE_NEW unsigned char[xsize * ysize * 4];
// ilCopyPixels(0,0,0,xsize,ysize,0,IL_RGBA,IL_UNSIGNED_BYTE,mem);
memcpy(mem, ilGetData(), xsize * ysize * 4);
ilDeleteImages(1, &ImageName);
#endif
if (noAlpha){
for (int y=0; y<ysize; ++y) {
for (int x=0; x<xsize; ++x) {
mem[((y*xsize+x) * 4) + 3] = defaultAlpha;
}
}
}
return true;
}
bool CBitmap::LoadGrayscale (const string& filename)
{
type = BitmapTypeStandardAlpha;
ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
ilEnable(IL_ORIGIN_SET);
CFileHandler file(filename);
if(!file.FileExists())
return false;
unsigned char *buffer = SAFE_NEW unsigned char[file.FileSize()+1];
file.Read(buffer, file.FileSize());
ILuint ImageName = 0;
ilGenImages(1, &ImageName);
ilBindImage(ImageName);
const bool success = !!ilLoadL(IL_TYPE_UNKNOWN, buffer, file.FileSize());
delete [] buffer;
if(success == false)
return false;
#if !defined(__APPLE__) // Temporary fix to allow testing of everything
// else until i get a quicktime image loader written
ilConvertImage(IL_LUMINANCE, IL_UNSIGNED_BYTE);
xsize = ilGetInteger(IL_IMAGE_WIDTH);
ysize = ilGetInteger(IL_IMAGE_HEIGHT);
mem = SAFE_NEW unsigned char[xsize * ysize];
memcpy(mem, ilGetData(), xsize * ysize);
#else
xsize = 4;
ysize = 4;
mem = SAFE_NEW unsigned char[xsize * ysize];
#endif
ilDeleteImages(1, &ImageName);
return true;
}
void CBitmap::Save(string const& filename)
{
if (type == BitmapTypeDDS) {
ddsimage->save(filename);
return;
}
#if !defined(__APPLE__) // Use devil on Windows/Linux/...
ilOriginFunc(IL_ORIGIN_UPPER_LEFT);
ilEnable(IL_ORIGIN_SET);
unsigned char* buf=SAFE_NEW unsigned char[xsize*ysize*4];
/* HACK Flip the image so it saves the right way up.
(Fiddling with ilOriginFunc didn't do anything?)
Duplicated with ReverseYAxis. */
for(int y=0;y<ysize;++y){
for(int x=0;x<xsize;++x){
buf[((ysize-1-y)*xsize+x)*4+0] = mem[((y)*xsize+x)*4+0];
buf[((ysize-1-y)*xsize+x)*4+1] = mem[((y)*xsize+x)*4+1];
buf[((ysize-1-y)*xsize+x)*4+2] = mem[((y)*xsize+x)*4+2];
buf[((ysize-1-y)*xsize+x)*4+3] = 0xff; // mem[((y)*xsize+x)*4+3];
}
}
ilHint(IL_COMPRESSION_HINT, IL_USE_COMPRESSION);
ilSetInteger (IL_JPG_QUALITY, 80);
ILuint ImageName = 0;
ilGenImages(1, &ImageName);
ilBindImage(ImageName);
ilTexImage(xsize,ysize,1,4,IL_RGBA,IL_UNSIGNED_BYTE,NULL);
ilSetData(buf);
ilSaveImage((char*)( filesystem.LocateFile(filename, FileSystem::WRITE).c_str() ));
ilDeleteImages(1,&ImageName);
delete[] buf;
#endif // I'll add a quicktime exporter for mac soonish...Krysole
}
#ifndef BITMAP_NO_OPENGL
unsigned int CBitmap::CreateTexture(bool mipmaps)
{
if(type == BitmapTypeDDS)
{
return CreateDDSTexture();
}
if(mem==NULL)
return 0;
// jcnossen: Some drivers return "2.0" as a version string,
// but switch to software rendering for non-power-of-two textures.
// GL_ARB_texture_non_power_of_two indicates that the hardware will actually support it.
if ((xsize != next_power_of_2(xsize) || ysize != next_power_of_2(ysize)) && !GLEW_ARB_texture_non_power_of_two)
//&& strcmp(reinterpret_cast<const char*>(glGetString(GL_VERSION)), "2.0") < 0 )
{
CBitmap bm = CreateRescaled(next_power_of_2(xsize), next_power_of_2(ysize));
return bm.CreateTexture(mipmaps);
}
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if(mipmaps)
{
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
// create mipmapped texture
if (GLEW_VERSION_1_4) {
// This required GL-1.4
// instead of using glu, we rely on glTexImage2D to create the Mipmaps.
glTexParameteri(GL_TEXTURE_2D,GL_GENERATE_MIPMAP,true);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8 ,xsize, ysize, 0,GL_RGBA, GL_UNSIGNED_BYTE, mem);
} else
gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA8 ,xsize, ysize,GL_RGBA, GL_UNSIGNED_BYTE, mem);
}
else
{
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
//glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8 ,xsize, ysize, 0,GL_RGBA, GL_UNSIGNED_BYTE, mem);
//gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA8 ,xsize, ysize, GL_RGBA, GL_UNSIGNED_BYTE, mem);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8 ,xsize, ysize, 0,GL_RGBA, GL_UNSIGNED_BYTE, mem);
}
return texture;
}
unsigned int CBitmap::CreateDDSTexture()
{
GLuint texobj;
glPushAttrib(GL_TEXTURE_BIT);
glGenTextures(1, &texobj);
switch(ddsimage->get_type())
{
case nv_dds::TextureNone:
glDeleteTextures(1, &texobj);
texobj = 0;
break;
case nv_dds::TextureFlat: // 1D, 2D, and rectangle textures
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texobj);
if(!ddsimage->upload_texture2D()) {
glDeleteTextures(1, &texobj);
texobj = 0;
}
break;
case nv_dds::Texture3D:
glEnable(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D, texobj);
if(!ddsimage->upload_texture3D()) {
glDeleteTextures(1, &texobj);
texobj = 0;
}
break;
case nv_dds::TextureCubemap:
glEnable(GL_TEXTURE_CUBE_MAP_ARB);
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, texobj);
if(!ddsimage->upload_textureCubemap()) {
glDeleteTextures(1, &texobj);
texobj = 0;
}
break;
default:
assert(false);
break;
}
glPopAttrib();
return texobj;
}
#endif // !BITMAP_NO_OPENGL
void CBitmap::CreateAlpha(unsigned char red,unsigned char green,unsigned char blue)
{
float3 aCol;
for(int a=0;a<3;++a)
{
int cCol=0;
int numCounted=0;
for(int y=0;y<ysize;++y){
for(int x=0;x<xsize;++x){
if(mem[(y*xsize+x)*4+3]!=0 && !(mem[(y*xsize+x)*4+0]==red && mem[(y*xsize+x)*4+1]==green && mem[(y*xsize+x)*4+2]==blue)){
cCol+=mem[(y*xsize+x)*4+a];
++numCounted;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?