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 + -
显示快捷键?