Class: GlimR::Texture

Inherits:
SceneObject show all
Defined in:
lib/glimr/renderer/texture.rb

Overview

A Texture is a wrapper around an OpenGL texture object. It generates a texture id when it is first used.

To load a texture from an image file, use Texture.load(image_filename) or Texture#load(image_filename).

The #width and #height of a texture refer to the dimensions of the loaded image, while the #bound of a texture is the closest containing power of two for the image dimensions (as in, the texture dimensions are a power of two square, inside which the image is stamped.)

The #mode of a texture is GL::TEXTURE_2D. If feeling particularly adventurous, extend the class to do rectangular textures, non-power-of-two textures, 1D and 3D textures.

Uses SDL, Imlib2, or RMagick to load images. If you have none of these, trying to load texture images will fail.

Instance Attribute Summary collapse

Attributes inherited from SceneObject

#children, #drawables, #mtime, #parent, #viewport

Attributes included from EventListener

#event_listeners, #listener_count

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from SceneObject

#<<, #absolute_geometry, #absolute_material, #absolute_shader, #absolute_transform, #absolute_transform_for_drawing, #add_drawables, #attach, #clone, #detach, #detach_self, #remove_drawables, #render, #replace_node, #root, #touch!, #visible

Methods included from EventListener

#add_event_listener, #decrement_listener_count, #dispatch_event, #event_root, #increment_listener_count, #method_missing, #multicast_event, #process_event, #remove_event_listener

Constructor Details

#initialize(*a, &b) ⇒ Texture

Returns a new instance of Texture.



62
63
64
65
# File 'lib/glimr/renderer/texture.rb', line 62

def initialize(*a, &b)
  @tex_id = []
  super
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class GlimR::EventListener

Instance Attribute Details

#boundObject

Returns the smallest power of two that is larger or equal to the larger of width and height.



167
168
169
# File 'lib/glimr/renderer/texture.rb', line 167

def bound
  @bound
end

#filenameObject (readonly)

Returns the value of attribute filename.



46
47
48
# File 'lib/glimr/renderer/texture.rb', line 46

def filename
  @filename
end

#heightObject

Returns the value of attribute height.



45
46
47
# File 'lib/glimr/renderer/texture.rb', line 45

def height
  @height
end

#modeObject

Returns the value of attribute mode.



45
46
47
# File 'lib/glimr/renderer/texture.rb', line 45

def mode
  @mode
end

#pixelsObject

Returns the value of attribute pixels.



45
46
47
# File 'lib/glimr/renderer/texture.rb', line 45

def pixels
  @pixels
end

#tex_idObject (readonly)

Returns the value of attribute tex_id.



46
47
48
# File 'lib/glimr/renderer/texture.rb', line 46

def tex_id
  @tex_id
end

#widthObject

Returns the value of attribute width.



45
46
47
# File 'lib/glimr/renderer/texture.rb', line 45

def width
  @width
end

Class Method Details

.load(filename) ⇒ Object

Creates a new Texture from the given image filename.



56
57
58
59
60
# File 'lib/glimr/renderer/texture.rb', line 56

def self.load(filename)
    t = new
    t.load(filename)
    t
end

Instance Method Details

#absolute_textureObject

The collapsed texture for a texture is the texture itself.



68
69
70
# File 'lib/glimr/renderer/texture.rb', line 68

def absolute_texture
  self
end

#applyObject

Bind tex_id as the OpenGL texture and upload the texture if it has been changed since last use.



121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/glimr/renderer/texture.rb', line 121

def apply
  return unless pixels
  Enable(mode)
  if not @tex_id[0]
    @tex_id[0] = GenTextures(1)[0]
    push_state
      BindTexture(mode, @tex_id[0])
      upload_texture
    pop_state
  end
  BindTexture(mode, @tex_id[0])
  upload_texture if @changed
end

#default_configObject



48
49
50
51
52
53
# File 'lib/glimr/renderer/texture.rb', line 48

def default_config
  super.merge(
    :mode => TEXTURE_2D,
    :width => 0, :height => 0
  )
end

#finishObject

Deletes the OpenGL texture object.



114
115
116
117
# File 'lib/glimr/renderer/texture.rb', line 114

def finish
  DeleteTextures(@tex_id)
  @tex_id.clear
end

#inspectObject



233
234
235
# File 'lib/glimr/renderer/texture.rb', line 233

def inspect
  "#<#{self.class.name}:#{hash}:TEXID#@tex_id:FILE:#@filename:MODE#@mode:W#@width:H#@height:B#@bound>"
end

#load(filename) ⇒ Object

Loads the image filename into the texture.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/glimr/renderer/texture.rb', line 73

def load(filename)
  if $sdl
    surf = SDL::Surface.load(filename.to_s)
    if surf.bpp < 32
      rmask = 0xff000000
      gmask = 0x00ff0000
      bmask = 0x0000ff00
      amask = 0x000000ff
      image = SDL::Surface.new(
          SDL::SWSURFACE|SDL::SRCALPHA,
          surf.w, surf.h, 32,
          amask,bmask,gmask,rmask)
      image.put(surf,0,0)
    else
      image = surf
    end
    w = image.w
    h = image.h
    px = image.pixels
  elsif $imlib
    image = Imlib2::Image.load(filename.to_s)
    w = image.width
    h = image.height
    px = image.data.gsub(/(.)(.)(.)(.)/, '\2\3\4\1')
  elsif $rmagick
    image = Magick::Image.read(filename.to_s).first
    w = image.width
    h = image.height
    px = image.to_blob{|i|
      i.format = "RGBA"
      i.depth = 8
    }
  end
  @filename = filename
  self.mode = TEXTURE_2D
  self.width = w.to_i
  self.height = h.to_i
  self.pixels = px + ""
end

#pop_stateObject

Pops the GL attrib stack.



160
161
162
# File 'lib/glimr/renderer/texture.rb', line 160

def pop_state
  PopAttrib()
end

#power_of_two?(n) ⇒ Boolean

Returns:

  • (Boolean)


135
136
137
# File 'lib/glimr/renderer/texture.rb', line 135

def power_of_two?(n)
  (n & (n - 1) == 0)
end

#push_stateObject

Pushes GL::TEXTURE_BIT to attrib stack.



155
156
157
# File 'lib/glimr/renderer/texture.rb', line 155

def push_state
  PushAttrib(TEXTURE_BIT)
end

#replace!(other) ⇒ Object

Replace main instance variables with the other’s. Namely: @tex_id, @bound, @bound_pixels, @width, @height, @pixels, @changed, @mode.

Use this to swap a texture for another when you want to preserve the rest of the state.

But beware, the current texture is lost unless you copy it somewhere else first.

E.g.

t = Texture.load 'foo.jpg'
backup = Texture.new
backup.replace! deep_texture_node
deep_texture_node.replace! t


219
220
221
222
223
224
225
226
227
228
229
# File 'lib/glimr/renderer/texture.rb', line 219

def replace!(other)
  @tex_id = other.tex_id
  @bound = other.instance_variable_get(:@bound)
  @bound_pixels = other.instance_variable_get(:@bound_pixels)
  @width = other.instance_variable_get(:@width)
  @height = other.instance_variable_get(:@height)
  @pixels = other.instance_variable_get(:@pixels)
  @changed = other.instance_variable_get(:@changed)
  @mode = other.instance_variable_get(:@mode)
  self
end

#upload_textureObject

Uploads the texture to OpenGL. Uses TexImage2D if the texture dimensions have changed since last upload, otherwise uses TexSubImage2D.



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/glimr/renderer/texture.rb', line 180

def upload_texture
  if !@bound
    @bound = self.bound
    @bound_pixels = "\000"*(4*@bound*@bound)
    TexImage2D(
      mode, 0, 4,
      @bound, @bound, 0,
      RGBA,
      UNSIGNED_BYTE,
      @bound_pixels
    )
  end
  TexSubImage2D(
    mode, 0,
    0, 0, width, height,
    RGBA,
    UNSIGNED_BYTE,
    pixels
  )
  TexParameteri(mode, TEXTURE_WRAP_S, CLAMP)
  TexParameteri(mode, TEXTURE_WRAP_T, CLAMP)
  TexParameteri(mode, TEXTURE_MIN_FILTER, LINEAR)
  TexParameteri(mode, TEXTURE_MAG_FILTER, LINEAR)
  @changed = false
end