/// <summary> /// Bitmap画像をSurfaceに変換(このあとTexture化したりするのに使える) /// </summary> /// <param name="bmp"></param> /// <param name="surface"></param> /// <returns></returns> public static YanesdkResult BitmapToSurface(Bitmap bmp, out Surface surface) { int w = bmp.Width; int h = bmp.Height; if (w == 0 || h == 0) { surface = null; return(YanesdkResult.PreconditionError); } BitmapData bmpdata; bmpdata = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); if (bmpdata == null) { surface = null; return(YanesdkResult.PreconditionError); } surface = new Surface(); surface.CreateDIB(w, h, true); // 32bpp ARGBになってんでない? // 画像コピー unsafe { // 最悪なのことにalignされている(´ω`) byte *src = (byte *)bmpdata.Scan0; int src_pitch = bmpdata.Stride; byte *dst = (byte *)surface.Pixels; int dst_pitch = surface.Pitch; for (int y = 0; y < h; ++y) { for (int i = 0; i < w * 4; i += 4) { // しかもR,G,B逆かよ!(`ω´) dst[i + 0] = src[i + 2]; dst[i + 1] = src[i + 1]; dst[i + 2] = src[i + 0]; dst[i + 3] = src[i + 3]; } src += src_pitch; dst += dst_pitch; } } bmp.UnlockBits(bmpdata); return(YanesdkResult.NoError); }
/// <summary> /// Bitmap画像をSurfaceに変換(このあとTexture化したりするのに使える) /// </summary> /// <param name="bmp"></param> /// <param name="surface"></param> /// <returns></returns> public static YanesdkResult BitmapToSurface(Bitmap bmp,out Surface surface) { int w = bmp.Width; int h = bmp.Height; if (w == 0 || h == 0) { surface = null; return YanesdkResult.PreconditionError; } BitmapData bmpdata; bmpdata = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); if (bmpdata==null) { surface = null; return YanesdkResult.PreconditionError; } surface = new Surface(); surface.CreateDIB(w, h, true); // 32bpp ARGBになってんでない? // 画像コピー unsafe { // 最悪なのことにalignされている(´ω`) byte* src = (byte*)bmpdata.Scan0; int src_pitch = bmpdata.Stride; byte* dst = (byte*)surface.Pixels; int dst_pitch = surface.Pitch; for (int y = 0; y < h; ++y) { for (int i = 0; i < w * 4; i += 4) { // しかもR,G,B逆かよ!(`ω´) dst[i + 0] = src[i + 2]; dst[i + 1] = src[i + 1]; dst[i + 2] = src[i + 0]; dst[i + 3] = src[i + 3]; } src += src_pitch; dst += dst_pitch; } } bmp.UnlockBits(bmpdata); return YanesdkResult.NoError; }
/// <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> 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> /// Screenの画像をサーフェスにする。 /// ただし、画面の上に載せている.NET Frameworkのコントロールは /// キャプチャできないので注意。 /// </summary> public Surface GetSurface() { Surface surface = new Surface(); if (surface.CreateDIB(Width, Height, false) != YanesdkResult.NoError) { surface.Dispose(); return(null); } // 読み出し元を設定。 // デフォルトでバックバッファだが念のため設定。 //Gl.glReadBuffer(Gl.GL_FRONT); Gl.glReadBuffer(Gl.GL_BACK); //* Gl.glReadPixels(0, 0, surface.Width, surface.Height, surface.Alpha ? Gl.GL_RGBA : Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, surface.Pixels); // glReadPixels()で取得したピクセルが上下逆で、 // 反転させる方法が分からなかったので、 // 仕方なくこちら側で反転させるコードを書いてみた。(´ω`) unsafe { int height = surface.Height; int pitch = surface.Pitch; byte *pixels = (byte *)surface.Pixels; byte *buffer = (byte *)Marshal.AllocHGlobal(pitch); for (int y = 0; y < height / 2; y++) { byte *y1 = pixels + y * pitch; byte *y2 = pixels + (height - y - 1) * pitch; CopyMemory(buffer, y1, (uint)pitch); CopyMemory(y1, y2, (uint)pitch); CopyMemory(y2, buffer, (uint)pitch); } Marshal.FreeHGlobal((IntPtr)buffer); } /*/ * * // ↓こっちの方が微妙に重い。 * // 排他処理かなにかでもしてるのかも? * unsafe { * byte* p = (byte*)surface.Pixels; * uint format = surface.Alpha ? Gl.GL_RGBA : Gl.GL_RGB; * for (int y = 0, h = surface.Height; y < h; y++) { * // 1行ずつ読む。 * Gl.glReadPixels(0, h - y - 1, surface.Width, 1, * format, Gl.GL_UNSIGNED_BYTE, (IntPtr)p); * p += surface.Pitch; * } * } * * //*/ return(surface); }
/// <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; }
/// <summary> /// mpegファイルを読み込む /// </summary> /// <param name="filename">ファイル名</param> public YanesdkResult Load(string filename) { lock (lockObject) { Release(); tmpFile = FileSys.GetTmpFile(filename); if (tmpFile == null || tmpFile.FileName == null) { return YanesdkResult.FileNotFound; } // 読み込み。 //mpeg = SMPEG.SMPEG_new(tmpFile.FileName, ref info, SDL.SDL_WasInit(SDL.SDL_INIT_AUDIO) == 0 ? 1 : 0); mpeg = SMPEG.SMPEG_new(tmpFile.FileName, ref info, 0); if (SMPEG.SMPEG_error(mpeg) != null) { Debug.Fail(SMPEG.SMPEG_error(mpeg)); return YanesdkResult.SdlError; // …SDL? } // 初期設定 // loop = false; // ループ設定はここでは変更しないほうが良い。 paused = false; SMPEG.SMPEG_enablevideo(mpeg, 1); SMPEG.SMPEG_enableaudio(mpeg, 0); if (info.has_audio != 0) { SDL.SDL_AudioSpec audiofmt = new SDL.SDL_AudioSpec(); audiofmt.format = (ushort)Sound.Sound.SoundConfig.AudioFormat; audiofmt.freq = (ushort)Sound.Sound.SoundConfig.AudioRate; audiofmt.channels = (byte)Sound.Sound.SoundConfig.AudioChannels; audiofmt.samples = (ushort)Sound.Sound.SoundConfig.AudioBuffers; SMPEG.SMPEG_actualSpec(mpeg, ref audiofmt); SDL.Mix_HookMusic(mix_hook, mpeg); SMPEG.SMPEG_enableaudio(mpeg, 1); } SMPEG.SMPEG_enableaudio(mpeg, 1); Volume = volume; // 描画先サーフェスのsmpegへの登録など。 if (window != null) { // SDLWindowに直に描画する if (surface != null) { surface.Dispose(); surface = null; } uint flags = (uint)window.Option; flags &= ~SDL.SDL_OPENGL; // OPENGLはダメ。 IntPtr s = SDL.SDL_SetVideoMode(window.Width, window.Height, window.Bpp, flags); if (s == IntPtr.Zero) return YanesdkResult.SdlError; SMPEG.SMPEG_setdisplay(mpeg, s, IntPtr.Zero, null); SMPEG.SMPEG_move(mpeg, (int)windowRect.Left, (int)windowRect.Top); SMPEG.SMPEG_scaleXY(mpeg, (int)windowRect.Width, (int)windowRect.Height); } else if ( Yanesdk.System.Platform.PlatformID == Yanesdk.System.PlatformID.Windows && hwnd != IntPtr.Zero) { // SDLWindowを貼り付けてそれに描画する if (surface != null) { surface.Dispose(); surface = null; } // 親ウィンドウの位置・サイズを取得 POINT parentPos = new POINT(); ClientToScreen(hwnd, ref parentPos); RECT parentRect = new RECT(); GetClientRect(hwnd, out parentRect); int w = parentRect.right - parentRect.left, h = parentRect.bottom - parentRect.top; // SDLウィンドウの位置を合わせる IntPtr sdlHwnd = GetSDLWindowHandle(); //SetParent(sdlHwnd, hwnd); // これするとどうもバグる… SetWindowPos(sdlHwnd, IntPtr.Zero, parentPos.x, parentPos.y, w, h, SWP_NOZORDER); // SDLウィンドウの作成 uint flags = SDL.SDL_HWSURFACE | SDL.SDL_NOFRAME; IntPtr s = SDL.SDL_SetVideoMode(w, h, 0, flags); if (s == IntPtr.Zero) return YanesdkResult.SdlError; sdlWindowCreated = true; sdlHwnd = GetSDLWindowHandle(); // 変わらないと思うが、一応再取得 if (sdlHwnd == IntPtr.Zero) return YanesdkResult.SdlError; SetParent(sdlHwnd, hwnd); SetWindowPos(sdlHwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE); SMPEG.SMPEG_setdisplay(mpeg, s, IntPtr.Zero, null); SMPEG.SMPEG_move(mpeg, 0, 0); SMPEG.SMPEG_scaleXY(mpeg, w, h); } else { // surfaceに描画する if (surface != null && (!surface.CheckRGB888() || surface.Width != Width || surface.Height != Height)) { surface.Dispose(); surface = null; } if (surface == null) { surface = new Surface(); // 拡大・縮小はSMPEG側にやらせると重いので、原寸大で。 YanesdkResult result = surface.CreateDIB(Width, Height, false); if (result != YanesdkResult.NoError) { return result; } } SMPEG.SMPEG_setdisplay(mpeg, surface.SDL_Surface, mutex, callback); SMPEG.SMPEG_move(mpeg, 0, 0); SMPEG.SMPEG_scaleXY(mpeg, surface.Width, surface.Height); //SetFilter(SMPEG.SMPEGfilter_null()); } this.fileName = filename; // おしまい。 return YanesdkResult.NoError; } }
/// <summary> /// Screenの画像をサーフェスにする。 /// ただし、画面の上に載せている.NET Frameworkのコントロールは /// キャプチャできないので注意。 /// </summary> public Surface GetSurface() { Surface surface = new Surface(); if (surface.CreateDIB(Width, Height, false) != YanesdkResult.NoError) { surface.Dispose(); return null; } // 読み出し元を設定。 // デフォルトでバックバッファだが念のため設定。 //Gl.glReadBuffer(Gl.GL_FRONT); Gl.glReadBuffer(Gl.GL_BACK); //* Gl.glReadPixels(0, 0, surface.Width, surface.Height, surface.Alpha ? Gl.GL_RGBA : Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, surface.Pixels); // glReadPixels()で取得したピクセルが上下逆で、 // 反転させる方法が分からなかったので、 // 仕方なくこちら側で反転させるコードを書いてみた。(´ω`) unsafe { int height = surface.Height; int pitch = surface.Pitch; byte* pixels = (byte*)surface.Pixels; byte* buffer = (byte*)Marshal.AllocHGlobal(pitch); for (int y = 0; y < height / 2; y++) { byte* y1 = pixels + y * pitch; byte* y2 = pixels + (height - y - 1) * pitch; CopyMemory(buffer, y1, (uint)pitch); CopyMemory(y1, y2, (uint)pitch); CopyMemory(y2, buffer, (uint)pitch); } Marshal.FreeHGlobal((IntPtr)buffer); } /*/ // ↓こっちの方が微妙に重い。 // 排他処理かなにかでもしてるのかも? unsafe { byte* p = (byte*)surface.Pixels; uint format = surface.Alpha ? Gl.GL_RGBA : Gl.GL_RGB; for (int y = 0, h = surface.Height; y < h; y++) { // 1行ずつ読む。 Gl.glReadPixels(0, h - y - 1, surface.Width, 1, format, Gl.GL_UNSIGNED_BYTE, (IntPtr)p); p += surface.Pitch; } } //*/ return surface; }