RubyでOpenGL続き
こないだから、久しぶりにruby-openglのプログラムを書いてみたいと思っていたので、書いてみた。
Ruby1.9.2+Ruby/SDL2.1.1+ruby-opengl0.61を使用。
(ruby-openglのビルド方法については回答できかねます…)
出来上がったのはこんな感じ。
「何このキャラ!?」と思われた方、ゲームのサンプル用に、何も考えずに手抜きで書いたものなので、ツッコミはスルーします(^^;
以下、ソースコードと画像
require 'sdl' require 'gl' require 'glu' include Gl include Glu SCREEN_WIDTH = 640 SCREEN_HEIGHT = 480 module GLBase @screen = nil @w = 0 @h = 0 def GLBase.w @w end def GLBase.h @h end def GLBase.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 GLBase.init(w, h, theta=30.0, top=[0.0,1.0,0.0]) @w = w @h = h 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::DEPTH_SIZE, 8) SDL::GL.set_attr(SDL::GL::DOUBLEBUFFER, 1) @screen = SDL::Screen.open(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL::HWSURFACE | SDL::OPENGL) glClearColor(0.0, 0.0, 0.0, 0.0) glPixelStorei(GL_UNPACK_ALIGNMENT, 4) GLBase.resize(@w, @h, theta, top) end def GLBase.enable? glGetString(GL_VERSION) < "2.0" end def GLBase.main_loop 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 glClear(GL_COLOR_BUFFER_BIT) yield SDL::GL.swap_buffers end end end class GLSprite GL_TEXTURE_RECTANGLE_EXT = 0x84F5 def self.create(file_name) self.new(SDL::Surface.load(file_name)) end def initialize(image) @image = image @w = @image.w @h = @image.h @ow = @w @oh = @h @ox = 0 @oy = 0 @oright = @ow-1 @obottom = @oh-1 @x = 0 @y = 0 @z = 0 @rot_0 = 0.0 @rot_1 = 0.0 @rot_2 = 0.0 @cx = @ow / 2 @cy = @oh / 2 @sca_x = 1.0 @sca_y = 1.0 @texture = glGenTextures(1) glEnable(GL_TEXTURE_RECTANGLE_EXT) glBindTexture(GL_TEXTURE_RECTANGLE_EXT, @texture[0]) glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_MAG_FILTER,GL_LINEAR) glTexParameteri(GL_TEXTURE_RECTANGLE_EXT,GL_TEXTURE_MIN_FILTER,GL_LINEAR) glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, @w, @h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, @image.pixels) glDisable(GL_TEXTURE_RECTANGLE_EXT) end def move(x,y,z=0) @x += x @y += y @z += z end def move_to(x,y,z=0) @x, @y, @z = x, y, z end def center(x,y) @cx, @cy = x, y end def rotate(r0,r1=0,r2=0) @rot_0, @rot_1, @rot_2 = r0, r1, r2 end def scale(x,y) @sca_x, @sca_y = x, y end def resize(x,y,w,h) @ox,@oy,@ow,@oh=x,y,w,h @oright = @ox+@ow-1 @obottom = @oy+@oh-1 end def render_inner(param) glBegin(GL_QUADS) yield glEnd end def render return unless @texture # sw = GLBase.w # sh = GLBase.h # x2 = sw-@x # y2 = sh-@y x2 = GLBase.w-@x y2 = GLBase.h-@y r2 = x2-@ow+1 b2 = y2-@oh+1 glPushMatrix glEnable(GL_TEXTURE_2D) glEnable(GL_TEXTURE_RECTANGLE_EXT) glEnable(GL_BLEND) glBindTexture(GL_TEXTURE_RECTANGLE_EXT, @texture[0]) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) # glTranslated(sw-(@x+@cx),sh-(@y+@cy),0) glTranslated(x2-@cx,y2-@cy,0) glRotated(@rot_0, 0.0, 0.0, 1.0) glRotated(@rot_1, 0.0, 1.0, 0.0) glRotated(@rot_2, 1.0, 0.0, 0.0) glScaled(@sca_x, @sca_y, 1.0) # glTranslated((@x+@cx-sw,(@y+@cy)-sh,0) glTranslated(@cx-x2,@cy-y2,0) render_inner(GL_QUADS){ glTexCoord2i(@ox, @obottom) # glVertex3i(sw-@x,sh-(@y+@oh-1),@z) glVertex3i(x2,b2,@z) glTexCoord2i(@oright, @obottom) # glVertex3i(sw-(@x+@ow-1),sh-(@y+@oh-1),@z) glVertex3i(r2,b2,@z) glTexCoord2i(@oright, @oy) # glVertex3i(sw-(@x+@ow-1),sh-@y,@z) glVertex3i(r2,y2,@z) glTexCoord2i(@ox, @oy) # glVertex3i(sw-@x,sh-@y,@z) glVertex3i(x2,y2,@z) } glDisable(GL_BLEND) glDisable(GL_TEXTURE_RECTANGLE_EXT) glDisable(GL_TEXTURE_2D) glPopMatrix end def dispose glDeleteTextures(@texture) @texture = nil end end w = SCREEN_WIDTH.to_f h = SCREEN_HEIGHT.to_f GLBase.init(w, h) exit if GLBase.enable? sprites = [1,2,3].map{|n| GLSprite.create("a#{n}.png")} sprites[0].move_to(16,16) sprites[1].move_to(128,16) sprites[2].move_to(256,128) #sprites[0].center(64,64) angle = 0 angle_amt = -10 scale = 1.0 scale_amt = 0.1 r = 80 rangle = 0 rangle_amt = 4 GLBase.main_loop do sprites[0].rotate(angle) sprites[1].scale(scale,scale) radian = rangle * Math::PI * 2 / 360.0 sprites[2].move_to(256+r*Math.sin(radian), 128+r*Math.cos(radian)) sprites[0].render sprites[1].render sprites[2].render angle = (angle + angle_amt) % 360 rangle = (rangle + rangle_amt) % 360 scale = scale + scale_amt scale_amt = -scale_amt if scale <= 0.0 or scale >= 2.0 end sprites.each{|sprite| sprite.dispose }
a1.png:
a2.png:
a3.png: