/// <summary> /// リージョンを作成する /// </summary> private unsafe Region InnerMakeRegion(bool bColorKey, uint r, uint g, uint b) { if (!Alpha && !SDLColorKey.HasValue && !bColorKey) { // αとかカラーキーが無いならどうにも出来ないので。。 return(null); } Region region = new Region(new Rectangle(0, 0, 0, 0)); // ↑ region = new Region(); では上手くいかない。何でだろ?(´ω`) using (Surface dupSurface = new Surface()) { Surface src; // RGB888とか以外の形式なら変換する if (Alpha && !CheckARGB8888()) { dupSurface.CreateDIB(Width, Height, true); dupSurface.Blt(this, 0, 0); src = dupSurface; } else if (!Alpha && !CheckRGB888()) { dupSurface.CreateDIB(Width, Height, false); dupSurface.Blt(this, 0, 0); src = dupSurface; } else { src = this; } if (bColorKey || SDLColorKey != null) { uint colorKeyMask = SDL.SDL_BYTEORDER.Equals(SDL.SDL_BIG_ENDIAN) ? 0xffffff00 : 0x00ffffff; // カラーキーの取得 uint colorKey; if (src.SDLColorKey.HasValue) { colorKey = (uint)src.SDLColorKey.Value & colorKeyMask; } else // if (bColorKey) { colorKey = SDL.SDL_BYTEORDER.Equals(SDL.SDL_BIG_ENDIAN) ? b + (g << 8) + (r << 16) : (b << 16) + (g << 8) + r; } byte *pixels = (byte *)Pixels; int bytePerPixel = Alpha ? 4 : 3; // こうやっちゃうと各ピクセル毎にかけ算になっちゃうが。。 for (int y = 0, h = Height, w = Width; y < h; y++) { int startX = -1; for (int x = 0; x < w; x++) { uint pixel = *(uint *)(pixels + x * bytePerPixel); if ((pixel & colorKeyMask) == colorKey) { // カラーキーなら透過させる if (0 <= startX) { region.Union(new Rectangle(startX, y, x - startX, 1)); startX = -1; } } else { if (startX < 0) { startX = x; } } } if (0 <= startX) { region.Union(new Rectangle(startX, y, w - startX, 1)); //startX = -1; } pixels += Pitch; } } else // if (Alpha) { // α値による処理 uint alphaMask = SDL.SDL_BYTEORDER.Equals(SDL.SDL_BIG_ENDIAN) ? 0x000000ff : 0xff000000; uint *pixels = (uint *)Pixels; for (int y = 0, h = Height, w = Width; y < h; y++) { int startX = -1; for (int x = 0; x < w; x++) { if ((pixels[x] & alphaMask) != alphaMask) { // α != 255なら透過させる if (0 <= startX) { region.Union(new Rectangle(startX, y, x - startX, 1)); startX = -1; } } else { if (startX < 0) { startX = x; } } } if (0 <= startX) { region.Union(new Rectangle(startX, y, w - startX, 1)); //startX = -1; } pixels += Pitch / sizeof(uint); } } } return(region); }
/// <summary> /// リージョンを作成する /// </summary> private unsafe Region InnerMakeRegion(bool bColorKey, uint r, uint g, uint b) { if (!Alpha && !SDLColorKey.HasValue && !bColorKey) { // αとかカラーキーが無いならどうにも出来ないので。。 return null; } Region region = new Region(new Rectangle(0, 0, 0, 0)); // ↑ region = new Region(); では上手くいかない。何でだろ?(´ω`) using (Surface dupSurface = new Surface()) { Surface src; // RGB888とか以外の形式なら変換する if (Alpha && !CheckARGB8888()) { dupSurface.CreateDIB(Width, Height, true); dupSurface.Blt(this, 0, 0); src = dupSurface; } else if (!Alpha && !CheckRGB888()) { dupSurface.CreateDIB(Width, Height, false); dupSurface.Blt(this, 0, 0); src = dupSurface; } else { src = this; } if (bColorKey || SDLColorKey != null) { uint colorKeyMask = SDL.SDL_BYTEORDER.Equals(SDL.SDL_BIG_ENDIAN) ? 0xffffff00 : 0x00ffffff; // カラーキーの取得 uint colorKey; if (src.SDLColorKey.HasValue) { colorKey = (uint)src.SDLColorKey.Value & colorKeyMask; } else // if (bColorKey) { colorKey = SDL.SDL_BYTEORDER.Equals(SDL.SDL_BIG_ENDIAN) ? b + (g << 8) + (r << 16) : (b << 16) + (g << 8) + r; } byte* pixels = (byte*)Pixels; int bytePerPixel = Alpha ? 4 : 3; // こうやっちゃうと各ピクセル毎にかけ算になっちゃうが。。 for (int y = 0, h = Height, w = Width; y < h; y++) { int startX = -1; for (int x = 0; x < w; x++) { uint pixel = *(uint*)(pixels + x * bytePerPixel); if ((pixel & colorKeyMask) == colorKey) { // カラーキーなら透過させる if (0 <= startX) { region.Union(new Rectangle(startX, y, x - startX, 1)); startX = -1; } } else { if (startX < 0) { startX = x; } } } if (0 <= startX) { region.Union(new Rectangle(startX, y, w - startX, 1)); //startX = -1; } pixels += Pitch; } } else // if (Alpha) { // α値による処理 uint alphaMask = SDL.SDL_BYTEORDER.Equals(SDL.SDL_BIG_ENDIAN) ? 0x000000ff : 0xff000000; uint* pixels = (uint*)Pixels; for (int y = 0, h = Height, w = Width; y < h; y++) { int startX = -1; for (int x = 0; x < w; x++) { if ((pixels[x] & alphaMask) != alphaMask) { // α != 255なら透過させる if (0 <= startX) { region.Union(new Rectangle(startX, y, x - startX, 1)); startX = -1; } } else { if (startX < 0) { startX = x; } } } if (0 <= startX) { region.Union(new Rectangle(startX, y, w - startX, 1)); //startX = -1; } pixels += Pitch / sizeof(uint); } } } return region; }
/// <summary> /// サーフェースをセットする。 /// </summary> /// <param name="surface"></param> /// <param name="bKeepSurface">trueであれば元のSurfaceを破壊しないことを保証する。</param> /// <returns></returns> unsafe private YanesdkResult InnerSetSurface(Surface surface, bool bKeepSurface) { if (surface == null) { return(YanesdkResult.InvalidParameter); } sizeX = surface.Width; sizeY = surface.Height; if (sizeX == 0 || sizeY == 0) { sizeX = sizeY = 0; return(YanesdkResult.PreconditionError); // おかしい.. } // NPOTを使ったのか? // bool npot = false; // TxRcを使ったのか? bool txrc = false; // GL_TEXTURE_RECTANGLE_ARBが使える状況なら積極的に使う。 // GL_TEXTURE_RECTANGLE_ARBが使えずにNPOT拡張が使えるというのは // あまり考えにくいのだが(´ω`) if (localOption.TxRc && GlExtensions.Instance.IsAvailableRectTexture(sizeX, sizeY)) { textureType = Gl.GL_TEXTURE_RECTANGLE_ARB; sizeRX = sizeX; sizeRY = sizeY; // 非正規化テクスチャなのでテクスチャ座標は // (0,0)×(1,1)の座標系ではなく、 // (0,0)×(sizeRX,sizeRY)の座標系になる。 widthRate = (float)sizeX; heightRate = (float)sizeY; // ↓これ本来どこで呼び出すのが正しいんだろ。(´ω`) // Gl.glEnable(Gl.GL_TEXTURE_RECTANGLE_ARB); // ↑draw contextを切り替えたときにうまく動く必要がある // bindするときに指定すべき。 txrc = true; } else { if (localOption.NPOT && GlExtensions.Instance.NPOT) { // NPOT拡張が使えるなら使う。 // 2の累乗サイズのテクスチャでなくとも構わないならそうしたほうが // ビデオメモリの節約になって大変良い(´ー`)v // 2の累乗じゃなくてもいいならぴったりサイズで作成。 sizeRX = sizeX; sizeRY = sizeY; // npot = true; } else { sizeRX = Floor(sizeX); sizeRY = Floor(sizeY); } textureType = Gl.GL_TEXTURE_2D; widthRate = ((float)sizeX) / sizeRX; heightRate = ((float)sizeY) / sizeRY; } using (Surface dupSurface = new Surface()) { // 複製を作成するかのフラグ bool bDup = false; // カラーキーが指定されているのか bool bColorKey = colorKey.ColorKeyType != ColorKeyType.None || surface.SDLColorKey != null; // α付きのサーフェースを作成する必要があるのか? bool bAlpha = surface.Alpha || bColorKey; // colorkeyの実現のために元のサーフェースを書き換えるので // 複製をとる必要がある。 if (bColorKey && bKeepSurface) { bDup = true; } if (!bAlpha) { if (!surface.CheckRGB888() || sizeX != sizeRX || sizeY != sizeRY) { bDup = true; } } else { if (!surface.CheckARGB8888() || sizeX != sizeRX || sizeY != sizeRY) { bDup = true; } } // 複製を作成するのか if (bDup) { // bDupフラグが立っていれば無条件に複製する dupSurface.CreateDIB(sizeRX, sizeRY, bAlpha /* surface.Alpha*/); dupSurface.Blt(surface, 0, 0); } /* // 書き換える例) * SDL_Surface* s = dupSurface.getSurface(); * SDL_LockSurface(s); * * for(int i=0;i < s.w * s.h ; ++i){ * ((ubyte*)s.pixels)[i*4 + 3] = 255; * } * * SDL_UnlockSurface(s); */ if (bColorKey) { // カラーキーが有効なので、カラーキーの該当部分のαを0に // 書き換えていく作業が必要となる。(気が遠くなりそう…) uint colorKeyMask = SDL.SDL_BYTEORDER.Equals(SDL.SDL_BIG_ENDIAN) ? 0xffffff00 : 0x00ffffff; uint *p0 = (uint *) (bDup ? dupSurface.Pixels : surface.Pixels); if (colorKey.ColorKeyType != ColorKeyType.None) { uint *p = p0; uint colorKeyValue; if (colorKey.ColorKeyType == ColorKeyType.ColorKeyRGB) { int r = colorKey.R; int g = colorKey.G; int b = colorKey.B; colorKeyValue = (uint) (SDL.SDL_BYTEORDER.Equals(SDL.SDL_BIG_ENDIAN) ? b + (g << 8) + (r << 16) : (b << 16) + (g << 8) + r); } else { int cx = colorKey.CX; int cy = colorKey.CY; if (cx < sizeX && cy < sizeY) { colorKeyValue = p[cx + cy * sizeRX] & colorKeyMask; } else { // 範囲外だとダメじゃん.. goto exitColorKey; } } for (int y = 0; y < sizeY; ++y) { for (int x = 0; x < sizeX; ++x) { uint data = p[x]; if ((data & colorKeyMask) == colorKeyValue) { p[x] = colorKeyValue; // α=0なので抜きを意味する } } p += sizeRX; // 1ラスタ送る } } // SDLのBltは、転送先がα付きで転送元がColorKeyが指定されていれば // ColorKeyが指定されている部分は転送されない == その部分のαは0となる。 /* * if (surface.ColorKey != null) * { * uint colorKey = (uint)surface.ColorKey; * * uint* p = p0; * for (int y = 0; y < sizeY; ++y) * { * for (int x = 0; x < sizeX; ++x) * { * uint data = p[x]; * if ((data & colorKeyMask) == colorKey) * { * p[x] = colorKey; // α=0なので抜きを意味する * } * } * p += sizeRX; // 1ラスタ送る * } * } */ } exitColorKey: // textureの生成 fixed(uint *p = &textureName) { Gl.glGenTextures(1, (IntPtr)p); } // textureNameは1から割り当てられると考えられる。 // 0が返ってきたら、割り当てに失敗していると思うのだが。 if (textureName == 0) { // これ 割り当て失敗でね? this.Release(); return(YanesdkResult.HappenSomeError); } // bind loaded = true; // これをtrueにしておかないとbindできない Bind(); uint internalformat = bAlpha ? Gl.GL_RGBA : Gl.GL_RGB; { // テクスチャ圧縮を用いるのか? bool s3tc = localOption.S3TC; bool fxt1 = localOption.FXT1; GlExtensions exts = GlExtensions.Instance; // テクスチャ圧縮を行ないたい場合 if ((s3tc || fxt1) // && !npot // s3tcはnpotとは併用できる && !txrc && // s3tcはTxRcとは併用できない exts.IsAvailable("GL_ARB_texture_compression")) { // S3TCが使えるのか? if (s3tc && exts.IsAvailable("GL_EXT_texture_compression_s3tc")) { internalformat = bAlpha ? Gl.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT : Gl.GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // // RGBAの方は、DXT1、DXT3、DXT5の3種類があり、 // DXT1はαが1ビットらしいので除外するとしても、 // DXT3はα値が急激に変化するフォントなどに向いていて、 // DXT5はグラデーションなどの、α値が緩やかに変化する場合に向いている…らしい。 // // まぁ、あんまり深く考えずにどちらか決めうちでいい気も。。(´ω`) // } // FXT1が使えるのか? else if (fxt1 && exts.IsAvailable("GL_3DFX_texture_compression_FXT1")) { internalformat = bAlpha ? Gl.GL_COMPRESSED_RGBA_FXT1_3DFX : Gl.GL_COMPRESSED_RGB_FXT1_3DFX; } } } IntPtr v = bDup ? dupSurface.Pixels : surface.Pixels; Gl.glTexImage2D(textureType, 0, // texture level (int)internalformat, sizeRX, sizeRY, 0, // texture境界は存在しない bAlpha ? Gl.GL_RGBA : Gl.GL_RGB, // α付き画像ならば GL_RGBAを指定する Gl.GL_UNSIGNED_BYTE, v ); uint error = Gl.glGetError(); global::System.Diagnostics.Debug.Assert(error == Gl.GL_NO_ERROR , Glu.gluErrorString(error)); if (error != 0) { Unbind(); this.Release(); return(YanesdkResult.HappenSomeError); } int option = (int)(localOption.Smooth ? Gl.GL_LINEAR : Gl.GL_NEAREST); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, option); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, option); // surface.Dispose(); // 画像もったいないから解放しておく // ここではなくて、どこか適切な場所でするべき…か。 this.alpha = bAlpha; Unbind(); } // dupSurface.Dispose(); // no more needed return(YanesdkResult.NoError); }
/// <summary> /// サーフェースをセットする。 /// </summary> /// <param name="surface"></param> /// <param name="bKeepSurface">trueであれば元のSurfaceを破壊しないことを保証する。</param> /// <returns></returns> private unsafe YanesdkResult InnerSetSurface(Surface surface, bool bKeepSurface) { if (surface == null) { return YanesdkResult.InvalidParameter; } sizeX = surface.Width; sizeY = surface.Height; if (sizeX == 0 || sizeY == 0) { sizeX = sizeY = 0; return YanesdkResult.PreconditionError; // おかしい.. } // NPOTを使ったのか? // bool npot = false; // TxRcを使ったのか? bool txrc = false; // GL_TEXTURE_RECTANGLE_ARBが使える状況なら積極的に使う。 // GL_TEXTURE_RECTANGLE_ARBが使えずにNPOT拡張が使えるというのは // あまり考えにくいのだが(´ω`) if (localOption.TxRc && GlExtensions.Instance.IsAvailableRectTexture(sizeX, sizeY)) { textureType = Gl.GL_TEXTURE_RECTANGLE_ARB; sizeRX = sizeX; sizeRY = sizeY; // 非正規化テクスチャなのでテクスチャ座標は // (0,0)×(1,1)の座標系ではなく、 // (0,0)×(sizeRX,sizeRY)の座標系になる。 widthRate = (float)sizeX; heightRate = (float)sizeY; // ↓これ本来どこで呼び出すのが正しいんだろ。(´ω`) // Gl.glEnable(Gl.GL_TEXTURE_RECTANGLE_ARB); // ↑draw contextを切り替えたときにうまく動く必要がある // bindするときに指定すべき。 txrc = true; } else { if (localOption.NPOT && GlExtensions.Instance.NPOT) { // NPOT拡張が使えるなら使う。 // 2の累乗サイズのテクスチャでなくとも構わないならそうしたほうが // ビデオメモリの節約になって大変良い(´ー`)v // 2の累乗じゃなくてもいいならぴったりサイズで作成。 sizeRX = sizeX; sizeRY = sizeY; // npot = true; } else { sizeRX = Floor(sizeX); sizeRY = Floor(sizeY); } textureType = Gl.GL_TEXTURE_2D; widthRate = ((float)sizeX) / sizeRX; heightRate = ((float)sizeY) / sizeRY; } using (Surface dupSurface = new Surface()) { // 複製を作成するかのフラグ bool bDup = false; // カラーキーが指定されているのか bool bColorKey = colorKey.ColorKeyType != ColorKeyType.None || surface.SDLColorKey != null; // α付きのサーフェースを作成する必要があるのか? bool bAlpha = surface.Alpha || bColorKey; // colorkeyの実現のために元のサーフェースを書き換えるので // 複製をとる必要がある。 if (bColorKey && bKeepSurface) bDup = true; if (!bAlpha) { if (!surface.CheckRGB888() || sizeX != sizeRX || sizeY != sizeRY) bDup = true; } else { if (!surface.CheckARGB8888() || sizeX != sizeRX || sizeY != sizeRY) bDup = true; } // 複製を作成するのか if (bDup) { // bDupフラグが立っていれば無条件に複製する dupSurface.CreateDIB(sizeRX, sizeRY, bAlpha /* surface.Alpha*/ ); dupSurface.Blt(surface, 0, 0); } /* // 書き換える例) SDL_Surface* s = dupSurface.getSurface(); SDL_LockSurface(s); for(int i=0;i < s.w * s.h ; ++i){ ((ubyte*)s.pixels)[i*4 + 3] = 255; } SDL_UnlockSurface(s); */ if (bColorKey) { // カラーキーが有効なので、カラーキーの該当部分のαを0に // 書き換えていく作業が必要となる。(気が遠くなりそう…) uint colorKeyMask = SDL.SDL_BYTEORDER.Equals(SDL.SDL_BIG_ENDIAN) ? 0xffffff00 : 0x00ffffff; uint* p0 = (uint*) (bDup ? dupSurface.Pixels : surface.Pixels); if (colorKey.ColorKeyType != ColorKeyType.None) { uint* p = p0; uint colorKeyValue; if (colorKey.ColorKeyType == ColorKeyType.ColorKeyRGB) { int r = colorKey.R; int g = colorKey.G; int b = colorKey.B; colorKeyValue = (uint) (SDL.SDL_BYTEORDER.Equals(SDL.SDL_BIG_ENDIAN) ? b + (g << 8) + (r << 16) : (b << 16) + (g << 8) + r); } else { int cx = colorKey.CX; int cy = colorKey.CY; if (cx < sizeX && cy < sizeY) { colorKeyValue = p[cx + cy * sizeRX] & colorKeyMask; } else { // 範囲外だとダメじゃん.. goto exitColorKey; } } for (int y = 0; y < sizeY; ++y) { for (int x = 0; x < sizeX; ++x) { uint data = p[x]; if ((data & colorKeyMask) == colorKeyValue) { p[x] = colorKeyValue; // α=0なので抜きを意味する } } p += sizeRX; // 1ラスタ送る } } // SDLのBltは、転送先がα付きで転送元がColorKeyが指定されていれば // ColorKeyが指定されている部分は転送されない == その部分のαは0となる。 /* if (surface.ColorKey != null) { uint colorKey = (uint)surface.ColorKey; uint* p = p0; for (int y = 0; y < sizeY; ++y) { for (int x = 0; x < sizeX; ++x) { uint data = p[x]; if ((data & colorKeyMask) == colorKey) { p[x] = colorKey; // α=0なので抜きを意味する } } p += sizeRX; // 1ラスタ送る } } */ } exitColorKey: // textureの生成 fixed (uint* p = &textureName) { Gl.glGenTextures(1, (IntPtr)p); } // textureNameは1から割り当てられると考えられる。 // 0が返ってきたら、割り当てに失敗していると思うのだが。 if (textureName == 0) { // これ 割り当て失敗でね? this.Release(); return YanesdkResult.HappenSomeError; } // bind loaded = true; // これをtrueにしておかないとbindできない Bind(); uint internalformat = bAlpha ? Gl.GL_RGBA : Gl.GL_RGB; { // テクスチャ圧縮を用いるのか? bool s3tc = localOption.S3TC; bool fxt1 = localOption.FXT1; GlExtensions exts = GlExtensions.Instance; // テクスチャ圧縮を行ないたい場合 if ((s3tc || fxt1) // && !npot // s3tcはnpotとは併用できる && !txrc // s3tcはTxRcとは併用できない && exts.IsAvailable("GL_ARB_texture_compression")) { // S3TCが使えるのか? if (s3tc && exts.IsAvailable("GL_EXT_texture_compression_s3tc")) { internalformat = bAlpha ? Gl.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT : Gl.GL_COMPRESSED_RGB_S3TC_DXT1_EXT; // // RGBAの方は、DXT1、DXT3、DXT5の3種類があり、 // DXT1はαが1ビットらしいので除外するとしても、 // DXT3はα値が急激に変化するフォントなどに向いていて、 // DXT5はグラデーションなどの、α値が緩やかに変化する場合に向いている…らしい。 // // まぁ、あんまり深く考えずにどちらか決めうちでいい気も。。(´ω`) // } // FXT1が使えるのか? else if (fxt1 && exts.IsAvailable("GL_3DFX_texture_compression_FXT1")) { internalformat = bAlpha ? Gl.GL_COMPRESSED_RGBA_FXT1_3DFX : Gl.GL_COMPRESSED_RGB_FXT1_3DFX; } } } IntPtr v = bDup ? dupSurface.Pixels : surface.Pixels; Gl.glTexImage2D(textureType, 0, // texture level (int)internalformat, sizeRX, sizeRY, 0, // texture境界は存在しない bAlpha ? Gl.GL_RGBA : Gl.GL_RGB, // α付き画像ならば GL_RGBAを指定する Gl.GL_UNSIGNED_BYTE, v ); uint error = Gl.glGetError(); global::System.Diagnostics.Debug.Assert(error == Gl.GL_NO_ERROR ,Glu.gluErrorString(error) ); if (error != 0) { Unbind(); this.Release(); return YanesdkResult.HappenSomeError; } int option = (int)(localOption.Smooth ? Gl.GL_LINEAR : Gl.GL_NEAREST); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, option); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, option); // surface.Dispose(); // 画像もったいないから解放しておく // ここではなくて、どこか適切な場所でするべき…か。 this.alpha = bAlpha; Unbind(); } // dupSurface.Dispose(); // no more needed return YanesdkResult.NoError; }