Texture.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // $Id$
  2. using System;
  3. using Sdl;
  4. using OpenGl;
  5. namespace Drawing
  6. {
  7. public class Texture : IDisposable
  8. {
  9. private uint handle;
  10. public uint Handle
  11. {
  12. get
  13. {
  14. return handle;
  15. }
  16. }
  17. private uint width;
  18. public uint Width
  19. {
  20. get
  21. {
  22. return width;
  23. }
  24. }
  25. private uint height;
  26. public uint Height
  27. {
  28. get
  29. {
  30. return height;
  31. }
  32. }
  33. protected Texture()
  34. {
  35. }
  36. public Texture(uint width, uint height, uint glformat)
  37. {
  38. CreateEmpty(width, height, glformat);
  39. }
  40. public Texture(IntPtr surfacep, uint glformat)
  41. {
  42. CreateFromSurface(surfacep, glformat);
  43. }
  44. protected unsafe void CreateFromSurface(IntPtr surfacep, uint glformat)
  45. {
  46. Sdl.Surface* surface = (Sdl.Surface*) surfacep;
  47. this.width = (uint) surface->w;
  48. this.height = (uint) surface->h;
  49. if(!IsPowerOf2(width) || !IsPowerOf2(height))
  50. throw new Exception("Texture size must be power of 2");
  51. GlUtil.Assert("before creating texture");
  52. CreateTexture();
  53. try {
  54. gl.BindTexture(gl.TEXTURE_2D, handle);
  55. uint surface_format = SetupPixelFormat(surfacep);
  56. gl.TexImage2D(gl.TEXTURE_2D, 0, (int) glformat,
  57. (int) width, (int) height, 0, surface_format,
  58. gl.UNSIGNED_BYTE, surface->pixels);
  59. GlUtil.Assert("creating texture (too big?)");
  60. SetTextureParams();
  61. } catch(Exception) {
  62. uint[] handles = { handle };
  63. gl.DeleteTextures(1, handles);
  64. throw;
  65. }
  66. }
  67. protected void CreateEmpty(uint width, uint height, uint glformat)
  68. {
  69. if(!IsPowerOf2(width) || !IsPowerOf2(height))
  70. throw new Exception("Texture size must be power of 2");
  71. this.width = width;
  72. this.height = height;
  73. GlUtil.Assert("before creating texture");
  74. CreateTexture();
  75. try {
  76. gl.BindTexture(gl.TEXTURE_2D, handle);
  77. gl.TexImage2D(gl.TEXTURE_2D, 0, (int) glformat,
  78. (int) width, (int) height, 0,
  79. gl.RGBA, gl.UNSIGNED_BYTE, IntPtr.Zero);
  80. GlUtil.Assert("creating texture (too big?)");
  81. SetTextureParams();
  82. } catch(Exception) {
  83. uint[] handles = { handle };
  84. gl.DeleteTextures(1, handles);
  85. throw;
  86. }
  87. }
  88. public unsafe void Dispose()
  89. {
  90. if(handle == 0)
  91. return;
  92. uint[] handles = { handle };
  93. gl.DeleteTextures(1, handles);
  94. this.handle = 0;
  95. }
  96. public unsafe void copy_to(IntPtr surfacep, uint surface_x, uint surface_y,
  97. uint texture_x, uint texture_y,
  98. uint width, uint height)
  99. {
  100. Sdl.Surface* surface = (Sdl.Surface*) surfacep;
  101. PixelFormat* format = (PixelFormat*) surface->format;
  102. GlUtil.Assert("Before update textxure");
  103. uint surface_format = SetupPixelFormat(surfacep);
  104. /* We're extracting sub rectangles from the SDL_Surface pixeldata, by
  105. * setting the pitch to the real width, but telling OpenGL just our
  106. * desired image dimensions.
  107. */
  108. IntPtr pixeldata = (IntPtr)
  109. (((byte*) surface->pixels) + surface_y * surface->pitch
  110. + format->BytesPerPixel * surface_x);
  111. gl.TexSubImage2D(gl.TEXTURE_2D, 0, (int) texture_x, (int) texture_y,
  112. (int) width, (int) height, surface_format,
  113. gl.UNSIGNED_BYTE, pixeldata);
  114. GlUtil.Assert("Updating Texture Part");
  115. }
  116. private static void SetTextureParams()
  117. {
  118. gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  119. gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  120. gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP);
  121. gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP);
  122. gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_R, gl.CLAMP);
  123. GlUtil.Assert("setting texture parameters");
  124. }
  125. private unsafe void CreateTexture()
  126. {
  127. if(!GlUtil.ContextValid) {
  128. LogManager.Log(LogLevel.Warning, "No opengl context active when creating textures");
  129. }
  130. uint[] handles = new uint[1];
  131. gl.GenTextures(1, handles);
  132. // 0 is used as special value to mark invalid textures here
  133. if(handles[0] == 0) {
  134. gl.GenTextures(1, handles);
  135. }
  136. this.handle = handles[0];
  137. }
  138. private static bool IsPowerOf2(uint val)
  139. {
  140. return (val & (val - 1)) == 0;
  141. }
  142. private static unsafe uint SetupPixelFormat(IntPtr surfacep)
  143. {
  144. Sdl.Surface* surface = (Sdl.Surface*) surfacep;
  145. PixelFormat* format = (PixelFormat*) surface->format;
  146. uint glformat;
  147. if(format->BytesPerPixel == 3)
  148. glformat = gl.RGB;
  149. else if(format->BytesPerPixel == 4)
  150. glformat = gl.RGBA;
  151. else
  152. throw new Exception("Surface format not supported (only 24 and 32BPP modes supported at the moment)");
  153. gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1);
  154. gl.PixelStorei(gl.UNPACK_ROW_LENGTH,
  155. surface->pitch / format->BytesPerPixel);
  156. return glformat;
  157. }
  158. }
  159. }