Class: RbSDL2::Surface

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
PixelFormatEnum, BlendMode
Defined in:
lib/rb_sdl2/surface.rb,
lib/rb_sdl2/surface/blend_mode.rb,
lib/rb_sdl2/surface/pixel_format.rb

Defined Under Namespace

Modules: BlendMode Classes: PixelFormat, SurfacePointer

Constant Summary

Constants included from PixelFormatEnum

PixelFormatEnum::FORMAT_MAP, PixelFormatEnum::INDEXED_TYPES, PixelFormatEnum::WITH_ALPHA

Class Method Summary collapse

Instance Method Summary collapse

Methods included from PixelFormatEnum

#format_name, #fourcc, #fourcc?, #indexed_color?, #rgb?, #rgba?, to_name, to_num

Methods included from BlendMode

#additive_blend_mode?, #alpha_blend_mode?, #modulate_blend_mode?, #multiply_blend_mode?, #normal_blend_mode?, to_name, to_num

Constructor Details

#initialize(ptr) ⇒ Surface

Returns a new instance of Surface.



87
88
89
# File 'lib/rb_sdl2/surface.rb', line 87

def initialize(ptr)
  @st = ::SDL::Surface.new(ptr)
end

Class Method Details

.convert(surface, new_format) ⇒ Object

指定した Surface オブジェクトを基に指定した画像フォーマットの新しい Surface オブジェクトを柵瀬します。 surface へ変換元の Surface オブジェクトを与えます。 new_format へ変換先の画像フォーマット(PixelFormatEnumの名前か番号)を与えます。 変換ができない場合は例外(RbSDL2::RbSDL2Error)を発生させます。 INDEX1*, INDEX4*, ARGB2101010、FOURCC系への変換はできません。 変換先がインデックスカラー(INDEX8)の時は例外は発生しませんが期待する変換は行われません。 その時はサーフェィス全面がインデックス番号0で埋められています。

Raises:



37
38
39
40
41
42
43
44
# File 'lib/rb_sdl2/surface.rb', line 37

def convert(surface, new_format)
  ptr = SurfacePointer.new(
    ::SDL.ConvertSurfaceFormat(surface, PixelFormatEnum.to_num(new_format), 0))
  raise RbSDL2Error if ptr.null?
  obj = allocate
  obj.__send__(:initialize, ptr)
  obj
end

.load(obj) ⇒ Object

ファイルから画像を読み込み新たな Surface オブジェクトを生成します。 読み込みに対応する画像は BMP 形式のみです。 インデックスカラー(2色、16色)は INDEX8 フォーマット(256色)として読み込まれます。 読み込みができない場合は例外(RbSDL2Error)を発生させます。

obj には ファイルへのパス(文字列)、オブジェクトを与えることができます。 例: File.open(“path.bmp”, “rb”) { |f| Surface.load(f) } パスを与えた場合、読み込み後にクローズします。 オブジェクトを与えた場合、それをクローズしません。 SDL は読み込み時に IO::SEEK_SET によるシークを行います。



56
57
58
59
60
61
62
# File 'lib/rb_sdl2/surface.rb', line 56

def load(obj)
  RbSDL2.open_rw(obj) do |rw|
    ptr = SurfacePointer.new(::SDL.LoadBMP_RW(rw, 0))
    raise RbSDL2Error if ptr.null?
    allocate.tap { |surface| surface.__send__(:initialize, ptr) }
  end
end

.new(w, h, format) ⇒ Object

新しい Surface オブジェクトを生成します。 w は画像の幅ピクセル数 h は画像の縦ピクセル数 format は画像フォーマットのを表すシンボルを与えます。 format へ FOURCC 系の画像フォーマットを与えた場合は例外を戻します。

Raises:



69
70
71
72
73
74
# File 'lib/rb_sdl2/surface.rb', line 69

def new(w, h, format)
  ptr = SurfacePointer.new(
    ::SDL.CreateRGBSurfaceWithFormat(0, w, h, 0, PixelFormatEnum.to_num(format)))
  raise RbSDL2Error if ptr.null?
  super(ptr)
end

.to_ptr(ptr) ⇒ Object

ポインターから Surface オブジェクトを生成します。 ptr へ対象となるポインターを与えます。 このメソッドは Surface 構造体の参照カウンターをサポートしています。 生成した Surface オブジェクトは SDL 側で破棄しても Ruby 側のスコープに存在していれば安全に使用できます。



80
81
82
83
84
# File 'lib/rb_sdl2/surface.rb', line 80

def to_ptr(ptr)
  obj = allocate
  obj.__send__(:initialize, SurfacePointer.to_ptr(ptr))
  obj
end

Instance Method Details

#==(other) ⇒ Object



91
92
93
# File 'lib/rb_sdl2/surface.rb', line 91

def ==(other)
  other.respond_to?(:to_ptr) && other.to_ptr == to_ptr
end

#alpha_modObject

Raises:



95
96
97
98
99
100
# File 'lib/rb_sdl2/surface.rb', line 95

def alpha_mod
  alpha = ::FFI::MemoryPointer.new(:uint8)
  num = ::SDL.GetSurfaceAlphaMod(self, alpha)
  raise RbSDL2Error if num < 0
  alpha.read_uint8
end

#alpha_mod=(alpha) ⇒ Object

Raises:



102
103
104
105
# File 'lib/rb_sdl2/surface.rb', line 102

def alpha_mod=(alpha)
  num = ::SDL.SetSurfaceAlphaMod(self, alpha)
  raise RbSDL2Error if num < 0
end

#blend_modeObject

Raises:



107
108
109
110
111
112
# File 'lib/rb_sdl2/surface.rb', line 107

def blend_mode
  blend = ::FFI::MemoryPointer.new(:int)
  err = ::SDL.GetSurfaceBlendMode(self, blend)
  raise RbSDL2Error if err < 0
  blend.read_int
end

#blend_mode=(blend) ⇒ Object

Raises:



119
120
121
122
# File 'lib/rb_sdl2/surface.rb', line 119

def blend_mode=(blend)
  err = ::SDL.SetSurfaceBlendMode(self, BlendMode.to_num(blend))
  raise RbSDL2Error if err < 0
end

#blend_mode_nameObject



117
# File 'lib/rb_sdl2/surface.rb', line 117

def blend_mode_name = BlendMode.to_name(blend_mode)

#blit(other, from: nil, to: nil, scale: false) ⇒ Object

Raises:



124
125
126
127
128
129
130
131
132
133
# File 'lib/rb_sdl2/surface.rb', line 124

def blit(other, from: nil, to: nil, scale: false)
  from &&= Rect.new(*from)
  to &&= Rect.new(*to)
  err = if scale
          ::SDL.UpperBlitScaled(other, from, self, to)
        else
          ::SDL.UpperBlit(other, from, self, to)
        end
  raise RbSDL2Error if err < 0
end

#boundsObject



135
# File 'lib/rb_sdl2/surface.rb', line 135

def bounds = [0, 0, w, h]

#bytesizeObject



137
# File 'lib/rb_sdl2/surface.rb', line 137

def bytesize = pitch * height

#clear(color = [0, 0, 0, 0]) ⇒ Object



152
# File 'lib/rb_sdl2/surface.rb', line 152

def clear(color = [0, 0, 0, 0]) = fill(bounds, color)

#clipObject



139
140
141
142
143
# File 'lib/rb_sdl2/surface.rb', line 139

def clip
  rect = Rect.new
  ::SDL.GetClipRect(self, rect)
  rect.to_a
end

#clip=(rect) ⇒ Object

nil の場合はサーフェィス全域がクリップになる。



146
147
148
149
150
# File 'lib/rb_sdl2/surface.rb', line 146

def clip=(rect)
  rect &&= Rect.new(*rect)
  bool = ::SDL.SetClipRect(self, rect)
  raise "out of bounds" if bool == ::SDL::FALSE
end

#color_keyObject



154
155
156
157
158
159
160
# File 'lib/rb_sdl2/surface.rb', line 154

def color_key
  return unless color_key?
  key = ::FFI::MemoryPointer.new(:uint32)
  err = ::SDL.GetColorKey(self, key)
  return RbSDL2Error if err < 0
  pixel_format.unpack_color(key.read_uint32)
end

#color_key=(color) ⇒ Object

Raises:



162
163
164
165
166
167
168
169
# File 'lib/rb_sdl2/surface.rb', line 162

def color_key=(color)
  err = if color
          ::SDL.SetColorKey(self, ::SDL::TRUE, pixel_format.pack_color(color))
        else
          ::SDL.SetColorKey(self, ::SDL::FALSE, 0)
        end
  raise RbSDL2Error if err < 0
end

#color_key?Boolean

Returns:

  • (Boolean)


171
# File 'lib/rb_sdl2/surface.rb', line 171

def color_key? = ::SDL.HasColorKey(self) == ::SDL::TRUE

#color_modObject

Raises:



173
174
175
176
177
178
# File 'lib/rb_sdl2/surface.rb', line 173

def color_mod
  rgb = Array.new(3) { ::FFI::MemoryPointer.new(:uint8) }
  err = ::SDL.GetSurfaceColorMod(self, *rgb)
  raise RbSDL2Error if err < 0
  rgb.map(&:read_uint8)
end

#color_mod=(color) ⇒ Object

Raises:



180
181
182
183
184
# File 'lib/rb_sdl2/surface.rb', line 180

def color_mod=(color)
  r, g, b = color
  err = ::SDL.SetSurfaceColorMod(self, r, g, b)
  raise RbSDL2Error if err < 0
end

#convert(new_format = format) ⇒ Object



186
# File 'lib/rb_sdl2/surface.rb', line 186

def convert(new_format = format) = Surface.convert(self, new_format)

#fill(rect = clip, color = [0, 0, 0, 0]) ⇒ Object

Raises:



188
189
190
191
# File 'lib/rb_sdl2/surface.rb', line 188

def fill(rect = clip, color = [0, 0, 0, 0])
  err = ::SDL.FillRect(self, Rect.new(*rect), pixel_format.pack_color(color))
  raise RbSDL2Error if err < 0
end

#heightObject Also known as: h



193
# File 'lib/rb_sdl2/surface.rb', line 193

def height = @st[:h]

#pitchObject



197
# File 'lib/rb_sdl2/surface.rb', line 197

def pitch = @st[:pitch]

#pixel(x, y) ⇒ Object

指定位置のピクセル値を戻します。

Raises:

  • (ArgumentError)


203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/rb_sdl2/surface.rb', line 203

def pixel(x, y)
  raise ArgumentError if x < 0 || width <= x
  raise ArgumentError if y < 0 || height <= y

  # RLE の場合にビットマップ・メモリーへアクセスするため synchronize が必要になる。
  synchronize do
    ptr = @st[:pixels] + (pitch * y + bytes_per_pixel * x)
    case bytes_per_pixel
    when 1 then ptr.read_uint8
    when 2 then ptr.read_uint16
    when 3 then ptr.read_uint32 & 0x1000000 # for little endian
    when 4 then ptr.read_uint32
    else
      raise TypeError
    end
  end
end

#pixel_color(x, y) ⇒ Object

指定位置のピクセル・カラーを戻します。



200
# File 'lib/rb_sdl2/surface.rb', line 200

def pixel_color(x, y) = unpack_pixel(pixel(x, y))

#pixel_formatObject

NOTE: @pixel_format へのアクセスは非公開にする予定です。



224
225
226
227
228
229
230
231
# File 'lib/rb_sdl2/surface.rb', line 224

def pixel_format
  # SDL_Surface の format メンバーは読み取り専用である。作成時の値が不変であることを前提とする。
  # PixelFormat は参照カウンターで管理されている。
  # 自身を所有している Surface が生きていればリソースが開放されることはない。
  # PixelFormat は Index 系(5種)のみ個別にリソースが確保されている。
  # RGB 系は SDL 側でキャッシュがあればそれを、なければ新しくリソースを確保している。
  @pixel_format ||= PixelFormat.new(@st[:format])
end

#rle=(bool) ⇒ Object

Raises:



243
244
245
246
# File 'lib/rb_sdl2/surface.rb', line 243

def rle=(bool)
  err = ::SDL.SetSurfaceRLE(self, bool ? 1 : 0)
  raise RbSDL2Error if err < 0
end

#rle?Boolean

Returns:

  • (Boolean)


248
# File 'lib/rb_sdl2/surface.rb', line 248

def rle? = ::SDL.HasSurfaceRLE(self) == ::SDL::TRUE

#save(obj) ⇒ Object

画像をファイルへ書き込みます。 obj には ファイルへのパス(文字列)、オブジェクト、RWOps オブジェクトを与えることができます。 例: File.open(“path.bmp”, “wb”) { |f| Surface.save(f) } パスを与えた場合、書き込み後にクローズします。 オブジェクトやRWOps オブジェクトを与えた場合、それらをクローズしません。 SDL は書き込み時に前方向へのシークを行います。(開始点より前には行かない) ストリーム IO では使用できないでしょう。 読み込みができない場合は例外(RbSDL2::RbSDL2Error)を発生させます。



258
259
260
261
262
263
# File 'lib/rb_sdl2/surface.rb', line 258

def save(obj)
  RbSDL2.open_rw(obj) do |rw|
    raise RbSDL2Error if ::SDL.SaveBMP_RW(self, rw, 0) < 0
  end
  nil
end

#sizeObject



265
# File 'lib/rb_sdl2/surface.rb', line 265

def size = [width, height]

#synchronizeObject



267
268
269
270
271
272
# File 'lib/rb_sdl2/surface.rb', line 267

def synchronize
  ::SDL.LockSurface(self)
  yield(self)
ensure
  ::SDL.UnlockSurface(self)
end

#to_ptrObject



274
# File 'lib/rb_sdl2/surface.rb', line 274

def to_ptr = @st.to_ptr

#widthObject Also known as: w



276
# File 'lib/rb_sdl2/surface.rb', line 276

def width = @st[:w]