サイログ。

~雑多な記事置き場~

Ruby+Ruby/SDL+ruby-openglよたび

というわけで、悪戦苦闘の後を恥ずかしながら公開いたします。
これは、文字(の画像)を、色々エフェクトさせています。
左右が逆転していますがキニシナーイ!
描画は書いた順でいいので、デプスバッファは取ってません(ムダになるけどね)。

require 'sdl'
require 'gl'
require 'glu'

include Gl
include Glu

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

@pos = 0.0
@st = 0
@size = 20
@amt  = -1
@x  = 0
@y  = 0
@ox = 0.0
@oy = 0.0
@w  = 256.0
@h  = 256.0
@ow = 128.0
@oh = 128.0
@r  = 0.0
@wx = 16
@hy = 16
@ww = 4
@hh = 4

def init_screen
  SDL.init(SDL::INIT_VIDEO|SDL::INIT_AUDIO)
  
  SDL::GL.set_attr(SDL::GL::RED_SIZE, 8)
  SDL::GL.set_attr(SDL::GL::GREEN_SIZE, 8)
  SDL::GL.set_attr(SDL::GL::BLUE_SIZE, 8)
  SDL::GL.set_attr(SDL::GL::ALPHA_SIZE, 8)
  SDL::GL.set_attr(SDL::GL::DOUBLEBUFFER, 1)
  
  SDL::Screen.open(SCREEN_WIDTH,
                   SCREEN_HEIGHT,
                   32,
                   SDL::HWSURFACE | SDL::OPENGL)
                   
end

def init_sprite(file_name)
  # 本当は、displayformatしなきゃいけないけど…。
  SDL::Surface.load(file_name)
end

def init_gl(w, h)
  glClearColor(0.0, 0.0, 0.0, 0.0)
  glPixelStorei(GL_UNPACK_ALIGNMENT, 4)
  resize(w, h)
end

def init_textures(sprites)
  textures = glGenTextures(sprites.length)
  
  sprites.each_with_index{|sprite, i|
    bitmap = sprite.pixels
    glBindTexture(GL_TEXTURE_2D, textures[i])
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sprite.w, sprite.h, 0, 
                 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, bitmap)
  }

  textures
end

def resize(w, h, theta=30.0,top=[0.0,1.0,0.0])
  # 0 < theta < 90.0
  w2 = w / 2
  h2 = h / 2
  gluPerspective(theta, w/h, -1.0, 1.0)
  # radian=2*PI*((theta/2)/360)
  # z = h * (cos(radian)/sin(radian)) = h * (1/tan(radian))
  gluLookAt(w2,h2,-(h2 / Math.tan(Math::PI * theta / 360.0)),w2,h2,0.0,*top)
end

def draw(screen, textures, w, h)
  glClear(GL_COLOR_BUFFER_BIT)

  l = @ox
  t = @oy
  r = (@ox+@ow)
  b = (@oy+@oh)
  lv = l / @ow
  tv = t / @oh
  rv = r / @ow
  bv = b / @oh
  ll = @x
  tt = @y
  rr = (@x+@ow)
  bb = (@y+@oh)
  llv = ll / @ow
  ttv = tt / @oh
  rrv = rr / @ow
  bbv = bb / @oh
  
  0.step(h, @hy){|y|
    0.step(w, @wx){|x|
      glPushMatrix
      glBegin(GL_QUADS)
      glColor3d(1,0,0)
      glVertex3d(x    ,y    ,   0)
      glVertex3d(x+@ww,y    ,   0)
      glVertex3d(x+@ww,y+@hh,   0)
      glVertex3d(x    ,y+@hh,   0)
      glColor3d(1,1,1)
      glEnd
      glPopMatrix
    }
  }

  glPushMatrix
  glEnable(GL_TEXTURE_2D)
  glEnable(GL_BLEND)
  glBindTexture(GL_TEXTURE_2D, textures[0])
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  glTranslated(@ow/2,@oh/2,0.0)
  glRotated(@r, 1.0, 0.0, 1.0)
  glTranslated(-@ow/2,-@oh/2,0.0)
  glBegin(GL_QUADS)
  glTexCoord2d(lv, bv)
  glVertex3d(ll,tt,0.0)
  glTexCoord2d(rv, bv)
  glVertex3d(rr,tt,0.0)
  glTexCoord2d(rv, tv)
  glVertex3d(rr,bb,0.0)
  glTexCoord2d(lv, tv)
  glVertex3d(ll,bb,0.0)
  glEnd
  glDisable(GL_BLEND)
  glDisable(GL_TEXTURE_2D)
  glPopMatrix
  
  glPushMatrix
  glEnable(GL_TEXTURE_2D)
  glEnable(GL_BLEND)
  glBindTexture(GL_TEXTURE_2D, textures[1])
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  glBegin(GL_QUADS)
  glTexCoord2i(0, @size)
  glVertex3i(120,120,0)
  glTexCoord2i(@size, @size)
  glVertex3i(375,120,0)
  glTexCoord2i(@size, 0)
  glVertex3i(375,375,0)
  glTexCoord2i(0, 0)
  glVertex3i(120,375,0)
  glEnd
  glDisable(GL_BLEND)
  glDisable(GL_TEXTURE_2D)
  glPopMatrix

  glPushMatrix
  glEnable(GL_TEXTURE_2D)
  glEnable(GL_BLEND)
  glBindTexture(GL_TEXTURE_2D, textures[2])
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  glBegin(GL_QUADS)
  glTexCoord2d(0.0, 1.0)
  glVertex3f(@pos,0,0)
  glTexCoord2d(1.0, 1.0)
  glVertex3f(@pos+255.0,0,0)
  glTexCoord2d(1.0, 0.0)
  glVertex3f(@pos+255.0,255.0,0)
  glTexCoord2d(0.0, 0.0)
  glVertex3f(@pos,255,0)
  glEnd
  glDisable(GL_BLEND)
  glDisable(GL_TEXTURE_2D)
  glPopMatrix
  
  SDL::GL.swap_buffers
  
  @pos += 8.0
  if @pos >= 480.0
    if @st == 0
      @st = SDL.get_ticks
    else
      ed = SDL.get_ticks
      @st = ed
    end
    @pos = 0.0
  end
  
  @size += @amt
  if @size == 0
    @size = 1
    @amt = 1
  elsif @size == 20
    @size = 19
    @amt = -1
  end
  
  @r = @r + 15.0
  @r = 0.0 if @x >= 360.0
end

def main_loop(screen, textures, w, h)
  flag = true
  while flag
    while event = SDL::Event.poll
      case event
      when SDL::Event::KeyDown
        case event.sym
        when SDL::Key::Q
        when SDL::Key::ESCAPE
          flag = false
        end
      end
    end
    draw(screen, textures, w, h)
  end
end

w = SCREEN_WIDTH.to_f
h = SCREEN_HEIGHT.to_f

screen = init_screen
exit if glGetString(GL_VERSION) < "2.0"
init_gl(w, h)
textures = init_textures(
  [1,2,3].map{|n| init_sprite("a#{n}.png")}
)
main_loop(screen, textures, w, h)

使用する画像は以下の3つ。


a1.png
(文字色が白なので、たんなる透明な画像に見えてしまいますが…(^^;


a2.png


a3.png

画像を直接保存して使ってみてください(32bit、アルファチャネル付き画像です)