MipmapCreate() 的第一個參數 Mipmap 用於回傳 Mipmap 所有圖層的陣列,格式為
{第 0 層圖片的指標, 第 1 層圖片的指標, ... 第 LevelNum-1 層圖片的指標}
第二個參數 WidthHeight 用於回傳各層圖片的長寬,格式為
{
第 0 層圖片的 Width, 第 0 層圖片的 Height,
...
第 LevelNum-1 層圖片的 Width, 第 LevelNum-1 層圖片的 Height
}
第三個參數 LevelNum 用於回傳建立的層數
MipmapDelete() 用於正確的刪除 MipmapCreate() 建立的所有資料
// 由 MipmapCreate() 叫用
// 產生各層的縮小圖片,直至 1*1
void MipmapCreateX(unsigned char **Mipmaps, unsigned int *WidthHeight,
const unsigned int LevelNum, const unsigned char *SrcMap,
const unsigned int SrcWidth, const unsigned int SrcHeight,
const unsigned int bpp)
{
unsigned int Level = 1; // 從第 2 層開始建立,第一層為 0
const unsigned char *PreSrcMap = SrcMap;
unsigned int PreSrcWidth = SrcWidth;
unsigned int PreSrcHeight = SrcHeight;
while(Level < LevelNum)
{
unsigned int Width = PreSrcWidth / 2 + PreSrcWidth % 2;
unsigned int Height = PreSrcHeight / 2 + PreSrcHeight % 2;
unsigned int NumberOfPixels = Width * Height;
unsigned int n=0, X=0, Y=0;
WidthHeight[Level * 2] = Width;
WidthHeight[Level * 2 + 1] = Height;
unsigned char *Pixels = new unsigned char[NumberOfPixels * bpp];
Mipmaps[Level] = Pixels;
while(n < NumberOfPixels)
{
unsigned char *p = Pixels + n*bpp;
const unsigned char *s = PreSrcMap + (Y*PreSrcWidth + X)*bpp;
if(Y < PreSrcHeight-1 && X < PreSrcWidth-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b]/4 + s[b+bpp]/4 + s[b+PreSrcWidth*bpp]/4 +
s[b+PreSrcWidth*bpp+bpp]/4;
X+=2;
if(X == PreSrcWidth)
{
X = 0; Y+=2;
}
}
else if(X < PreSrcWidth-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b]/2 + s[b+bpp]/2;
X+=2;
}
else if(Y < PreSrcHeight-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b]/2 + s[b+PreSrcWidth*bpp]/2;
X=0;
Y+=2;
}
else // if(Y == PreSrcHeight-1 && X == PreSrcWidth-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b];
}
++n;
}
++Level;
PreSrcMap = Pixels;
PreSrcWidth = Width;
PreSrcHeight = Height;
}
}
/*
用 max(Width,Height) 來算
2^(n+1) 比 2^n 多一層
2^n + 1 比 2^n 多一層
所以 2^n + 1 至 2^(n+1) 比 2^n 多一層
*/
unsigned int CalculateLevelNum(unsigned int len)
{
bool b = false;
unsigned int LevelNum = 1;
unsigned int Len = len;
unsigned int t;
while((t = Len >> 1))
{
++LevelNum;
b = (Len&1)? true:b;
Len = t;
}
return (b)?LevelNum+1:LevelNum;
}
// 長寬皆不能為 0,否則回覆 false
// SrcMap 須指向以 byte 為單位,為每個像素做分色的圖片
// bpp 表示每個像素的 byte 數,比如 rgba 為 4,rgb 為 3
bool MipmapCreate(unsigned char ***Mipmap, unsigned int **WidthHeight,
unsigned int *LevelNum,
const unsigned char *SrcMap, const unsigned int SrcWidth,
const unsigned int SrcHeight, const unsigned int bpp)
{
if(SrcWidth == 0 || SrcHeight == 0)
return false;
if(SrcWidth > SrcHeight)
*LevelNum = CalculateLevelNum(SrcWidth);
else
*LevelNum = CalculateLevelNum(SrcHeight);
unsigned int NumberOfPixels = SrcWidth * SrcHeight;
*Mipmap = new unsigned char *[*LevelNum];
*WidthHeight = new unsigned int[(*LevelNum) * 2];
(*WidthHeight)[0] = SrcWidth;
(*WidthHeight)[1] = SrcHeight;
unsigned char *Pixels = new unsigned char[NumberOfPixels * bpp];
(*Mipmap)[0] = Pixels;
// 先複製第 1 層
for(unsigned int n=0, X=0, Y=0; n < NumberOfPixels; ++n)
{
unsigned char *p = Pixels + n*bpp;
const unsigned char *s = SrcMap + (X + Y * SrcWidth) * bpp;
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b];
if(++X == SrcWidth)
{
X = 0;
++Y;
}
}
MipmapCreateX(*Mipmap,*WidthHeight,*LevelNum,Pixels,SrcWidth,SrcHeight,bpp);
return true;
}
void MipmapDelete(unsigned char **Mipmap, unsigned int *WidthHeight,
unsigned int LevelNum)
{
delete [] WidthHeight;
for(unsigned int n = 0; n < LevelNum; ++n)
delete [] Mipmap[n];
delete [] Mipmap;
}
int main()
{
unsigned int bpp = 4;
unsigned int MapWidth = 3;
unsigned int MapHeight = 2;
unsigned char *Map = new unsigned char[MapWidth*MapHeight*bpp]; // 實務上應載入圖檔
unsigned char **Mipmap;
unsigned int *WidthHeight;
unsigned int LevelNum;
if(MipmapCreate(&Mipmap, &WidthHeight, &LevelNum, Map, MapWidth, MapHeight, bpp))
MipmapDelete(Mipmap, WidthHeight, LevelNum);
delete [] Map;
return 0;
}
-------------------------------------------------------------------
上面的程式碼發現在 OpenGL 和 D3D 皆不能用,只好修一下,若 Ext 指定為 false,將以 OpenGL 和 D3D 的方式做縮減,但這方法每次縮小若 n%2 不等於 0,會捨棄最後的邊
// 由 MipmapCreate() 叫用
// 產生各層的縮小圖片,直至 1*1
static void MipmapCreateX(unsigned char **Mipmaps, unsigned int *WidthHeight,
const unsigned int LevelNum,
const unsigned char *SrcMap, const unsigned int SrcWidth,
const unsigned int SrcHeight, const unsigned int bpp)
{
unsigned int Level = 1; // 從第 2 層開始建立,第一層為 0
const unsigned char *PreSrcMap = SrcMap;
unsigned int PreSrcWidth = SrcWidth;
unsigned int PreSrcHeight = SrcHeight;
while(Level < LevelNum)
{
unsigned int Width = PreSrcWidth / 2 + (PreSrcWidth & 1);
unsigned int Height = PreSrcHeight / 2 + (PreSrcHeight & 1);
unsigned int NumberOfPixels = Width * Height;
unsigned int n=0, X=0, Y=0;
WidthHeight[Level * 2] = Width;
WidthHeight[Level * 2 + 1] = Height;
unsigned char *Pixels = new unsigned char[NumberOfPixels * bpp];
Mipmaps[Level] = Pixels;
while(n < NumberOfPixels)
{
unsigned char *p = Pixels + n*bpp;
const unsigned char *s = PreSrcMap + (Y*PreSrcWidth + X)*bpp;
if(Y < PreSrcHeight-1 && X < PreSrcWidth-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b]/4 + s[b+bpp]/4 + s[b+PreSrcWidth*bpp]/4 +
s[b+PreSrcWidth*bpp+bpp]/4;
X+=2;
if(X == PreSrcWidth)
{
X = 0; Y+=2;
}
}
else if(X < PreSrcWidth-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b]/2 + s[b+bpp]/2;
X+=2;
}
else if(Y < PreSrcHeight-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b]/2 + s[b+PreSrcWidth*bpp]/2;
X=0;
Y+=2;
}
else // if(Y == PreSrcHeight-1 && X == PreSrcWidth-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b];
}
++n;
}
++Level;
PreSrcMap = Pixels;
PreSrcWidth = Width;
PreSrcHeight = Height;
}
}
// 由 MipmapCreate() 叫用
// 產生各層的縮小圖片,直至 1*1
static void MipmapCreateX2(unsigned char **Mipmaps, unsigned int *WidthHeight,
const unsigned int LevelNum,
const unsigned char *SrcMap, const unsigned int SrcWidth,
const unsigned int SrcHeight, const unsigned int bpp)
{
unsigned int Level = 1; // 從第 2 層開始建立,第一層為 0
const unsigned char *PreSrcMap = SrcMap;
unsigned int PreSrcWidth = SrcWidth;
unsigned int PreSrcHeight = SrcHeight;
while(Level < LevelNum)
{
bool Xodd = PreSrcWidth & 1;
// bool Yodd = PreSrcHeight & 1;
unsigned int Width = (PreSrcWidth>1)? PreSrcWidth/2 : 1;
unsigned int Height = (PreSrcHeight>1)? PreSrcHeight/2 : 1;
unsigned int NumberOfPixels = Width * Height;
unsigned int n=0, X=0, Y=0;
WidthHeight[Level * 2] = Width;
WidthHeight[Level * 2 + 1] = Height;
unsigned char *Pixels = new unsigned char[NumberOfPixels * bpp];
Mipmaps[Level] = Pixels;
while(n < NumberOfPixels)
{
unsigned char *p = Pixels + n*bpp;
const unsigned char *s = PreSrcMap + (Y*PreSrcWidth + X)*bpp;
if(Y < PreSrcHeight-1 && X < PreSrcWidth-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b]/4 + s[b+bpp]/4 + s[b+PreSrcWidth*bpp]/4 +
s[b+PreSrcWidth*bpp+bpp]/4;
X+=2;
if(X == PreSrcWidth || (Xodd && X == PreSrcWidth-1))
{
X = 0; Y+=2;
}
}
else if(X < PreSrcWidth-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b]/2 + s[b+bpp]/2;
X+=2;
}
else // if(Y < PreSrcHeight-1)
{
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b]/2 + s[b+PreSrcWidth*bpp]/2;
//X=0;
Y+=2;
}
++n;
}
++Level;
PreSrcMap = Pixels;
PreSrcWidth = Width;
PreSrcHeight = Height;
}
}
/*
用 max(Width,Height) 來算有多少層
log2() 為 2 的對數
int() 為取整數部份
if Ext == true
2^(n+1) 比 2^n 多一層
2^n + 1 比 2^n 多一層
所以 2^n + 1 至 2^(n+1) 比 2^n 多一層
int(log2(len))+1 層 (log2(len) 無小數)
或
int(log2(len))+1+1 層 (log2(len) 有小數)
if Ext == false
只計算 int(log2(len))+1 層
*/
unsigned int CalculateLevelNum(const unsigned int len, const bool Ext)
{
bool b = false;
unsigned int LevelNum = 1;
unsigned int Len = len;
unsigned int t;
while((t = Len >> 1))
{
++LevelNum;
b = (Ext && Len&1)? true:b;
Len = t;
}
return (b)?LevelNum+1:LevelNum;
}
// 長寬皆不能為 0,否則回覆 false
// SrcMap 須指向以 byte 為單位,為每個像素做分色的圖片
// bpp 表示每個像素的 byte 數,比如 rgba 為 4,rgb 為 3
bool MipmapCreate(unsigned char ***Mipmap, unsigned int **WidthHeight,
unsigned int *LevelNum,
const unsigned char *SrcMap, const unsigned int SrcWidth,
const unsigned int SrcHeight, const unsigned int bpp,
const bool Ext = false)
{
if(SrcWidth == 0 || SrcHeight == 0)
return false;
if(SrcWidth > SrcHeight)
*LevelNum = CalculateLevelNum(SrcWidth, Ext);
else
*LevelNum = CalculateLevelNum(SrcHeight, Ext);
unsigned int NumberOfPixels = SrcWidth * SrcHeight;
*Mipmap = new unsigned char *[*LevelNum];
*WidthHeight = new unsigned int[(*LevelNum) * 2];
(*WidthHeight)[0] = SrcWidth;
(*WidthHeight)[1] = SrcHeight;
unsigned char *Pixels = new unsigned char[NumberOfPixels * bpp];
(*Mipmap)[0] = Pixels;
// 先複製第 1 層
for(unsigned int n=0, X=0, Y=0; n < NumberOfPixels; ++n)
{
unsigned char *p = Pixels + n*bpp;
const unsigned char *s = SrcMap + (X + Y * SrcWidth) * bpp;
for(unsigned int b = 0; b < bpp; ++b)
p[b] = s[b];
if(++X == SrcWidth)
{
X = 0;
++Y;
}
}
if(Ext)
MipmapCreateX(*Mipmap,*WidthHeight,*LevelNum,Pixels,SrcWidth,SrcHeight,bpp);
else
MipmapCreateX2(*Mipmap,*WidthHeight,*LevelNum,Pixels,SrcWidth,SrcHeight,bpp);
return true;
}
// 用於正確的刪除 MipmapCreate() 建立的所有資料
void MipmapDelete(unsigned char **Mipmap, unsigned int *WidthHeight,
unsigned int LevelNum)
{
delete [] WidthHeight;
for(unsigned int n = 0; n < LevelNum; ++n)
delete [] Mipmap[n];
delete [] Mipmap;
}
沒有留言:
張貼留言