├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.markdown ├── config └── boot.rb ├── lessons ├── lesson01.rb └── lesson10_advance.rb ├── resources ├── nehe │ ├── lesson06 │ │ └── ruby.png │ ├── lesson07 │ │ └── crate.png │ ├── lesson08 │ │ └── Glass.bmp │ ├── lesson09 │ │ └── Star.bmp │ └── lesson10 │ │ ├── Mud.bmp │ │ └── world.json └── tj │ ├── lesson01 │ └── earth.png │ └── lesson10_advance │ ├── brick_wall.jpg │ ├── ceiling.jpg │ ├── hallway.jpg │ ├── small_brick_wall.jpg │ ├── tile_floor.jpg │ ├── wooden_floor.jpg │ └── world.json └── using_nehe_lessons ├── lesson02.rb ├── lesson03.rb ├── lesson04.rb ├── lesson05.rb ├── lesson06.rb ├── lesson07.rb ├── lesson08.rb ├── lesson09.rb └── lesson10.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "gosu", "0.13.2" 4 | gem "opengl", "0.10.0" 5 | gem "ruby-opengl", "0.61.0" 6 | gem "glu", "8.3.0" 7 | gem "glut", "8.3.0" 8 | gem "json", "2.1.0" 9 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | glu (8.3.0) 5 | glut (8.3.0) 6 | gosu (0.13.2) 7 | json (2.1.0) 8 | opengl (0.10.0) 9 | ruby-opengl (0.61.0) 10 | opengl 11 | 12 | PLATFORMS 13 | ruby 14 | 15 | DEPENDENCIES 16 | glu (= 8.3.0) 17 | glut (= 8.3.0) 18 | gosu (= 0.13.2) 19 | json (= 2.1.0) 20 | opengl (= 0.10.0) 21 | ruby-opengl (= 0.61.0) 22 | 23 | BUNDLED WITH 24 | 1.16.0 25 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | ## Gosu OpenGl Fun ## 2 | 3 | ### Prerequisites ### 4 | * [Gosu](http://www.libgosu.org/) 5 | * [ruby-opengl](http://ruby-opengl.rubyforge.org/) 6 | * They are managed with [Bundler](http://gembundler.com/) 7 | 8 | ### Info ### 9 | * using_nehe_lessons - Dir containing [NeHe](http://nehe.gamedev.net/) tutorials simplified and ported to use ruby, ruby-opengl, gosu 10 | * lessons - Dir containing tutorials that will help playing around with gosu and opengl 11 | * modules - As I will go though lessons and exams of open gl code I will start to refactor them into usable modules, engine parts etc 12 | 13 | ### Installation ### 14 | * Install gems via `bundle install` 15 | * Run lessons via `bundle exec ruby ` 16 | 17 | ### Implemented so far ### 18 | * lesson01 - texture loading 19 | * lesson02 - polygons 20 | * lesson03 - adding colors 21 | * lesson04 - rotation animation 22 | * lesson05 - 3D shapes 23 | * lesson06 - texture mapping 24 | * lesson07 - texture filters, lighting and keyboard control 25 | * lesson08 - texture blending, transparency 26 | * lesson09 - moving bitmaps in 3D space 27 | * lesson10 - loading and moving through 3D World -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | Bundler.require(:default) 4 | 5 | require 'gl' 6 | require 'glu' 7 | require 'glut' 8 | 9 | include Gl 10 | include Glu 11 | -------------------------------------------------------------------------------- /lessons/lesson01.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../config/boot', __FILE__) 2 | 3 | class Window < Gosu::Window 4 | def initialize 5 | super(800, 600, false) 6 | self.caption = "Lesson #1 - Texture Loading" 7 | texture = Gosu::Image.new(self, "resources/tj/lesson01/earth.png", true) 8 | @texture_info = texture.gl_tex_info #helper structure that contains image data 9 | end 10 | 11 | def update 12 | end 13 | 14 | def draw 15 | gl do 16 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # clear the screen and the depth buffer 17 | 18 | #glMatrixMode(matrix) indicates that following [matrix] is going to get used 19 | glMatrixMode(GL_PROJECTION) # The projection matrix is responsible for adding perspective to our scene. 20 | glLoadIdentity # Resets current modelview matrix 21 | 22 | # Calculates aspect ratio of the window. Gets perspective view. 45 is degree viewing angle, (0.1, 100) are ranges how deep can we draw into the screen 23 | gluPerspective(45.0, width / height, 0.1, 100.0) 24 | glMatrixMode(GL_MODELVIEW) # The modelview matrix is where object information is stored. 25 | glLoadIdentity 26 | # Think 3-d coordinate system (x,y,z). +- on each movies on that axis 27 | glTranslate(0, 0, -2) # Moving function from the current point by x,y,z change 28 | 29 | glEnable(GL_TEXTURE_2D) # enables two-dimensional texturing to perform 30 | glBindTexture(GL_TEXTURE_2D, @texture_info.tex_name) # bing named texture to a target 31 | 32 | glBegin(GL_QUADS) # begin drawing model 33 | glTexCoord2d(@texture_info.left, @texture_info.top) #sets texture coordinates 34 | glVertex3d(0, 0, 0) # place a point at (x,y,z) location from the current point 35 | glTexCoord2d(@texture_info.right, @texture_info.top) 36 | glVertex3d(0.5, 0, 0) 37 | glTexCoord2d(@texture_info.right, @texture_info.bottom) 38 | glVertex3d(0.5, -0.5, 0) 39 | glTexCoord2d(@texture_info.left, @texture_info.bottom) 40 | glVertex3d(0, -0.5, 0) 41 | glEnd 42 | end 43 | end 44 | 45 | def button_down(id) 46 | if id == Gosu::KbEscape 47 | close 48 | end 49 | end 50 | end 51 | 52 | window = Window.new 53 | window.show -------------------------------------------------------------------------------- /lessons/lesson10_advance.rb: -------------------------------------------------------------------------------- 1 | # This lesson wants to make sure that nehe/lesson10 is fully understood, 2 | # certain decisions in nehe/lesson 10 could be argueable: use of the meshes, 3 | # less than optimal data point map, interesting choice of lighting source 4 | # coordinates, only 1 type of textures. Here we will create 2 connecting 5 | # rooms (diagram below) each with its own set of textures. We will only use 6 | # knowledge learned up and including to lesson10. 7 | # 8 | # We will also provide the following movement control: 9 | # Up - move forward 10 | # Down - move back 11 | # Left - turn left 12 | # Right - turn right 13 | # W - go up 14 | # S - go down 15 | # D - strafe right 16 | # A - strafe left 17 | # Esc - quit 18 | # B - toggle blending 19 | # L - toggle lights 20 | # F - toggle filters 21 | # 22 | # 3D Map 23 | # /-------------------\ 24 | # | | 25 | # | stone room | 26 | # |__________ ______| 27 | # __________| |_______ 28 | # | | 29 | # | wood rooom | 30 | # \-------------------/ 31 | # 32 | # Take Home exerises: 33 | # * reduce size of textures/increase quality 34 | # * modify lighting to go from the center of the ceiling of each floor 35 | # * add another room 36 | require 'gosu' 37 | require 'json' 38 | require 'gl' 39 | require 'glu' 40 | require 'glut' 41 | include Gl 42 | include Glu 43 | 44 | class TjTexture 45 | attr_accessor :info, :image 46 | def initialize(window, name) 47 | @image = Gosu::Image.new("resources/tj/lesson10_advance/#{name}.jpg", {tileable: true}) 48 | @info = @image.gl_tex_info 49 | end 50 | end 51 | 52 | class TjVertex 53 | attr_reader :x, :y, :z, :u, :v 54 | 55 | def initialize(coords) 56 | coords.each do |coordinate, value| 57 | instance_variable_set(:"@#{coordinate}", value) 58 | end 59 | end 60 | end 61 | 62 | class TjMesh 63 | attr_accessor :vertexes 64 | def initialize 65 | @vertexes = [] 66 | end 67 | end 68 | 69 | class Window < Gosu::Window 70 | attr_accessor :meshes, :current_filter 71 | 72 | def initialize 73 | super(800, 600, false) 74 | self.caption = "Lesson #10 - Loading and moving through 3D World" 75 | setup_world 76 | init_defaults 77 | init_lights 78 | init_textures 79 | end 80 | 81 | def setup_world 82 | world = JSON.parse(File.read('resources/tj/lesson10_advance/world.json')) 83 | @all_meshes = world.inject({}) do |acc, mesh_array| 84 | acc[mesh_array.first] = mesh_array.last.map do |vertexes| 85 | TjMesh.new.tap do |mesh| 86 | vertexes.each do |vertex| 87 | mesh.vertexes << TjVertex.new(vertex) 88 | end 89 | end 90 | end 91 | acc 92 | end 93 | end 94 | 95 | def init_defaults 96 | @light_on = false 97 | @blending = false 98 | @bouncing = @bouncing_angle = 0 99 | @x_pos = @look_up_or_down_pos = @y_angle = @look_up_or_down = @y_pos = @z_pos = 0 100 | @degree_radian_conversion = 0.0174532925 # pi / 180 101 | end 102 | 103 | def init_lights 104 | @ambient_light = [0.5, 0.5, 0.5, 1] 105 | @diffuse_light = [1, 1, 1, 1] 106 | @light_postion = [0, 0, 2, 1] 107 | end 108 | 109 | def init_textures 110 | @filter_index = 0 111 | @filters = {} 112 | glGetError 113 | @all_meshes.keys.each do |name| 114 | nearest = TjTexture.new(self, name) 115 | glBindTexture(GL_TEXTURE_2D, nearest.info.tex_name) 116 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST) 117 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST) 118 | 119 | linear = TjTexture.new(self, name) 120 | glBindTexture(GL_TEXTURE_2D, linear.info.tex_name) 121 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 122 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR) 123 | 124 | minimap = TjTexture.new(self, name) 125 | glBindTexture(GL_TEXTURE_2D, minimap.info.tex_name) 126 | texture = glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_FLOAT) 127 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 128 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST) 129 | gluBuild2DMipmaps(GL_TEXTURE_2D, 3, minimap.image.width, minimap.image.height, GL_RGB, GL_FLOAT, texture) 130 | @filters[name] = [nearest, linear, minimap] 131 | end 132 | end 133 | 134 | def init_scene 135 | glBlendFunc(GL_SRC_ALPHA,GL_ONE) 136 | glShadeModel(GL_SMOOTH) 137 | glClearColor(0,0,0,0) 138 | glClearDepth(1) 139 | glEnable(GL_DEPTH_TEST) 140 | glDepthFunc(GL_LEQUAL) 141 | glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) 142 | end 143 | 144 | 145 | def add_perspective_to_scene 146 | glEnable(GL_TEXTURE_2D) 147 | glMatrixMode(GL_PROJECTION) 148 | glLoadIdentity 149 | gluPerspective(45.0, width / height, 0.1, 100.0) 150 | glMatrixMode(GL_MODELVIEW) 151 | glLoadIdentity 152 | end 153 | 154 | def update 155 | @y_angle -= 1.5 if button_down? Gosu::Button::KbRight 156 | @y_angle += 1.5 if button_down? Gosu::Button::KbLeft 157 | 158 | if button_down?(Gosu::Button::KbUp) 159 | @x_pos -= Math.sin(@y_angle * @degree_radian_conversion) * 0.05 160 | @look_up_or_down_pos -= Math.cos(@y_angle * @degree_radian_conversion) * 0.05 161 | @bouncing_angle > 359 ? @bouncing_angle = 0 : @bouncing_angle += 10 162 | @bouncing = Math.sin(@bouncing_angle * @degree_radian_conversion) / 20 163 | end 164 | if button_down?(Gosu::Button::KbDown) 165 | @x_pos += Math.sin(@y_angle * @degree_radian_conversion) * 0.05 166 | @look_up_or_down_pos += Math.cos(@y_angle * @degree_radian_conversion) * 0.05 167 | @bouncing_angle <= 1 ? @bouncing_angle = 359 : @bouncing_angle -= 10 168 | @bouncing = Math.sin(@bouncing_angle * @degree_radian_conversion) / 20 169 | end 170 | @look_up_or_down -= 0.3 if button_down? Gosu::Button::KbPageUp 171 | @look_up_or_down += 0.3 if button_down? Gosu::Button::KbPageDown 172 | @y_pos -= 0.05 if button_down? Gosu::Button::KbW 173 | @y_pos += 0.05 if button_down? Gosu::Button::KbS 174 | @x_pos += 0.05 if button_down? Gosu::Button::KbD 175 | @x_pos -= 0.05 if button_down? Gosu::Button::KbA 176 | end 177 | 178 | def draw 179 | gl do 180 | init_scene 181 | add_perspective_to_scene 182 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 183 | glLightfv(GL_LIGHT1, GL_AMBIENT, @ambient_light) 184 | glLightfv(GL_LIGHT1, GL_DIFFUSE, @diffuse_light) 185 | glLightfv(GL_LIGHT1, GL_POSITION, @light_postion) 186 | glEnable(GL_LIGHT1) 187 | 188 | @light_on ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING) 189 | if @blending 190 | glEnable(GL_BLEND) 191 | glDisable(GL_DEPTH_TEST) 192 | else 193 | glDisable(GL_BLEND) 194 | glEnable(GL_DEPTH_TEST) 195 | end 196 | 197 | x = -@x_pos 198 | y = -@bouncing - 0.25 + @y_pos 199 | z = -@look_up_or_down_pos 200 | scene_angle = 360 - @y_angle 201 | 202 | glRotatef(@look_up_or_down,1,0,0) 203 | glRotatef(scene_angle,0,1,0); 204 | glTranslate(x, y, z) 205 | 206 | @all_meshes.each do |name, meshes| 207 | glBindTexture(GL_TEXTURE_2D, @filters[name][@filter_index].info.tex_name) 208 | meshes.each do |mesh| 209 | draw_mesh(mesh) 210 | end 211 | end 212 | end 213 | end 214 | 215 | def draw_mesh(mesh) 216 | glBegin(GL_QUADS) 217 | glNormal3f(0, 0, 1) 218 | mesh.vertexes.each do |vertex| 219 | glTexCoord2f(vertex.u, vertex.v) 220 | glVertex3f(vertex.x, vertex.y, vertex.z) 221 | end 222 | glEnd 223 | end 224 | 225 | def change_filter! 226 | @filter_index == 2 ? @filter_index = 0 : @filter_index += 1 227 | end 228 | 229 | def button_down(id) 230 | case id 231 | when Gosu::Button::KbEscape then close 232 | when Gosu::Button::KbL then @light_on = !@light_on 233 | when Gosu::Button::KbF then change_filter! 234 | when Gosu::Button::KbB then @blending = !@blending 235 | end 236 | end 237 | end 238 | 239 | window = Window.new 240 | window.show -------------------------------------------------------------------------------- /resources/nehe/lesson06/ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/nehe/lesson06/ruby.png -------------------------------------------------------------------------------- /resources/nehe/lesson07/crate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/nehe/lesson07/crate.png -------------------------------------------------------------------------------- /resources/nehe/lesson08/Glass.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/nehe/lesson08/Glass.bmp -------------------------------------------------------------------------------- /resources/nehe/lesson09/Star.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/nehe/lesson09/Star.bmp -------------------------------------------------------------------------------- /resources/nehe/lesson10/Mud.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/nehe/lesson10/Mud.bmp -------------------------------------------------------------------------------- /resources/nehe/lesson10/world.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ {"x":-3,"y":0,"z":-3,"u":0,"v":1}, 3 | {"x":-3,"y":0,"z":3,"u":0,"v":0}, 4 | {"x":3,"y":0,"z":3,"u":1,"v":0}], 5 | [ {"x":-3,"y":0,"z":-3,"u":0,"v":1}, 6 | {"x":3,"y":0,"z":-3,"u":1,"v":1}, 7 | {"x":3,"y":0,"z":3,"u":1,"v":0}], 8 | [ {"x":-3,"y":1,"z":-3,"u":0,"v":1}, 9 | {"x":-3,"y":1,"z":3,"u":0,"v":0}, 10 | {"x":3,"y":1,"z":3,"u":1,"v":0}], 11 | [ {"x":-3,"y":1,"z":-3,"u":0,"v":1}, 12 | {"x":3,"y":1,"z":-3,"u":1,"v":1}, 13 | {"x":3,"y":1,"z":3,"u":1,"v":0}], 14 | [ {"x":-2,"y":1,"z":-2,"u":0,"v":1}, 15 | {"x":-2,"y":0,"z":-2,"u":0,"v":0}, 16 | {"x":-0.5,"y":0,"z":-2,"u":1,"v":0}], 17 | [ {"x":-2,"y":1,"z":-2,"u":0,"v":1}, 18 | {"x":-0.5,"y":1,"z":-2,"u":1,"v":1}, 19 | {"x":-0.5,"y":0,"z":-2,"u":1,"v":0}], 20 | [ {"x":2,"y":1,"z":-2,"u":0,"v":1}, 21 | {"x":2,"y":0,"z":-2,"u":0,"v":0}, 22 | {"x":0.5,"y":0,"z":-2,"u":1,"v":0}], 23 | [ {"x":2,"y":1,"z":-2,"u":0,"v":1}, 24 | {"x":0.5,"y":1,"z":-2,"u":1,"v":1}, 25 | {"x":0.5,"y":0,"z":-2,"u":1,"v":0}], 26 | [ {"x":-2,"y":1,"z":2,"u":0,"v":1}, 27 | {"x":-2,"y":0,"z":2,"u":0,"v":0}, 28 | {"x":-0.5,"y":0,"z":2,"u":1,"v":0}], 29 | [ {"x":-2,"y":1,"z":2,"u":0,"v":1}, 30 | {"x":-0.5,"y":1,"z":2,"u":1,"v":1}, 31 | {"x":-0.5,"y":0,"z":2,"u":1,"v":0}], 32 | [ {"x":2,"y":1,"z":2,"u":0,"v":1}, 33 | {"x":2,"y":0,"z":2,"u":0,"v":0}, 34 | {"x":0.5,"y":0,"z":2,"u":1,"v":0}], 35 | [ {"x":2,"y":1,"z":2,"u":0,"v":1}, 36 | {"x":0.5,"y":1,"z":2,"u":1,"v":1}, 37 | {"x":0.5,"y":0,"z":2,"u":1,"v":0}], 38 | [ {"x":-2,"y":1,"z":-2,"u":0,"v":1}, 39 | {"x":-2,"y":0,"z":-2,"u":0,"v":0}, 40 | {"x":-2,"y":0,"z":-0.5,"u":1,"v":0}], 41 | [ {"x":-2,"y":1,"z":-2,"u":0,"v":1}, 42 | {"x":-2,"y":1,"z":-0.5,"u":1,"v":1}, 43 | {"x":-2,"y":0,"z":-0.5,"u":1,"v":0}], 44 | [ {"x":-2,"y":1,"z":2,"u":0,"v":1}, 45 | {"x":-2,"y":0,"z":2,"u":0,"v":0}, 46 | {"x":-2,"y":0,"z":0.5,"u":1,"v":0}], 47 | [ {"x":-2,"y":1,"z":2,"u":0,"v":1}, 48 | {"x":-2,"y":1,"z":0.5,"u":1,"v":1}, 49 | {"x":-2,"y":0,"z":0.5,"u":1,"v":0}], 50 | [ {"x":2,"y":1,"z":-2,"u":0,"v":1}, 51 | {"x":2,"y":0,"z":-2,"u":0,"v":0}, 52 | {"x":2,"y":0,"z":-0.5,"u":1,"v":0}], 53 | [ {"x":2,"y":1,"z":-2,"u":0,"v":1}, 54 | {"x":2,"y":1,"z":-0.5,"u":1,"v":1}, 55 | {"x":2,"y":0,"z":-0.5,"u":1,"v":0}], 56 | [ {"x":2,"y":1,"z":2,"u":0,"v":1}, 57 | {"x":2,"y":0,"z":2,"u":0,"v":0}, 58 | {"x":2,"y":0,"z":0.5,"u":1,"v":0}], 59 | [ {"x":2,"y":1,"z":2,"u":0,"v":1}, 60 | {"x":2,"y":1,"z":0.5,"u":1,"v":1}, 61 | {"x":2,"y":0,"z":0.5,"u":1,"v":0}], 62 | [ {"x":-0.5,"y":1,"z":-3,"u":0,"v":1}, 63 | {"x":-0.5,"y":0,"z":-3,"u":0,"v":0}, 64 | {"x":-0.5,"y":0,"z":-2,"u":1,"v":0}], 65 | [ {"x":-0.5,"y":1,"z":-3,"u":0,"v":1}, 66 | {"x":-0.5,"y":1,"z":-2,"u":1,"v":1}, 67 | {"x":-0.5,"y":0,"z":-2,"u":1,"v":0}], 68 | [ {"x":0.5,"y":1,"z":-3,"u":0,"v":1}, 69 | {"x":0.5,"y":0,"z":-3,"u":0,"v":0}, 70 | {"x":0.5,"y":0,"z":-2,"u":1,"v":0}], 71 | [ {"x":0.5,"y":1,"z":-3,"u":0,"v":1}, 72 | {"x":0.5,"y":1,"z":-2,"u":1,"v":1}, 73 | {"x":0.5,"y":0,"z":-2,"u":1,"v":0}], 74 | [ {"x":-0.5,"y":1,"z":3,"u":0,"v":1}, 75 | {"x":-0.5,"y":0,"z":3,"u":0,"v":0}, 76 | {"x":-0.5,"y":0,"z":2,"u":1,"v":0}], 77 | [ {"x":-0.5,"y":1,"z":3,"u":0,"v":1}, 78 | {"x":-0.5,"y":1,"z":2,"u":1,"v":1}, 79 | {"x":-0.5,"y":0,"z":2,"u":1,"v":0}], 80 | [ {"x":0.5,"y":1,"z":3,"u":0,"v":1}, 81 | {"x":0.5,"y":0,"z":3,"u":0,"v":0}, 82 | {"x":0.5,"y":0,"z":2,"u":1,"v":0}], 83 | [ {"x":0.5,"y":1,"z":3,"u":0,"v":1}, 84 | {"x":0.5,"y":1,"z":2,"u":1,"v":1}, 85 | {"x":0.5,"y":0,"z":2,"u":1,"v":0}], 86 | [ {"x":-3,"y":1,"z":0.5,"u":1,"v":1}, 87 | {"x":-3,"y":0,"z":0.5,"u":1,"v":0}, 88 | {"x":-2,"y":0,"z":0.5,"u":0,"v":0}], 89 | [ {"x":-3,"y":1,"z":0.5,"u":1,"v":1}, 90 | {"x":-2,"y":1,"z":0.5,"u":0,"v":1}, 91 | {"x":-2,"y":0,"z":0.5,"u":0,"v":0}], 92 | [ {"x":-3,"y":1,"z":-0.5,"u":1,"v":1}, 93 | {"x":-3,"y":0,"z":-0.5,"u":1,"v":0}, 94 | {"x":-2,"y":0,"z":-0.5,"u":0,"v":0}], 95 | [ {"x":-3,"y":1,"z":-0.5,"u":1,"v":1}, 96 | {"x":-2,"y":1,"z":-0.5,"u":0,"v":1}, 97 | {"x":-2,"y":0,"z":-0.5,"u":0,"v":0}], 98 | [ {"x":3,"y":1,"z":0.5,"u":1,"v":1}, 99 | {"x":3,"y":0,"z":0.5,"u":1,"v":0}, 100 | {"x":2,"y":0,"z":0.5,"u":0,"v":0}], 101 | [ {"x":3,"y":1,"z":0.5,"u":1,"v":1}, 102 | {"x":2,"y":1,"z":0.5,"u":0,"v":1}, 103 | {"x":2,"y":0,"z":0.5,"u":0,"v":0}], 104 | [ {"x":3,"y":1,"z":-0.5,"u":1,"v":1}, 105 | {"x":3,"y":0,"z":-0.5,"u":1,"v":0}, 106 | {"x":2,"y":0,"z":-0.5,"u":0,"v":0}], 107 | [ {"x":3,"y":1,"z":-0.5,"u":1,"v":1}, 108 | {"x":2,"y":1,"z":-0.5,"u":0,"v":1}, 109 | {"x":2,"y":0,"z":-0.5,"u":0,"v":0}] 110 | ] -------------------------------------------------------------------------------- /resources/tj/lesson01/earth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/tj/lesson01/earth.png -------------------------------------------------------------------------------- /resources/tj/lesson10_advance/brick_wall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/tj/lesson10_advance/brick_wall.jpg -------------------------------------------------------------------------------- /resources/tj/lesson10_advance/ceiling.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/tj/lesson10_advance/ceiling.jpg -------------------------------------------------------------------------------- /resources/tj/lesson10_advance/hallway.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/tj/lesson10_advance/hallway.jpg -------------------------------------------------------------------------------- /resources/tj/lesson10_advance/small_brick_wall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/tj/lesson10_advance/small_brick_wall.jpg -------------------------------------------------------------------------------- /resources/tj/lesson10_advance/tile_floor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/tj/lesson10_advance/tile_floor.jpg -------------------------------------------------------------------------------- /resources/tj/lesson10_advance/wooden_floor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tjbladez/gosu-opengl-tutorials/8f6c8ea0450f66c28577fec45b46aa7424da6998/resources/tj/lesson10_advance/wooden_floor.jpg -------------------------------------------------------------------------------- /resources/tj/lesson10_advance/world.json: -------------------------------------------------------------------------------- 1 | {"wooden_floor": [[{"x":-4,"y":0,"z":-4,"u":0,"v":0}, 2 | {"x":4,"y":0,"z":-4,"u":1 ,"v":0}, 3 | {"x":4,"y":0,"z":1,"u":1,"v": 1 }, 4 | {"x":-4,"y":0,"z":1,"u":0, "v": 1}]], 5 | "tile_floor": [[{"x":-4,"y":0,"z":-9,"u":0,"v":0}, 6 | {"x":0,"y":0,"z":-9,"u":1 ,"v":0}, 7 | {"x":0,"y":0,"z":-5,"u":1,"v": 1 }, 8 | {"x":-4,"y":0,"z":-5,"u":0, "v": 1}], 9 | [{"x":0,"y":0,"z":-9,"u":0,"v":0}, 10 | {"x":4,"y":0,"z":-9,"u":1 ,"v":0}, 11 | {"x":4,"y":0,"z":-5,"u":1,"v": 1 }, 12 | {"x":0,"y":0,"z":-5,"u":0, "v": 1}]], 13 | "hallway": [[{"x":0,"y":0,"z":-5,"u":0,"v":0}, 14 | {"x":1,"y":0,"z":-5,"u":1 ,"v":0}, 15 | {"x":1,"y":0,"z":-4,"u":1,"v": 1 }, 16 | {"x":0,"y":0,"z":-4,"u":0, "v": 1}]], 17 | "brick_wall": [[{"x":-4,"y":2,"z":-9,"u":0,"v":0}, 18 | {"x":-3,"y":2,"z":-9,"u":1 ,"v":0}, 19 | {"x":-3,"y":1,"z":-9,"u":1,"v": 0.968 }, 20 | {"x":-4,"y":1,"z":-9,"u":0, "v": 0.968}], 21 | [{"x":-3,"y":2,"z":-9,"u":0,"v":0}, 22 | {"x":-2,"y":2,"z":-9,"u":1 ,"v":0}, 23 | {"x":-2,"y":1,"z":-9,"u":1,"v": 0.968 }, 24 | {"x":-3,"y":1,"z":-9,"u":0, "v": 0.968}], 25 | [{"x":-2,"y":2,"z":-9,"u":0,"v":0}, 26 | {"x":-1,"y":2,"z":-9,"u":1 ,"v":0}, 27 | {"x":-1,"y":1,"z":-9,"u":1,"v": 0.968 }, 28 | {"x":-2,"y":1,"z":-9,"u":0, "v": 0.968}], 29 | [{"x":-1,"y":2,"z":-9,"u":0,"v":0}, 30 | {"x":0,"y":2,"z":-9,"u":1 ,"v":0}, 31 | {"x":0,"y":1,"z":-9,"u":1,"v": 0.968 }, 32 | {"x":-1,"y":1,"z":-9,"u":0, "v": 0.968}], 33 | [{"x":-4,"y":1,"z":-9,"u":0,"v":0}, 34 | {"x":-3,"y":1,"z":-9,"u":1 ,"v":0}, 35 | {"x":-3,"y":0,"z":-9,"u":1,"v": 0.968 }, 36 | {"x":-4,"y":0,"z":-9,"u":0, "v": 0.968}], 37 | [{"x":-3,"y":1,"z":-9,"u":0,"v":0}, 38 | {"x":-2,"y":1,"z":-9,"u":1 ,"v":0}, 39 | {"x":-2,"y":0,"z":-9,"u":1,"v": 0.968 }, 40 | {"x":-3,"y":0,"z":-9,"u":0, "v": 0.968}], 41 | [{"x":-2,"y":1,"z":-9,"u":0,"v":0}, 42 | {"x":-1,"y":1,"z":-9,"u":1 ,"v":0}, 43 | {"x":-1,"y":0,"z":-9,"u":1,"v": 0.968 }, 44 | {"x":-2,"y":0,"z":-9,"u":0, "v": 0.968}], 45 | [{"x":-1,"y":1,"z":-9,"u":0,"v":0}, 46 | {"x":0,"y":1,"z":-9,"u":1 ,"v":0}, 47 | {"x":0,"y":0,"z":-9,"u":1,"v": 0.968 }, 48 | {"x":-1,"y":0,"z":-9,"u":0, "v": 0.968}], 49 | [{"x":0,"y":2,"z":-9,"u":0,"v":0}, 50 | {"x":1,"y":2,"z":-9,"u":1 ,"v":0}, 51 | {"x":1,"y":1,"z":-9,"u":1,"v":0.968}, 52 | {"x":0,"y":1,"z":-9,"u":0, "v":0.968}], 53 | [{"x":1,"y":2,"z":-9,"u":0,"v":0}, 54 | {"x":2,"y":2,"z":-9,"u":1 ,"v":0}, 55 | {"x":2,"y":1,"z":-9,"u":1,"v": 0.968 }, 56 | {"x":1,"y":1,"z":-9,"u":0, "v": 0.968}], 57 | [{"x":2,"y":2,"z":-9,"u":0,"v":0}, 58 | {"x":3,"y":2,"z":-9,"u":1 ,"v":0}, 59 | {"x":3,"y":1,"z":-9,"u":1,"v": 0.968 }, 60 | {"x":2,"y":1,"z":-9,"u":0, "v": 0.968}], 61 | [{"x":3,"y":2,"z":-9,"u":0,"v":0}, 62 | {"x":4,"y":2,"z":-9,"u":1 ,"v":0}, 63 | {"x":4,"y":1,"z":-9,"u":1,"v": 0.968 }, 64 | {"x":3,"y":1,"z":-9,"u":0, "v": 0.968}], 65 | [{"x":0,"y":1,"z":-9,"u":0,"v":0}, 66 | {"x":1,"y":1,"z":-9,"u":1 ,"v":0}, 67 | {"x":1,"y":0,"z":-9,"u":1,"v": 0.968 }, 68 | {"x":0,"y":0,"z":-9,"u":0, "v": 0.968}], 69 | [{"x":1,"y":1,"z":-9,"u":0,"v":0}, 70 | {"x":2,"y":1,"z":-9,"u":1 ,"v":0}, 71 | {"x":2,"y":0,"z":-9,"u":1,"v": 0.968 }, 72 | {"x":1,"y":0,"z":-9,"u":0, "v": 0.968}], 73 | [{"x":2,"y":1,"z":-9,"u":0,"v":0}, 74 | {"x":3,"y":1,"z":-9,"u":1 ,"v":0}, 75 | {"x":3,"y":0,"z":-9,"u":1,"v": 0.968 }, 76 | {"x":2,"y":0,"z":-9,"u":0, "v": 0.968}], 77 | [{"x":3,"y":1,"z":-9,"u":0,"v":0}, 78 | {"x":4,"y":1,"z":-9,"u":1 ,"v":0}, 79 | {"x":4,"y":0,"z":-9,"u":1,"v": 0.968 }, 80 | {"x":3,"y":0,"z":-9,"u":0, "v": 0.968}], 81 | [{"x":-4,"y":2,"z":-5,"u":0,"v":0}, 82 | {"x":-4,"y":2,"z":-6,"u":1 ,"v":0}, 83 | {"x":-4,"y":1,"z":-6,"u":1,"v": 0.968 }, 84 | {"x":-4,"y":1,"z":-5,"u":0, "v": 0.968}], 85 | [{"x":-4,"y":2,"z":-6,"u":0,"v":0}, 86 | {"x":-4,"y":2,"z":-7,"u":1 ,"v":0}, 87 | {"x":-4,"y":1,"z":-7,"u":1,"v": 0.968 }, 88 | {"x":-4,"y":1,"z":-6,"u":0, "v": 0.968}], 89 | [{"x":-4,"y":2,"z":-7,"u":0,"v":0}, 90 | {"x":-4,"y":2,"z":-8,"u":1 ,"v":0}, 91 | {"x":-4,"y":1,"z":-8,"u":1,"v": 0.968 }, 92 | {"x":-4,"y":1,"z":-7,"u":0, "v": 0.968}], 93 | [{"x":-4,"y":2,"z":-8,"u":0,"v":0}, 94 | {"x":-4,"y":2,"z":-9,"u":1 ,"v":0}, 95 | {"x":-4,"y":1,"z":-9,"u":1,"v": 0.968 }, 96 | {"x":-4,"y":1,"z":-8,"u":0, "v": 0.968}], 97 | [{"x":-4,"y":1,"z":-5,"u":0,"v":0}, 98 | {"x":-4,"y":1,"z":-6,"u":1 ,"v":0}, 99 | {"x":-4,"y":0,"z":-6,"u":1,"v": 0.968 }, 100 | {"x":-4,"y":0,"z":-5,"u":0, "v": 0.968}], 101 | [{"x":-4,"y":1,"z":-6,"u":0,"v":0}, 102 | {"x":-4,"y":1,"z":-7,"u":1 ,"v":0}, 103 | {"x":-4,"y":0,"z":-7,"u":1,"v": 0.968 }, 104 | {"x":-4,"y":0,"z":-6,"u":0, "v": 0.968}], 105 | [{"x":-4,"y":1,"z":-7,"u":0,"v":0}, 106 | {"x":-4,"y":1,"z":-8,"u":1 ,"v":0}, 107 | {"x":-4,"y":0,"z":-8,"u":1,"v": 0.968 }, 108 | {"x":-4,"y":0,"z":-7,"u":0, "v": 0.968}], 109 | [{"x":-4,"y":1,"z":-8,"u":0,"v":0}, 110 | {"x":-4,"y":1,"z":-9,"u":1 ,"v":0}, 111 | {"x":-4,"y":0,"z":-9,"u":1,"v": 0.968 }, 112 | {"x":-4,"y":0,"z":-8,"u":0, "v": 0.968}], 113 | [{"x":4,"y":2,"z":-9,"u":0,"v":0}, 114 | {"x":4,"y":2,"z":-8,"u":1 ,"v":0}, 115 | {"x":4,"y":1,"z":-8,"u":1,"v": 0.968 }, 116 | {"x":4,"y":1,"z":-9,"u":0, "v": 0.968}], 117 | [{"x":4,"y":2,"z":-8,"u":0,"v":0}, 118 | {"x":4,"y":2,"z":-7,"u":1 ,"v":0}, 119 | {"x":4,"y":1,"z":-7,"u":1,"v": 0.968 }, 120 | {"x":4,"y":1,"z":-8,"u":0, "v": 0.968}], 121 | [{"x":4,"y":2,"z":-7,"u":0,"v":0}, 122 | {"x":4,"y":2,"z":-6,"u":1 ,"v":0}, 123 | {"x":4,"y":1,"z":-6,"u":1,"v": 0.968 }, 124 | {"x":4,"y":1,"z":-7,"u":0, "v": 0.968}], 125 | [{"x":4,"y":2,"z":-6,"u":0,"v":0}, 126 | {"x":4,"y":2,"z":-5,"u":1 ,"v":0}, 127 | {"x":4,"y":1,"z":-5,"u":1,"v": 0.968 }, 128 | {"x":4,"y":1,"z":-6,"u":0, "v": 0.968}], 129 | [{"x":4,"y":1,"z":-9,"u":0,"v":0}, 130 | {"x":4,"y":1,"z":-8,"u":1 ,"v":0}, 131 | {"x":4,"y":0,"z":-8,"u":1,"v": 0.968 }, 132 | {"x":4,"y":0,"z":-9,"u":0, "v": 0.968}], 133 | [{"x":4,"y":1,"z":-8,"u":0,"v":0}, 134 | {"x":4,"y":1,"z":-7,"u":1 ,"v":0}, 135 | {"x":4,"y":0,"z":-7,"u":1,"v": 0.968 }, 136 | {"x":4,"y":0,"z":-8,"u":0, "v": 0.968}], 137 | [{"x":4,"y":1,"z":-7,"u":0,"v":0}, 138 | {"x":4,"y":1,"z":-6,"u":1 ,"v":0}, 139 | {"x":4,"y":0,"z":-6,"u":1,"v": 0.968 }, 140 | {"x":4,"y":0,"z":-7,"u":0, "v": 0.968}], 141 | [{"x":4,"y":1,"z":-6,"u":0,"v":0}, 142 | {"x":4,"y":1,"z":-5,"u":1 ,"v":0}, 143 | {"x":4,"y":0,"z":-5,"u":1,"v": 0.968 }, 144 | {"x":4,"y":0,"z":-6,"u":0, "v": 0.968}], 145 | [{"x":4,"y":2,"z":-5,"u":0,"v":0}, 146 | {"x":3,"y":2,"z":-5,"u":1 ,"v":0}, 147 | {"x":3,"y":1,"z":-5,"u":1,"v": 0.968 }, 148 | {"x":4,"y":1,"z":-5,"u":0, "v": 0.968}], 149 | [{"x":3,"y":2,"z":-5,"u":0,"v":0}, 150 | {"x":2,"y":2,"z":-5,"u":1 ,"v":0}, 151 | {"x":2,"y":1,"z":-5,"u":1,"v": 0.968 }, 152 | {"x":3,"y":1,"z":-5,"u":0, "v": 0.968}], 153 | [{"x":2,"y":2,"z":-5,"u":0,"v":0}, 154 | {"x":1,"y":2,"z":-5,"u":1 ,"v":0}, 155 | {"x":1,"y":1,"z":-5,"u":1,"v": 0.968 }, 156 | {"x":2,"y":1,"z":-5,"u":0, "v": 0.968}], 157 | [{"x":1,"y":2,"z":-5,"u":0,"v":0}, 158 | {"x":0, "y":2,"z":-5,"u":1 ,"v":0}, 159 | {"x":0, "y":1,"z":-5,"u":1,"v": 0.968 }, 160 | {"x":1,"y":1,"z":-5,"u":0, "v": 0.968}], 161 | [{"x":4,"y":1,"z":-5,"u":0,"v":0}, 162 | {"x":3,"y":1,"z":-5,"u":1 ,"v":0}, 163 | {"x":3,"y":0,"z":-5,"u":1,"v": 0.968 }, 164 | {"x":4,"y":0,"z":-5,"u":0, "v": 0.968}], 165 | [{"x":3,"y":1,"z":-5,"u":0,"v":0}, 166 | {"x":2,"y":1,"z":-5,"u":1 ,"v":0}, 167 | {"x":2,"y":0,"z":-5,"u":1,"v": 0.968 }, 168 | {"x":3,"y":0,"z":-5,"u":0, "v": 0.968}], 169 | [{"x":2,"y":1,"z":-5,"u":0,"v":0}, 170 | {"x":1,"y":1,"z":-5,"u":1 ,"v":0}, 171 | {"x":1,"y":0,"z":-5,"u":1,"v": 0.968 }, 172 | {"x":2,"y":0,"z":-5,"u":0, "v": 0.968}], 173 | [{"x":0,"y":2,"z":-5,"u":0,"v":0}, 174 | {"x":-1,"y":2,"z":-5,"u":1 ,"v":0}, 175 | {"x":-1,"y":1,"z":-5,"u":1,"v":0.968}, 176 | {"x":0,"y":1,"z":-5,"u":0, "v":0.968}], 177 | [{"x":-1,"y":2,"z":-5,"u":0,"v":0}, 178 | {"x":-2,"y":2,"z":-5,"u":1 ,"v":0}, 179 | {"x":-2,"y":1,"z":-5,"u":1,"v": 0.968 }, 180 | {"x":-1,"y":1,"z":-5,"u":0, "v": 0.968}], 181 | [{"x":-2,"y":2,"z":-5,"u":0,"v":0}, 182 | {"x":-3,"y":2,"z":-5,"u":1 ,"v":0}, 183 | {"x":-3,"y":1,"z":-5,"u":1,"v": 0.968 }, 184 | {"x":-2,"y":1,"z":-5,"u":0, "v": 0.968}], 185 | [{"x":-3,"y":2,"z":-5,"u":0,"v":0}, 186 | {"x":-4,"y":2,"z":-5,"u":1 ,"v":0}, 187 | {"x":-4,"y":1,"z":-5,"u":1,"v": 0.968 }, 188 | {"x":-3,"y":1,"z":-5,"u":0, "v": 0.968}], 189 | [{"x":0,"y":1,"z":-5,"u":0,"v":0}, 190 | {"x":-1,"y":1,"z":-5,"u":1 ,"v":0}, 191 | {"x":-1,"y":0,"z":-5,"u":1,"v": 0.968 }, 192 | {"x":0,"y":0,"z":-5,"u":0, "v": 0.968}], 193 | [{"x":-1,"y":1,"z":-5,"u":0,"v":0}, 194 | {"x":-2,"y":1,"z":-5,"u":1 ,"v":0}, 195 | {"x":-2,"y":0,"z":-5,"u":1,"v": 0.968 }, 196 | {"x":-1,"y":0,"z":-5,"u":0, "v": 0.968}], 197 | [{"x":-2,"y":1,"z":-5,"u":0,"v":0}, 198 | {"x":-3,"y":1,"z":-5,"u":1 ,"v":0}, 199 | {"x":-3,"y":0,"z":-5,"u":1,"v": 0.968 }, 200 | {"x":-2,"y":0,"z":-5,"u":0, "v": 0.968}], 201 | [{"x":-3,"y":1,"z":-5,"u":0,"v":0}, 202 | {"x":-4,"y":1,"z":-5,"u":1 ,"v":0}, 203 | {"x":-4,"y":0,"z":-5,"u":1,"v": 0.968 }, 204 | {"x":-3,"y":0,"z":-5,"u":0, "v": 0.968}], 205 | [{"x":1,"y":1,"z":-5,"u":0,"v":0}, 206 | {"x":1,"y":1,"z":-4,"u":1 ,"v":0}, 207 | {"x":1,"y":0,"z":-4,"u":1,"v": 0.968 }, 208 | {"x":1,"y":0,"z":-5,"u":0, "v": 0.968}], 209 | [{"x":0,"y":1,"z":-5,"u":0,"v":0}, 210 | {"x":0,"y":1,"z":-4,"u":1 ,"v":0}, 211 | {"x":0,"y":0,"z":-4,"u":1,"v": 0.968 }, 212 | {"x":0,"y":0,"z":-5,"u":0, "v": 0.968}], 213 | [{"x":0,"y":1,"z":-5,"u":0,"v":0}, 214 | {"x":1,"y":1,"z":-5,"u":1 ,"v":0}, 215 | {"x":1,"y":1,"z":-4,"u":1,"v": 0.968 }, 216 | {"x":0,"y":1,"z":-4,"u":0, "v": 0.968}]], 217 | "small_brick_wall":[[{"x":-4,"y":2,"z":-4,"u":0,"v":0}, 218 | {"x":-3,"y":2,"z":-4,"u":1 ,"v":0}, 219 | {"x":-3,"y":1,"z":-4,"u":1,"v": 0.968 }, 220 | {"x":-4,"y":1,"z":-4,"u":0, "v": 0.968}], 221 | [{"x":-3,"y":2,"z":-4,"u":0,"v":0}, 222 | {"x":-2,"y":2,"z":-4,"u":1 ,"v":0}, 223 | {"x":-2,"y":1,"z":-4,"u":1,"v": 0.968 }, 224 | {"x":-3,"y":1,"z":-4,"u":0, "v": 0.968}], 225 | [{"x":-2,"y":2,"z":-4,"u":0,"v":0}, 226 | {"x":-1,"y":2,"z":-4,"u":1 ,"v":0}, 227 | {"x":-1,"y":1,"z":-4,"u":1,"v": 0.968 }, 228 | {"x":-2,"y":1,"z":-4,"u":0, "v": 0.968}], 229 | [{"x":-1,"y":2,"z":-4,"u":0,"v":0}, 230 | {"x":0,"y":2,"z":-4,"u":1 ,"v":0}, 231 | {"x":0,"y":1,"z":-4,"u":1,"v": 0.968 }, 232 | {"x":-1,"y":1,"z":-4,"u":0, "v": 0.968}], 233 | [{"x":-4,"y":1,"z":-4,"u":0,"v":0}, 234 | {"x":-3,"y":1,"z":-4,"u":1 ,"v":0}, 235 | {"x":-3,"y":0,"z":-4,"u":1,"v": 0.968 }, 236 | {"x":-4,"y":0,"z":-4,"u":0, "v": 0.968}], 237 | [{"x":-3,"y":1,"z":-4,"u":0,"v":0}, 238 | {"x":-2,"y":1,"z":-4,"u":1 ,"v":0}, 239 | {"x":-2,"y":0,"z":-4,"u":1,"v": 0.968 }, 240 | {"x":-3,"y":0,"z":-4,"u":0, "v": 0.968}], 241 | [{"x":-2,"y":1,"z":-4,"u":0,"v":0}, 242 | {"x":-1,"y":1,"z":-4,"u":1 ,"v":0}, 243 | {"x":-1,"y":0,"z":-4,"u":1,"v": 0.968 }, 244 | {"x":-2,"y":0,"z":-4,"u":0, "v": 0.968}], 245 | [{"x":-1,"y":1,"z":-4,"u":0,"v":0}, 246 | {"x":0,"y":1,"z":-4,"u":1 ,"v":0}, 247 | {"x":0,"y":0,"z":-4,"u":1,"v": 0.968 }, 248 | {"x":-1,"y":0,"z":-4,"u":0, "v": 0.968}], 249 | [{"x":0,"y":2,"z":-4,"u":0,"v":0}, 250 | {"x":1,"y":2,"z":-4,"u":1 ,"v":0}, 251 | {"x":1,"y":1,"z":-4,"u":1,"v":0.968}, 252 | {"x":0,"y":1,"z":-4,"u":0, "v":0.968}], 253 | [{"x":1,"y":2,"z":-4,"u":0,"v":0}, 254 | {"x":2,"y":2,"z":-4,"u":1 ,"v":0}, 255 | {"x":2,"y":1,"z":-4,"u":1,"v": 0.968 }, 256 | {"x":1,"y":1,"z":-4,"u":0, "v": 0.968}], 257 | [{"x":2,"y":2,"z":-4,"u":0,"v":0}, 258 | {"x":3,"y":2,"z":-4,"u":1 ,"v":0}, 259 | {"x":3,"y":1,"z":-4,"u":1,"v": 0.968 }, 260 | {"x":2,"y":1,"z":-4,"u":0, "v": 0.968}], 261 | [{"x":3,"y":2,"z":-4,"u":0,"v":0}, 262 | {"x":4,"y":2,"z":-4,"u":1 ,"v":0}, 263 | {"x":4,"y":1,"z":-4,"u":1,"v": 0.968 }, 264 | {"x":3,"y":1,"z":-4,"u":0, "v": 0.968}], 265 | [{"x":1,"y":1,"z":-4,"u":0,"v":0}, 266 | {"x":2,"y":1,"z":-4,"u":1 ,"v":0}, 267 | {"x":2,"y":0,"z":-4,"u":1,"v": 0.968 }, 268 | {"x":1,"y":0,"z":-4,"u":0, "v": 0.968}], 269 | [{"x":2,"y":1,"z":-4,"u":0,"v":0}, 270 | {"x":3,"y":1,"z":-4,"u":1 ,"v":0}, 271 | {"x":3,"y":0,"z":-4,"u":1,"v": 0.968 }, 272 | {"x":2,"y":0,"z":-4,"u":0, "v": 0.968}], 273 | [{"x":3,"y":1,"z":-4,"u":0,"v":0}, 274 | {"x":4,"y":1,"z":-4,"u":1 ,"v":0}, 275 | {"x":4,"y":0,"z":-4,"u":1,"v": 0.968 }, 276 | {"x":3,"y":0,"z":-4,"u":0, "v": 0.968}], 277 | [{"x":-4,"y":2,"z":1,"u":0,"v":0}, 278 | {"x":-4,"y":2,"z":0,"u":1 ,"v":0}, 279 | {"x":-4,"y":1,"z":0,"u":1,"v": 0.968 }, 280 | {"x":-4,"y":1,"z":1,"u":0, "v": 0.968}], 281 | [{"x":-4,"y":2,"z":0,"u":0,"v":0}, 282 | {"x":-4,"y":2,"z":-1,"u":1 ,"v":0}, 283 | {"x":-4,"y":1,"z":-1,"u":1,"v": 0.968 }, 284 | {"x":-4,"y":1,"z":0,"u":0, "v": 0.968}], 285 | [{"x":-4,"y":2,"z":-1,"u":0,"v":0}, 286 | {"x":-4,"y":2,"z":-2,"u":1 ,"v":0}, 287 | {"x":-4,"y":1,"z":-2, "u":1,"v": 0.968 }, 288 | {"x":-4,"y":1,"z":-1,"u":0, "v": 0.968}], 289 | [{"x":-4,"y":2,"z":-2,"u":0,"v":0}, 290 | {"x":-4,"y":2,"z":-3,"u":1 ,"v":0}, 291 | {"x":-4,"y":1,"z":-3,"u":1,"v": 0.968 }, 292 | {"x":-4,"y":1,"z":-2,"u":0, "v": 0.968}], 293 | [{"x":-4,"y":2,"z":-3,"u":0,"v":0}, 294 | {"x":-4,"y":2,"z":-4,"u":1 ,"v":0}, 295 | {"x":-4,"y":1,"z":-4,"u":1,"v": 0.968 }, 296 | {"x":-4,"y":1,"z":-3,"u":0, "v": 0.968}], 297 | [{"x":-4,"y":1,"z":1,"u":0,"v":0}, 298 | {"x":-4,"y":1,"z":0,"u":1 ,"v":0}, 299 | {"x":-4,"y":0,"z":0,"u":1,"v": 0.968 }, 300 | {"x":-4,"y":0,"z":1,"u":0, "v": 0.968}], 301 | [{"x":-4,"y":1,"z":0,"u":0,"v":0}, 302 | {"x":-4,"y":1,"z":-1,"u":1 ,"v":0}, 303 | {"x":-4,"y":0,"z":-1,"u":1,"v": 0.968 }, 304 | {"x":-4,"y":0,"z":0,"u":0, "v": 0.968}], 305 | [{"x":-4,"y":1,"z":-1,"u":0,"v":0}, 306 | {"x":-4,"y":1,"z":-2,"u":1 ,"v":0}, 307 | {"x":-4,"y":0,"z":-2, "u":1,"v": 0.968 }, 308 | {"x":-4,"y":0,"z":-1,"u":0, "v": 0.968}], 309 | [{"x":-4,"y":1,"z":-2,"u":0,"v":0}, 310 | {"x":-4,"y":1,"z":-3,"u":1 ,"v":0}, 311 | {"x":-4,"y":0,"z":-3,"u":1,"v": 0.968 }, 312 | {"x":-4,"y":0,"z":-2,"u":0, "v": 0.968}], 313 | [{"x":-4,"y":1,"z":-3,"u":0,"v":0}, 314 | {"x":-4,"y":1,"z":-4,"u":1 ,"v":0}, 315 | {"x":-4,"y":0,"z":-4,"u":1,"v": 0.968 }, 316 | {"x":-4,"y":0,"z":-3,"u":0, "v": 0.968}], 317 | [{"x":4,"y":2,"z":1,"u":0,"v":0}, 318 | {"x":4,"y":2,"z":0,"u":1 ,"v":0}, 319 | {"x":4,"y":1,"z":0,"u":1,"v": 0.968 }, 320 | {"x":4,"y":1,"z":1,"u":0, "v": 0.968}], 321 | [{"x":4,"y":2,"z":0,"u":0,"v":0}, 322 | {"x":4,"y":2,"z":-1,"u":1 ,"v":0}, 323 | {"x":4,"y":1,"z":-1,"u":1,"v": 0.968 }, 324 | {"x":4,"y":1,"z":0,"u":0, "v": 0.968}], 325 | [{"x":4,"y":2,"z":-1,"u":0,"v":0}, 326 | {"x":4,"y":2,"z":-2,"u":1 ,"v":0}, 327 | {"x":4,"y":1,"z":-2, "u":1,"v": 0.968 }, 328 | {"x":4,"y":1,"z":-1,"u":0, "v": 0.968}], 329 | [{"x":4,"y":2,"z":-2,"u":0,"v":0}, 330 | {"x":4,"y":2,"z":-3,"u":1 ,"v":0}, 331 | {"x":4,"y":1,"z":-3,"u":1,"v": 0.968 }, 332 | {"x":4,"y":1,"z":-2,"u":0, "v": 0.968}], 333 | [{"x":4,"y":2,"z":-3,"u":0,"v":0}, 334 | {"x":4,"y":2,"z":-4,"u":1 ,"v":0}, 335 | {"x":4,"y":1,"z":-4,"u":1,"v": 0.968 }, 336 | {"x":4,"y":1,"z":-3,"u":0, "v": 0.968}], 337 | [{"x":4,"y":1,"z":1,"u":0,"v":0}, 338 | {"x":4,"y":1,"z":0,"u":1 ,"v":0}, 339 | {"x":4,"y":0,"z":0,"u":1,"v": 0.968 }, 340 | {"x":4,"y":0,"z":1,"u":0, "v": 0.968}], 341 | [{"x":4,"y":1,"z":0,"u":0,"v":0}, 342 | {"x":4,"y":1,"z":-1,"u":1 ,"v":0}, 343 | {"x":4,"y":0,"z":-1,"u":1,"v": 0.968 }, 344 | {"x":4,"y":0,"z":0,"u":0, "v": 0.968}], 345 | [{"x":4,"y":1,"z":-1,"u":0,"v":0}, 346 | {"x":4,"y":1,"z":-2,"u":1 ,"v":0}, 347 | {"x":4,"y":0,"z":-2, "u":1,"v": 0.968 }, 348 | {"x":4,"y":0,"z":-1,"u":0, "v": 0.968}], 349 | [{"x":4,"y":1,"z":-2,"u":0,"v":0}, 350 | {"x":4,"y":1,"z":-3,"u":1 ,"v":0}, 351 | {"x":4,"y":0,"z":-3,"u":1,"v": 0.968 }, 352 | {"x":4,"y":0,"z":-2,"u":0, "v": 0.968}], 353 | [{"x":4,"y":1,"z":-3,"u":0,"v":0}, 354 | {"x":4,"y":1,"z":-4,"u":1 ,"v":0}, 355 | {"x":4,"y":0,"z":-4,"u":1,"v": 0.968 }, 356 | {"x":4,"y":0,"z":-3,"u":0, "v": 0.968}], 357 | [{"x":-4,"y":2,"z":1,"u":0,"v":0}, 358 | {"x":-3,"y":2,"z":1,"u":1 ,"v":0}, 359 | {"x":-3,"y":1,"z":1,"u":1,"v": 0.968 }, 360 | {"x":-4,"y":1,"z":1,"u":0, "v": 0.968}], 361 | [{"x":-3,"y":2,"z":1,"u":0,"v":0}, 362 | {"x":-2,"y":2,"z":1,"u":1 ,"v":0}, 363 | {"x":-2,"y":1,"z":1,"u":1,"v": 0.968 }, 364 | {"x":-3,"y":1,"z":1,"u":0, "v": 0.968}], 365 | [{"x":-2,"y":2,"z":1,"u":0,"v":0}, 366 | {"x":-1,"y":2,"z":1,"u":1 ,"v":0}, 367 | {"x":-1,"y":1,"z":1,"u":1,"v": 0.968 }, 368 | {"x":-2,"y":1,"z":1,"u":0, "v": 0.968}], 369 | [{"x":-1,"y":2,"z":1,"u":0,"v":0}, 370 | {"x":0,"y":2,"z":1,"u":1 ,"v":0}, 371 | {"x":0,"y":1,"z":1,"u":1,"v": 0.968 }, 372 | {"x":-1,"y":1,"z":1,"u":0, "v": 0.968}], 373 | [{"x":-4,"y":1,"z":1,"u":0,"v":0}, 374 | {"x":-3,"y":1,"z":1,"u":1 ,"v":0}, 375 | {"x":-3,"y":0,"z":1,"u":1,"v": 0.968 }, 376 | {"x":-4,"y":0,"z":1,"u":0, "v": 0.968}], 377 | [{"x":-3,"y":1,"z":1,"u":0,"v":0}, 378 | {"x":-2,"y":1,"z":1,"u":1 ,"v":0}, 379 | {"x":-2,"y":0,"z":1,"u":1,"v": 0.968 }, 380 | {"x":-3,"y":0,"z":1,"u":0, "v": 0.968}], 381 | [{"x":-2,"y":1,"z":1,"u":0,"v":0}, 382 | {"x":-1,"y":1,"z":1,"u":1 ,"v":0}, 383 | {"x":-1,"y":0,"z":1,"u":1,"v": 0.968 }, 384 | {"x":-2,"y":0,"z":1,"u":0, "v": 0.968}], 385 | [{"x":-1,"y":1,"z":1,"u":0,"v":0}, 386 | {"x":0,"y":1,"z":1,"u":1 ,"v":0}, 387 | {"x":0,"y":0,"z":1,"u":1,"v": 0.968 }, 388 | {"x":-1,"y":0,"z":1,"u":0, "v": 0.968}], 389 | [{"x":0,"y":2,"z":1,"u":0,"v":0}, 390 | {"x":1,"y":2,"z":1,"u":1 ,"v":0}, 391 | {"x":1,"y":1,"z":1,"u":1,"v":0.968}, 392 | {"x":0,"y":1,"z":1,"u":0, "v":0.968}], 393 | [{"x":1,"y":2,"z":1,"u":0,"v":0}, 394 | {"x":2,"y":2,"z":1,"u":1 ,"v":0}, 395 | {"x":2,"y":1,"z":1,"u":1,"v": 0.968 }, 396 | {"x":1,"y":1,"z":1,"u":0, "v": 0.968}], 397 | [{"x":2,"y":2,"z":1,"u":0,"v":0}, 398 | {"x":3,"y":2,"z":1,"u":1 ,"v":0}, 399 | {"x":3,"y":1,"z":1,"u":1,"v": 0.968 }, 400 | {"x":2,"y":1,"z":1,"u":0, "v": 0.968}], 401 | [{"x":3,"y":2,"z":1,"u":0,"v":0}, 402 | {"x":4,"y":2,"z":1,"u":1 ,"v":0}, 403 | {"x":4,"y":1,"z":1,"u":1,"v": 0.968 }, 404 | {"x":3,"y":1,"z":1,"u":0, "v": 0.968}], 405 | [{"x":1,"y":1,"z":1,"u":0,"v":0}, 406 | {"x":2,"y":1,"z":1,"u":1 ,"v":0}, 407 | {"x":2,"y":0,"z":1,"u":1,"v": 0.968 }, 408 | {"x":1,"y":0,"z":1,"u":0, "v": 0.968}], 409 | [{"x":2,"y":1,"z":1,"u":0,"v":0}, 410 | {"x":3,"y":1,"z":1,"u":1 ,"v":0}, 411 | {"x":3,"y":0,"z":1,"u":1,"v": 0.968 }, 412 | {"x":2,"y":0,"z":1,"u":0, "v": 0.968}], 413 | [{"x":3,"y":1,"z":1,"u":0,"v":0}, 414 | {"x":4,"y":1,"z":1,"u":1 ,"v":0}, 415 | {"x":4,"y":0,"z":1,"u":1,"v": 0.968 }, 416 | {"x":3,"y":0,"z":1,"u":0, "v": 0.968}], 417 | [{"x":0,"y":1,"z":1,"u":0,"v":0}, 418 | {"x":1,"y":1,"z":1,"u":1 ,"v":0}, 419 | {"x":1,"y":0,"z":1,"u":1,"v":0.968}, 420 | {"x":0,"y":0,"z":1,"u":0, "v":0.968}]], 421 | "ceiling": [[{"x":-4,"y":2,"z":-4,"u":0,"v":0}, 422 | {"x":-2,"y":2,"z":-4,"u":1 ,"v":0}, 423 | {"x":-2,"y":2,"z":-3,"u":1,"v": 1 }, 424 | {"x":-4,"y":2,"z":-3,"u":0, "v": 1}], 425 | [{"x":-2,"y":2,"z":-4,"u":0,"v":0}, 426 | {"x":0,"y":2,"z":-4,"u":1 ,"v":0}, 427 | {"x":0,"y":2,"z":-3,"u":1,"v": 1 }, 428 | {"x":-2,"y":2,"z":-3,"u":0, "v": 1}], 429 | [{"x":0,"y":2,"z":-4,"u":0,"v":0}, 430 | {"x":2,"y":2,"z":-4,"u":1 ,"v":0}, 431 | {"x":2,"y":2,"z":-3,"u":1,"v": 1 }, 432 | {"x":0,"y":2,"z":-3,"u":0, "v": 1}], 433 | [{"x":2,"y":2,"z":-4,"u":0,"v":0}, 434 | {"x":4,"y":2,"z":-4,"u":1 ,"v":0}, 435 | {"x":4,"y":2,"z":-3,"u":1,"v": 1 }, 436 | {"x":2,"y":2,"z":-3,"u":0, "v": 1}], 437 | [{"x":-4,"y":2,"z":-3,"u":0,"v":0}, 438 | {"x":-2,"y":2,"z":-3,"u":1 ,"v":0}, 439 | {"x":-2,"y":2,"z":-2,"u":1,"v": 1 }, 440 | {"x":-4,"y":2,"z":-2,"u":0, "v": 1}], 441 | [{"x":-2,"y":2,"z":-3,"u":0,"v":0}, 442 | {"x":0,"y":2,"z":-3,"u":1 ,"v":0}, 443 | {"x":0,"y":2,"z":-2,"u":1,"v": 1 }, 444 | {"x":-2,"y":2,"z":-2,"u":0, "v": 1}], 445 | [{"x":0,"y":2,"z":-3,"u":0,"v":0}, 446 | {"x":2,"y":2,"z":-3,"u":1 ,"v":0}, 447 | {"x":2,"y":2,"z":-2,"u":1,"v": 1 }, 448 | {"x":0,"y":2,"z":-2,"u":0, "v": 1}], 449 | [{"x":2,"y":2,"z":-3,"u":0,"v":0}, 450 | {"x":4,"y":2,"z":-3,"u":1 ,"v":0}, 451 | {"x":4,"y":2,"z":-2,"u":1,"v": 1 }, 452 | {"x":2,"y":2,"z":-2,"u":0, "v": 1}], 453 | [{"x":-4,"y":2,"z":-2,"u":0,"v":0}, 454 | {"x":-2,"y":2,"z":-2,"u":1 ,"v":0}, 455 | {"x":-2,"y":2,"z":-1,"u":1,"v": 1 }, 456 | {"x":-4,"y":2,"z":-1,"u":0, "v": 1}], 457 | [{"x":-2,"y":2,"z":-2,"u":0,"v":0}, 458 | {"x":0,"y":2,"z":-2,"u":1 ,"v":0}, 459 | {"x":0,"y":2,"z":-1,"u":1,"v": 1 }, 460 | {"x":-2,"y":2,"z":-1,"u":0, "v": 1}], 461 | [{"x":0,"y":2,"z":-2,"u":0,"v":0}, 462 | {"x":2,"y":2,"z":-2,"u":1 ,"v":0}, 463 | {"x":2,"y":2,"z":-1,"u":1,"v": 1 }, 464 | {"x":0,"y":2,"z":-1,"u":0, "v": 1}], 465 | [{"x":2,"y":2,"z":-2,"u":0,"v":0}, 466 | {"x":4,"y":2,"z":-2,"u":1 ,"v":0}, 467 | {"x":4,"y":2,"z":-1,"u":1,"v": 1 }, 468 | {"x":2,"y":2,"z":-1,"u":0, "v": 1}], 469 | [{"x":-4,"y":2,"z":-1,"u":0,"v":0}, 470 | {"x":-2,"y":2,"z":-1,"u":1 ,"v":0}, 471 | {"x":-2,"y":2,"z":0,"u":1,"v": 1 }, 472 | {"x":-4,"y":2,"z":0,"u":0, "v": 1}], 473 | [{"x":-2,"y":2,"z":-1,"u":0,"v":0}, 474 | {"x":0,"y":2,"z":-1,"u":1 ,"v":0}, 475 | {"x":0,"y":2,"z":0,"u":1,"v": 1 }, 476 | {"x":-2,"y":2,"z":0,"u":0, "v": 1}], 477 | [{"x":0,"y":2,"z":-1,"u":0,"v":0}, 478 | {"x":2,"y":2,"z":-1,"u":1 ,"v":0}, 479 | {"x":2,"y":2,"z":0,"u":1,"v": 1 }, 480 | {"x":0,"y":2,"z":0,"u":0, "v": 1}], 481 | [{"x":2,"y":2,"z":-1,"u":0,"v":0}, 482 | {"x":4,"y":2,"z":-1,"u":1 ,"v":0}, 483 | {"x":4,"y":2,"z":0,"u":1,"v": 1 }, 484 | {"x":2,"y":2,"z":0,"u":0, "v": 1}], 485 | [{"x":-4,"y":2,"z":0,"u":0,"v":0}, 486 | {"x":-2,"y":2,"z":0,"u":1 ,"v":0}, 487 | {"x":-2,"y":2,"z":1,"u":1,"v": 1 }, 488 | {"x":-4,"y":2,"z":1,"u":0, "v": 1}], 489 | [{"x":-2,"y":2,"z":0,"u":0,"v":0}, 490 | {"x":0,"y":2,"z":0,"u":1 ,"v":0}, 491 | {"x":0,"y":2,"z":1,"u":1,"v": 1 }, 492 | {"x":-2,"y":2,"z":1,"u":0, "v": 1}], 493 | [{"x":0,"y":2,"z":0,"u":0,"v":0}, 494 | {"x":2,"y":2,"z":0,"u":1 ,"v":0}, 495 | {"x":2,"y":2,"z":1,"u":1,"v": 1 }, 496 | {"x":0,"y":2,"z":1,"u":0, "v": 1}], 497 | [{"x":2,"y":2,"z":0,"u":0,"v":0}, 498 | {"x":4,"y":2,"z":0,"u":1 ,"v":0}, 499 | {"x":4,"y":2,"z":1,"u":1,"v": 1 }, 500 | {"x":2,"y":2,"z":1,"u":0, "v": 1}], 501 | [{"x":-4,"y":2,"z":-9,"u":0,"v":0}, 502 | {"x":-2,"y":2,"z":-9,"u":1 ,"v":0}, 503 | {"x":-2,"y":2,"z":-8,"u":1,"v": 1 }, 504 | {"x":-4,"y":2,"z":-8,"u":0, "v": 1}], 505 | [{"x":-2,"y":2,"z":-9,"u":0,"v":0}, 506 | {"x":0,"y":2,"z":-9,"u":1 ,"v":0}, 507 | {"x":0,"y":2,"z":-8,"u":1,"v": 1 }, 508 | {"x":-2,"y":2,"z":-8,"u":0, "v": 1}], 509 | [{"x":0,"y":2,"z":-9,"u":0,"v":0}, 510 | {"x":2,"y":2,"z":-9,"u":1 ,"v":0}, 511 | {"x":2,"y":2,"z":-8,"u":1,"v": 1 }, 512 | {"x":0,"y":2,"z":-8,"u":0, "v": 1}], 513 | [{"x":2,"y":2,"z":-9,"u":0,"v":0}, 514 | {"x":4,"y":2,"z":-9,"u":1 ,"v":0}, 515 | {"x":4,"y":2,"z":-8,"u":1,"v": 1 }, 516 | {"x":2,"y":2,"z":-8,"u":0, "v": 1}], 517 | [{"x":-4,"y":2,"z":-8,"u":0,"v":0}, 518 | {"x":-2,"y":2,"z":-8,"u":1 ,"v":0}, 519 | {"x":-2,"y":2,"z":-7,"u":1,"v": 1 }, 520 | {"x":-4,"y":2,"z":-7,"u":0, "v": 1}], 521 | [{"x":-2,"y":2,"z":-8,"u":0,"v":0}, 522 | {"x":0,"y":2,"z":-8,"u":1 ,"v":0}, 523 | {"x":0,"y":2,"z":-7,"u":1,"v": 1 }, 524 | {"x":-2,"y":2,"z":-7,"u":0, "v": 1}], 525 | [{"x":0,"y":2,"z":-8,"u":0,"v":0}, 526 | {"x":2,"y":2,"z":-8,"u":1 ,"v":0}, 527 | {"x":2,"y":2,"z":-7,"u":1,"v": 1 }, 528 | {"x":0,"y":2,"z":-7,"u":0, "v": 1}], 529 | [{"x":2,"y":2,"z":-8,"u":0,"v":0}, 530 | {"x":4,"y":2,"z":-8,"u":1 ,"v":0}, 531 | {"x":4,"y":2,"z":-7,"u":1,"v": 1 }, 532 | {"x":2,"y":2,"z":-7,"u":0, "v": 1}], 533 | [{"x":-4,"y":2,"z":-7,"u":0,"v":0}, 534 | {"x":-2,"y":2,"z":-7,"u":1 ,"v":0}, 535 | {"x":-2,"y":2,"z":-6,"u":1,"v": 1 }, 536 | {"x":-4,"y":2,"z":-6,"u":0, "v": 1}], 537 | [{"x":-2,"y":2,"z":-7,"u":0,"v":0}, 538 | {"x":0,"y":2,"z":-7,"u":1 ,"v":0}, 539 | {"x":0,"y":2,"z":-6,"u":1,"v": 1 }, 540 | {"x":-2,"y":2,"z":-6,"u":0, "v": 1}], 541 | [{"x":0,"y":2,"z":-7,"u":0,"v":0}, 542 | {"x":2,"y":2,"z":-7,"u":1 ,"v":0}, 543 | {"x":2,"y":2,"z":-6,"u":1,"v": 1 }, 544 | {"x":0,"y":2,"z":-6,"u":0, "v": 1}], 545 | [{"x":2,"y":2,"z":-7,"u":0,"v":0}, 546 | {"x":4,"y":2,"z":-7,"u":1 ,"v":0}, 547 | {"x":4,"y":2,"z":-6,"u":1,"v": 1 }, 548 | {"x":2,"y":2,"z":-6,"u":0, "v": 1}], 549 | [{"x":-4,"y":2,"z":-6,"u":0,"v":0}, 550 | {"x":-2,"y":2,"z":-6,"u":1 ,"v":0}, 551 | {"x":-2,"y":2,"z":-5,"u":1,"v": 1 }, 552 | {"x":-4,"y":2,"z":-5,"u":0, "v": 1}], 553 | [{"x":-2,"y":2,"z":-6,"u":0,"v":0}, 554 | {"x":0,"y":2,"z":-6,"u":1 ,"v":0}, 555 | {"x":0,"y":2,"z":-5,"u":1,"v": 1 }, 556 | {"x":-2,"y":2,"z":-5,"u":0, "v": 1}], 557 | [{"x":0,"y":2,"z":-6,"u":0,"v":0}, 558 | {"x":2,"y":2,"z":-6,"u":1 ,"v":0}, 559 | {"x":2,"y":2,"z":-5,"u":1,"v": 1 }, 560 | {"x":0,"y":2,"z":-5,"u":0, "v": 1}], 561 | [{"x":2,"y":2,"z":-6,"u":0,"v":0}, 562 | {"x":4,"y":2,"z":-6,"u":1 ,"v":0}, 563 | {"x":4,"y":2,"z":-5,"u":1,"v": 1 }, 564 | {"x":2,"y":2,"z":-5,"u":0, "v": 1}]]} -------------------------------------------------------------------------------- /using_nehe_lessons/lesson02.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../config/boot', __FILE__) 2 | 3 | class Window < Gosu::Window 4 | def initialize 5 | super(800, 600, false) 6 | self.caption = "Lesson #2 - Polygons" 7 | end 8 | 9 | def update 10 | end 11 | 12 | def draw 13 | gl do 14 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # see lesson01 15 | glMatrixMode(GL_PROJECTION) # see lesson01 16 | glLoadIdentity # see lesson01 17 | gluPerspective(45.0, width / height, 0.1, 100.0) # see lesson01 18 | glMatrixMode(GL_MODELVIEW) # see lesson01 19 | glLoadIdentity # see lesson01 20 | 21 | glTranslatef(-2, 0, -10) # see lesson01 22 | 23 | glBegin(GL_TRIANGLES) # see lesson01 24 | glVertex3f( 0, 1, 0) # see lesson01 25 | glVertex3f( 1, -1, 0) 26 | glVertex3f(-1, -1, 0) 27 | glEnd 28 | end 29 | end 30 | 31 | def button_down(id) 32 | if id == Gosu::KbEscape 33 | close 34 | end 35 | end 36 | end 37 | 38 | window = Window.new 39 | window.show -------------------------------------------------------------------------------- /using_nehe_lessons/lesson03.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../config/boot', __FILE__) 2 | 3 | class Window < Gosu::Window 4 | def initialize 5 | super(800, 600, false) 6 | self.caption = "Lesson #3 - Adding colors" 7 | end 8 | 9 | def update 10 | end 11 | 12 | def draw 13 | gl do 14 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #explained in nehe lesson02 [see lesson01] 15 | 16 | glMatrixMode(GL_PROJECTION) # see lesson01 17 | glLoadIdentity # see lesson01 18 | 19 | gluPerspective(45.0, width / height, 0.1, 100.0) # see lesson01 20 | 21 | glMatrixMode(GL_MODELVIEW) # see lesson01 22 | glLoadIdentity # see lesson01 23 | 24 | glTranslatef(-2, 0, -10) # see lesson01 25 | 26 | glBegin(GL_TRIANGLES) # see lesson01 27 | glColor3f(1, 0, 0) # sets color to be used using RBG 28 | glVertex3f( 0,1, 0) 29 | glColor3f(0, 1, 0) 30 | glVertex3f( 1, -1, 0) 31 | glColor3f(0, 0, 1) 32 | glVertex3f(-1, -1, 0) 33 | glEnd 34 | end 35 | end 36 | 37 | def button_down(id) 38 | if id == Gosu::KbEscape 39 | close 40 | end 41 | end 42 | end 43 | 44 | window = Window.new 45 | window.show -------------------------------------------------------------------------------- /using_nehe_lessons/lesson04.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../config/boot', __FILE__) 2 | 3 | class Window < Gosu::Window 4 | attr_accessor :rotation_angle 5 | 6 | def initialize 7 | super(800, 600, false) 8 | self.caption = "Lesson #4 - Rotation animation" 9 | @rotation_angle = 0 10 | end 11 | 12 | def update 13 | @rotation_angle += 0.2 14 | end 15 | 16 | def draw 17 | gl do 18 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # see lesson01 19 | 20 | glMatrixMode(GL_PROJECTION) # see lesson01 21 | glLoadIdentity 22 | 23 | gluPerspective(45.0, width / height, 0.1, 100.0) # see lesson01 24 | 25 | glMatrixMode(GL_MODELVIEW) # see lesson01 26 | glLoadIdentity # see lesson01 27 | 28 | glTranslatef(-2, 0, -10) # see lesson01 29 | 30 | glRotatef(@rotation_angle, 0, 1, 0) # rotate object around vector set by traveling to x,y,z from current unit, angle is in degrees 31 | 32 | glBegin(GL_TRIANGLES) # see lesson01 33 | glColor3f(1, 0, 0) # see nehe03 34 | glVertex3f( 0,1, 0) 35 | glColor3f(0, 1, 0) 36 | glVertex3f( 1, -1, 0) 37 | glColor3f(0, 0, 1) 38 | glVertex3f(-1, -1, 0) 39 | glEnd 40 | end 41 | end 42 | 43 | def button_down(id) 44 | close if id == Gosu::KbEscape 45 | end 46 | end 47 | 48 | window = Window.new 49 | window.show -------------------------------------------------------------------------------- /using_nehe_lessons/lesson05.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../config/boot', __FILE__) 2 | 3 | class Window < Gosu::Window 4 | attr_accessor :rotation_angle 5 | 6 | def initialize 7 | super(800, 600, false) 8 | self.caption = "Lesson #5 - 3D Shapes" 9 | @rotation_angle = 0 10 | end 11 | 12 | def update 13 | @rotation_angle += 0.2 14 | end 15 | 16 | def draw 17 | gl do 18 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # see lesson01 19 | 20 | glMatrixMode(GL_PROJECTION) # see lesson01 21 | glLoadIdentity # see lesson01 22 | 23 | gluPerspective(45.0, width / height, 0.1, 100.0) # see lesson01 24 | 25 | glMatrixMode(GL_MODELVIEW) # see lesson01 26 | glLoadIdentity # see lesson01 27 | 28 | glTranslatef(0, 0, -7) # see lesson01 29 | 30 | glRotatef(@rotation_angle, 0.0, 1.0, 0.0) # see nehe04 31 | 32 | glBegin(GL_TRIANGLES) # see lesson01 33 | glColor3f(1, 0, 0) 34 | glVertex3f( 0, 1, 0) 35 | glColor3f(0, 1, 0) 36 | glVertex3f(-1, -1, 1) 37 | glColor3f(0, 0, 1) 38 | glVertex3f(1, -1, 1) 39 | 40 | glColor3f(1, 0, 0) 41 | glVertex3f( 0, 1, 0) 42 | glColor3f(0, 1, 0) 43 | glVertex3f( 1, -1, 1) 44 | glColor3f(0, 0, 1) 45 | glVertex3f(1, -1, -1) 46 | 47 | glColor3f(1, 0, 0) 48 | glVertex3f( 0, 1, 0) 49 | glColor3f(0, 0, 1) 50 | glVertex3f(-1, -1, 1) 51 | glColor3f(0, 0, 1) 52 | glVertex3f(-1, -1, -1) 53 | 54 | glColor3f(1, 0, 0) 55 | glVertex3f( 0, 1, 0) 56 | glColor3f(0, 1, 0) 57 | glVertex3f(-1, -1, -1) 58 | glColor3f(0, 0, 1) 59 | glVertex3f(1, -1, -1) 60 | glEnd 61 | 62 | glColor3f(1, 0, 0) 63 | glBegin(GL_QUADS) 64 | glVertex3f(1, -1, 1) 65 | glVertex3f(1, -1, -1) 66 | glVertex3f(-1, -1, -1) 67 | glVertex3f(-1, -1, 1) 68 | glEnd 69 | end 70 | end 71 | 72 | def button_down(id) 73 | close if id == Gosu::KbEscape 74 | end 75 | end 76 | 77 | window = Window.new 78 | window.show -------------------------------------------------------------------------------- /using_nehe_lessons/lesson06.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../config/boot', __FILE__) 2 | 3 | class Texture 4 | attr_accessor :info 5 | def initialize(window) 6 | @image = Gosu::Image.new(window, "resources/nehe/lesson06/ruby.png", true) 7 | @info = @image.gl_tex_info 8 | end 9 | end 10 | class Window < Gosu::Window 11 | 12 | def initialize 13 | super(800, 600, false) 14 | self.caption = "Lesson #6 - Texture Mapping" 15 | @texture = Texture.new(self) 16 | @texture_info = @texture.info 17 | @x_angle = @y_angle = @z_angle = 0 18 | end 19 | 20 | def update 21 | @x_angle += 0.3 22 | @y_angle += 0.2 23 | @z_angle += 0.4 24 | end 25 | 26 | def draw 27 | gl do 28 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #see lesson 01 29 | 30 | glEnable(GL_DEPTH_TEST) # enables depth testing 31 | 32 | # Our depth function. Everything that is less or equal the actual value gets drawn. Depth buffet value is 1/z 33 | glDepthFunc(GL_LEQUAL) 34 | 35 | glMatrixMode(GL_PROJECTION) #see lesson01 36 | glLoadIdentity # see lesson01 37 | 38 | gluPerspective(45.0, width / height, 0.1, 100.0) #see lesson 01 39 | glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) #Perspective correction calculation for most correct/highest quality value 40 | glMatrixMode(GL_MODELVIEW) #see lesson 01 41 | glLoadIdentity #see lesson 01 42 | 43 | glTranslate(0, 0, -10) #see lesson 01 44 | 45 | glEnable(GL_TEXTURE_2D) #see lesson 01 46 | glBindTexture(GL_TEXTURE_2D, @texture_info.tex_name) #see lesson 01 47 | 48 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR) #linear filter when image is larger than actual texture 49 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) #linear filter when image is smaller than actual texture 50 | glRotatef(@x_angle, 1, 0, 0) # see nehe04 51 | glRotatef(@y_angle, 0, 1, 0) # see nehe04 52 | glRotatef(@z_angle, 0, 0, 1) # see nehe04 53 | 54 | glBegin(GL_QUADS) 55 | glTexCoord2f(0, 0); glVertex3f(-1, -1, 1) # see lesson 01 56 | glTexCoord2f(1, 0); glVertex3f( 1, -1, 1) 57 | glTexCoord2f(1, 1); glVertex3f( 1, 1, 1) 58 | glTexCoord2f(0, 1); glVertex3f(-1, 1, 1) 59 | glTexCoord2f(1, 0); glVertex3f(-1, -1, -1) 60 | glTexCoord2f(1, 1); glVertex3f(-1, 1, -1) 61 | glTexCoord2f(0, 1); glVertex3f( 1, 1, -1) 62 | glTexCoord2f(0, 0); glVertex3f( 1, -1, -1) 63 | 64 | glTexCoord2f(0, 1); glVertex3f(-1, 1, -1) 65 | glTexCoord2f(0, 0); glVertex3f(-1, 1, 1) 66 | glTexCoord2f(1, 0); glVertex3f( 1, 1, 1) 67 | glTexCoord2f(1, 1); glVertex3f( 1, 1, -1) 68 | 69 | glTexCoord2f(1, 1); glVertex3f(-1, -1, -1) 70 | glTexCoord2f(0, 1); glVertex3f( 1, -1, -1) 71 | glTexCoord2f(0, 0); glVertex3f( 1, -1, 1) 72 | glTexCoord2f(1, 0); glVertex3f(-1, -1, 1) 73 | 74 | glTexCoord2f(1, 0); glVertex3f( 1, -1, -1) 75 | glTexCoord2f(1, 1); glVertex3f( 1, 1, -1) 76 | glTexCoord2f(0, 1); glVertex3f( 1, 1, 1) 77 | glTexCoord2f(0, 0); glVertex3f( 1, -1, 1) 78 | 79 | glTexCoord2f(0, 0); glVertex3f(-1, -1, -1) 80 | glTexCoord2f(1, 0); glVertex3f(-1, -1, 1) 81 | glTexCoord2f(1, 1); glVertex3f(-1, 1, 1) 82 | glTexCoord2f(0, 1); glVertex3f(-1, 1, -1) 83 | glEnd 84 | end 85 | end 86 | 87 | def button_down(id) 88 | if id == Gosu::KbEscape 89 | close 90 | end 91 | end 92 | end 93 | 94 | window = Window.new 95 | window.show -------------------------------------------------------------------------------- /using_nehe_lessons/lesson07.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../config/boot', __FILE__) 2 | 3 | class Texture 4 | attr_accessor :info 5 | def initialize(window) 6 | @image = Gosu::Image.new(window, "resources/nehe/lesson07/crate.png", true) 7 | @info = @image.gl_tex_info 8 | end 9 | end 10 | 11 | class Window < Gosu::Window 12 | attr_accessor :current_filter 13 | 14 | def initialize 15 | super(800, 600, false) 16 | self.caption = "Lesson #7 - Texture Filters, Lighting and Keyboard Control" 17 | initialize_light 18 | initialize_textures 19 | @x_angle = @y_angle = 0 20 | @x_change = @y_change = 0.2 21 | @z_depth = -5 22 | @light_on = false 23 | end 24 | 25 | def initialize_light 26 | @ambient_light = [0.5, 0.5, 0.5, 1] # ambient light - lights all objects on the scene equally, format is RGBA 27 | @diffuse_light = [1, 1, 1, 1] # diffuse light is created by the light source and reflects off the surface of an object, format is also RGBA 28 | @light_postion = [0, 0, 2, 1] # position of the light source from the current point 29 | end 30 | 31 | def initialize_textures 32 | glGetError 33 | #note that window needs to keep texture variables and not just tex_name which is a fixnum in order to 34 | #reference texture and prevent it collected by the GC 35 | @nearest = Texture.new(self) 36 | glBindTexture(GL_TEXTURE_2D, @nearest.info.tex_name); # see lesson 1 37 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST) # Nearest filter is the worst on quality 38 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST) # but fastest and lowest need for processing power 39 | 40 | @linear = Texture.new(self) 41 | glBindTexture(GL_TEXTURE_2D, @linear.info.tex_name); 42 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) # Linear filter, good quality - high demands see nehe06 43 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR) 44 | 45 | @minimap = Texture.new(self) 46 | glBindTexture(GL_TEXTURE_2D, @minimap.info.tex_name); 47 | texture = glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_FLOAT) #use texture data to get data for buildimg a mipmap 48 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 49 | # Mipmapping. OpenGL tried to build different sized high quality texture. When you draw it OpenGL will select the best 50 | # looking texture from ones it built and draw that instead of resizing the original image which can cause detail loss 51 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST) 52 | gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 128, 128, GL_RGB, GL_FLOAT, texture) # building mipmaps 53 | @filters = [@nearest.info.tex_name, @linear.info.tex_name, @minimap.info.tex_name] 54 | end 55 | 56 | def update 57 | @z_depth -= 0.2 if button_down? Gosu::Button::KbPageUp 58 | @z_depth += 0.2 if button_down? Gosu::Button::KbPageDown 59 | @x_change -= 0.01 if button_down? Gosu::Button::KbUp 60 | @x_change += 0.01 if button_down? Gosu::Button::KbDown 61 | @y_change -= 0.01 if button_down? Gosu::Button::KbLeft 62 | @y_change += 0.01 if button_down? Gosu::Button::KbRight 63 | @x_angle += @x_change 64 | @y_angle += @y_change 65 | end 66 | 67 | def change_filter! 68 | index = @filters.index(current_filter) 69 | index > 1 ? index = 0 : index += 1 70 | @current_filter = @filters[index] 71 | end 72 | 73 | def current_filter 74 | @current_filter ||= @filters.first 75 | end 76 | 77 | def draw 78 | gl do 79 | glClearColor(0,0,0,0.5) #see lesson 01 80 | glClearDepth(1) #see lesson 01 81 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #see lesson 01 82 | glEnable(GL_DEPTH_TEST) # see nehe06 83 | glDepthFunc(GL_LEQUAL) # see nehe06 84 | 85 | glMatrixMode(GL_PROJECTION) #see lesson01 86 | glLoadIdentity # see lesson01 87 | gluPerspective(45.0, width / height, 0.1, 100.0) #see lesson 01 88 | glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) #Perspective correction calculation for most correct/highest quality value 89 | glMatrixMode(GL_MODELVIEW) #see lesson 01 90 | glLoadIdentity #see lesson 01 91 | 92 | 93 | glEnable(GL_TEXTURE_2D) #see lesson01 94 | glShadeModel(GL_SMOOTH) # selects smooth shading 95 | glLightfv(GL_LIGHT1, GL_AMBIENT, @ambient_light) # sets ambient light for light source 96 | glLightfv(GL_LIGHT1, GL_DIFFUSE, @diffuse_light) # sets diffuse light for light source 97 | glLightfv(GL_LIGHT1, GL_POSITION, @light_postion) # sets position of light 98 | glEnable(GL_LIGHT1) # enables prepared light source 99 | @light_on ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING) # enables / disables lighting of the scene based on light switch 100 | glTranslate(0, 0, @z_depth) #see lesson 01 101 | 102 | glBindTexture(GL_TEXTURE_2D, current_filter) #see lesson 01 103 | glRotatef(@x_angle, 1, 0, 0) # see nehe04 104 | glRotatef(@y_angle, 0, 1, 0) # see nehe04 105 | 106 | glBegin(GL_QUADS) 107 | # normal pointing to viewer. Normal is a line from the middle of the polygon at 90 degree angle. It is needed to tell opengl which 108 | # direction the polygon is facing. 109 | glNormal3f(0, 0, 1) 110 | glTexCoord2f(0, 0); glVertex3f(-1, -1, 1) # see lesson 01 111 | glTexCoord2f(1, 0); glVertex3f( 1, -1, 1) 112 | glTexCoord2f(1, 1); glVertex3f( 1, 1, 1) 113 | glTexCoord2f(0, 1); glVertex3f(-1, 1, 1) 114 | 115 | glNormal3f(0, 0, -1) # normal point away from viewer 116 | glTexCoord2f(1, 0); glVertex3f(-1, -1, -1) 117 | glTexCoord2f(1, 1); glVertex3f(-1, 1, -1) 118 | glTexCoord2f(0, 1); glVertex3f( 1, 1, -1) 119 | glTexCoord2f(0, 0); glVertex3f( 1, -1, -1) 120 | 121 | glNormal3f(0, 1, 0) 122 | glTexCoord2f(0, 1); glVertex3f(-1, 1, -1) 123 | glTexCoord2f(0, 0); glVertex3f(-1, 1, 1) 124 | glTexCoord2f(1, 0); glVertex3f( 1, 1, 1) 125 | glTexCoord2f(1, 1); glVertex3f( 1, 1, -1) 126 | 127 | glNormal3f(0, -1, 0) 128 | glTexCoord2f(1, 1); glVertex3f(-1, -1, -1) 129 | glTexCoord2f(0, 1); glVertex3f( 1, -1, -1) 130 | glTexCoord2f(0, 0); glVertex3f( 1, -1, 1) 131 | glTexCoord2f(1, 0); glVertex3f(-1, -1, 1) 132 | 133 | glNormal3f(1, 0, 0) 134 | glTexCoord2f(1, 0); glVertex3f( 1, -1, -1) 135 | glTexCoord2f(1, 1); glVertex3f( 1, 1, -1) 136 | glTexCoord2f(0, 1); glVertex3f( 1, 1, 1) 137 | glTexCoord2f(0, 0); glVertex3f( 1, -1, 1) 138 | 139 | glNormal3f(-1, 0, 0) 140 | glTexCoord2f(0, 0); glVertex3f(-1, -1, -1) 141 | glTexCoord2f(1, 0); glVertex3f(-1, -1, 1) 142 | glTexCoord2f(1, 1); glVertex3f(-1, 1, 1) 143 | glTexCoord2f(0, 1); glVertex3f(-1, 1, -1) 144 | glEnd 145 | end 146 | end 147 | 148 | def button_down(id) 149 | case id 150 | when Gosu::Button::KbEscape then close 151 | when Gosu::Button::KbL then @light_on = !@light_on # switch light on or off is L is pressed 152 | when Gosu::Button::KbF then change_filter! # change filter if F is pressed 153 | end 154 | end 155 | end 156 | 157 | window = Window.new 158 | window.show -------------------------------------------------------------------------------- /using_nehe_lessons/lesson08.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../config/boot', __FILE__) 2 | 3 | class Texture 4 | attr_accessor :info 5 | def initialize(window) 6 | @image = Gosu::Image.new(window, "resources/nehe/lesson08/Glass.bmp", true) 7 | @info = @image.gl_tex_info 8 | end 9 | end 10 | 11 | class Window < Gosu::Window 12 | attr_accessor :current_filter 13 | 14 | def initialize 15 | super(800, 600, false) 16 | self.caption = "Lesson #8 - Texture blending, transparency" 17 | initialize_light 18 | initialize_textures 19 | @x_angle = @y_angle = 0 20 | @x_change = @y_change = 0.2 21 | @z_depth = -5 22 | @light_on = false 23 | @blending 24 | end 25 | 26 | def initialize_light 27 | @ambient_light = [0.5, 0.5, 0.5, 1] # see nehe07 28 | @diffuse_light = [1, 1, 1, 1] # see nehe07 29 | @light_postion = [0, 0, 2, 1] # see nehe07 30 | end 31 | 32 | def initialize_textures 33 | glGetError 34 | @nearest = Texture.new(self) 35 | glBindTexture(GL_TEXTURE_2D, @nearest.info.tex_name) # see lesson 1 36 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST) # see nehe07 37 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST) # see nehe07 38 | 39 | @linear = Texture.new(self) 40 | glBindTexture(GL_TEXTURE_2D, @linear.info.tex_name) 41 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) # see nehe06 42 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR) 43 | 44 | @minimap = Texture.new(self) 45 | glBindTexture(GL_TEXTURE_2D, @minimap.info.tex_name) 46 | texture = glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_FLOAT) # see nehe07 47 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 48 | 49 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST) # see nehe07 50 | gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 128, 128, GL_RGB, GL_FLOAT, texture) # see nehe07 51 | @filters = [@nearest.info.tex_name, @linear.info.tex_name, @minimap.info.tex_name] 52 | end 53 | 54 | def update 55 | @z_depth -= 0.2 if button_down? Gosu::Button::KbPageUp 56 | @z_depth += 0.2 if button_down? Gosu::Button::KbPageDown 57 | @x_change -= 0.01 if button_down? Gosu::Button::KbUp 58 | @x_change += 0.01 if button_down? Gosu::Button::KbDown 59 | @y_change -= 0.01 if button_down? Gosu::Button::KbLeft 60 | @y_change += 0.01 if button_down? Gosu::Button::KbRight 61 | @x_angle += @x_change 62 | @y_angle += @y_change 63 | end 64 | 65 | def change_filter! 66 | index = @filters.index(current_filter) 67 | index > 1 ? index = 0 : index += 1 68 | @current_filter = @filters[index] 69 | end 70 | 71 | def current_filter 72 | @current_filter ||= @filters.first 73 | end 74 | 75 | def draw 76 | gl do 77 | glClearColor(0,0,0,0.5) #see lesson 01 78 | glClearDepth(1) #see lesson 01 79 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #see lesson 01 80 | glEnable(GL_DEPTH_TEST) # see nehe06 81 | glDepthFunc(GL_LEQUAL) # see nehe06 82 | 83 | glMatrixMode(GL_PROJECTION) #see lesson01 84 | glLoadIdentity # see lesson01 85 | gluPerspective(45.0, width / height, 0.1, 100.0) #see lesson 01 86 | glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) #see nehe07 87 | glMatrixMode(GL_MODELVIEW) #see lesson 01 88 | glLoadIdentity #see lesson 01 89 | 90 | glColor4f(1.0,1.0,1.0,0.5) # full brightness, 50% opacity 91 | glBlendFunc(GL_SRC_ALPHA,GL_ONE) # blending function for translucency based on alpha source 92 | 93 | glEnable(GL_TEXTURE_2D) #see lesson01 94 | glShadeModel(GL_SMOOTH) # see nehe07 95 | glLightfv(GL_LIGHT1, GL_AMBIENT, @ambient_light) # see nehe07 96 | glLightfv(GL_LIGHT1, GL_DIFFUSE, @diffuse_light) # see nehe07 97 | glLightfv(GL_LIGHT1, GL_POSITION, @light_postion) # see nehe07 98 | glEnable(GL_LIGHT1) # see nehe07 99 | @light_on ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING) # see nehe07 100 | if @blending 101 | glEnable(GL_BLEND) # enable blending 102 | glDisable(GL_DEPTH_TEST) # disable depth 103 | else 104 | glDisable(GL_BLEND) 105 | glEnable(GL_DEPTH_TEST) 106 | end 107 | glTranslate(0, 0, @z_depth) #see lesson 01 108 | 109 | glBindTexture(GL_TEXTURE_2D, current_filter) #see lesson 01 110 | glRotatef(@x_angle, 1, 0, 0) # see nehe04 111 | glRotatef(@y_angle, 0, 1, 0) # see nehe04 112 | 113 | glBegin(GL_QUADS) 114 | glNormal3f(0, 0, 1) # see nehe07 115 | glTexCoord2f(0, 0); glVertex3f(-1, -1, 1) # see lesson 01 116 | glTexCoord2f(1, 0); glVertex3f( 1, -1, 1) 117 | glTexCoord2f(1, 1); glVertex3f( 1, 1, 1) 118 | glTexCoord2f(0, 1); glVertex3f(-1, 1, 1) 119 | 120 | glNormal3f(0, 0, -1) 121 | glTexCoord2f(1, 0); glVertex3f(-1, -1, -1) 122 | glTexCoord2f(1, 1); glVertex3f(-1, 1, -1) 123 | glTexCoord2f(0, 1); glVertex3f( 1, 1, -1) 124 | glTexCoord2f(0, 0); glVertex3f( 1, -1, -1) 125 | 126 | glNormal3f(0, 1, 0) 127 | glTexCoord2f(0, 1); glVertex3f(-1, 1, -1) 128 | glTexCoord2f(0, 0); glVertex3f(-1, 1, 1) 129 | glTexCoord2f(1, 0); glVertex3f( 1, 1, 1) 130 | glTexCoord2f(1, 1); glVertex3f( 1, 1, -1) 131 | 132 | glNormal3f(0, -1, 0) 133 | glTexCoord2f(1, 1); glVertex3f(-1, -1, -1) 134 | glTexCoord2f(0, 1); glVertex3f( 1, -1, -1) 135 | glTexCoord2f(0, 0); glVertex3f( 1, -1, 1) 136 | glTexCoord2f(1, 0); glVertex3f(-1, -1, 1) 137 | 138 | glNormal3f(1, 0, 0) 139 | glTexCoord2f(1, 0); glVertex3f( 1, -1, -1) 140 | glTexCoord2f(1, 1); glVertex3f( 1, 1, -1) 141 | glTexCoord2f(0, 1); glVertex3f( 1, 1, 1) 142 | glTexCoord2f(0, 0); glVertex3f( 1, -1, 1) 143 | 144 | glNormal3f(-1, 0, 0) 145 | glTexCoord2f(0, 0); glVertex3f(-1, -1, -1) 146 | glTexCoord2f(1, 0); glVertex3f(-1, -1, 1) 147 | glTexCoord2f(1, 1); glVertex3f(-1, 1, 1) 148 | glTexCoord2f(0, 1); glVertex3f(-1, 1, -1) 149 | glEnd 150 | end 151 | end 152 | 153 | def button_down(id) 154 | case id 155 | when Gosu::Button::KbEscape then close 156 | when Gosu::Button::KbL then @light_on = !@light_on 157 | when Gosu::Button::KbF then change_filter! 158 | when Gosu::Button::KbB then @blending = !@blending 159 | end 160 | end 161 | end 162 | 163 | window = Window.new 164 | window.show -------------------------------------------------------------------------------- /using_nehe_lessons/lesson09.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../../config/boot', __FILE__) 2 | 3 | class Texture 4 | attr_accessor :index 5 | def initialize(window) 6 | @image = Gosu::Image.new(window, "resources/nehe/lesson09/Star.bmp", true) 7 | @index = @image.gl_tex_info.tex_name 8 | end 9 | end 10 | 11 | class Star 12 | attr_accessor :colors, :distance, :angle 13 | 14 | def color_randomly 15 | self.colors = [rand(256), rand(256), rand(256)] 16 | end 17 | end 18 | 19 | class Window < Gosu::Window 20 | STAR_NUMBER = 50 21 | 22 | def initialize 23 | super(800, 600, false) 24 | self.caption = "Lesson #9 - Moving bitmaps in 3D space" 25 | @texture = Texture.new(self) 26 | initialize_defaults 27 | initialize_stars 28 | end 29 | 30 | def initialize_defaults 31 | @twinkle_on = false 32 | @tilt = 90 33 | @zoom = -15 34 | @spin = 0 35 | end 36 | 37 | def initialize_stars 38 | @stars = [] 39 | STAR_NUMBER.times do |i| 40 | @stars << Star.new.tap do |star| 41 | star.angle = 0 42 | star.distance = 7 * i.to_f / STAR_NUMBER 43 | star.color_randomly 44 | end 45 | end 46 | end 47 | 48 | def update 49 | @zoom -= 0.2 if button_down? Gosu::Button::KbPageUp 50 | @zoom += 0.2 if button_down? Gosu::Button::KbPageDown 51 | @tilt -= 0.5 if button_down? Gosu::Button::KbUp 52 | @tilt += 0.5 if button_down? Gosu::Button::KbDown 53 | @spin += 0.01 54 | end 55 | 56 | def draw_star(star) 57 | red, green, blue = * star.colors 58 | glColor4ub(red, green, blue, 255) 59 | glBegin(GL_QUADS) 60 | glTexCoord2f(0, 0); glVertex3f(-1,-1, 0) 61 | glTexCoord2f(1, 0); glVertex3f( 1,-1, 0) 62 | glTexCoord2f(1, 1); glVertex3f( 1, 1, 0) 63 | glTexCoord2f(0, 1); glVertex3f(-1, 1, 0) 64 | glEnd 65 | end 66 | 67 | # see lesson 01 and nehe02 68 | def init_scene 69 | glEnable(GL_TEXTURE_2D) 70 | glShadeModel(GL_SMOOTH) 71 | glClearColor(0,0,0,0.5) 72 | glClearDepth(1) 73 | glBlendFunc(GL_SRC_ALPHA,GL_ONE) #see nehe08 74 | glEnable(GL_BLEND) 75 | end 76 | 77 | # see lesson 01 78 | def add_perspective_to_scene 79 | glMatrixMode(GL_PROJECTION) 80 | glLoadIdentity 81 | gluPerspective(45.0, width / height, 0.1, 100.0) 82 | glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) #see nehe07 83 | end 84 | 85 | def draw 86 | gl do 87 | init_scene 88 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 89 | glBindTexture(GL_TEXTURE_2D, @texture.index) 90 | 91 | @stars.each_with_index do |star, i| 92 | add_perspective_to_scene 93 | 94 | glMatrixMode(GL_MODELVIEW) #see lesson 01 95 | glLoadIdentity #see lesson 01 96 | 97 | glTranslatef(0, 0, @zoom) #see lesson 01 98 | 99 | glRotatef(@tilt, 1, 0, 0) # rotate it by x direction 100 | glRotatef(star.angle, 0, 1, 0) # rotate it by y direction 101 | glTranslatef(star.distance, 0, 0) # move on the x direction 102 | 103 | # since we are using a flat texture we want it always look flat and correct regardless how much spinning and rotation are we doing. We 104 | # can archive that by canceling the rotations that we are doing before we draw our stars. IMPORTANT: Cancellation by happen in the reverse order 105 | glRotatef(-star.angle, 0, 1, 0) 106 | glRotatef(-@tilt, 1, 0, 0) 107 | 108 | draw_star(@stars[rand(@stars.size)]) if @twinkle_on # we make star swinkle by drawing another random non spinning star on the bottom of it 109 | 110 | glRotatef(@spin,0,0,1) #spin the star on z axis 111 | draw_star(star) 112 | 113 | star.angle += i.to_f / @stars.size # increase the angle for next frame 114 | star.distance -= 0.01 # move stars to closer and closer to the center 115 | 116 | if (star.distance < 0) # if it reaches center, restart its distance and reset the color 117 | star.distance += 5 118 | star.color_randomly 119 | end 120 | end 121 | end 122 | end 123 | 124 | def button_down(id) 125 | case id 126 | when Gosu::Button::KbEscape then close 127 | when Gosu::Button::KbT then @twinkle_on = !@twinkle_on 128 | end 129 | end 130 | end 131 | 132 | window = Window.new 133 | window.show -------------------------------------------------------------------------------- /using_nehe_lessons/lesson10.rb: -------------------------------------------------------------------------------- 1 | require 'gosu' 2 | require 'json' 3 | require 'gl' 4 | require 'glu' 5 | require 'glut' 6 | include Gl 7 | include Glu 8 | 9 | class Texture 10 | attr_accessor :info 11 | def initialize(window) 12 | @image = Gosu::Image.new(window, "resources/nehe/lesson10/Mud.bmp", true) 13 | @info = @image.gl_tex_info 14 | end 15 | end 16 | 17 | class Vertex 18 | attr_reader :x, :y, :z, :u, :v 19 | 20 | def initialize(coords) 21 | coords.each do |coordinate, value| 22 | instance_variable_set(:"@#{coordinate}", value) 23 | end 24 | end 25 | end 26 | 27 | class Triangle 28 | attr_accessor :vertexes 29 | def initialize 30 | @vertexes = [] 31 | end 32 | end 33 | 34 | class Window < Gosu::Window 35 | attr_accessor :triangles, :current_filter 36 | 37 | def initialize 38 | super(800, 600, false) 39 | self.caption = "Lesson #10 - Loading and moving through 3D World" 40 | @texture = Texture.new(self) 41 | setup_world 42 | init_defaults 43 | init_lights 44 | init_textures 45 | end 46 | 47 | def setup_world 48 | triangle_data = JSON.parse(File.read('resources/nehe/lesson10/world.json')) 49 | @triangles = triangle_data.inject([]) do |acc, vertexes| 50 | acc << Triangle.new.tap do |triangle| 51 | vertexes.each do |vertex| 52 | triangle.vertexes << Vertex.new(vertex) 53 | end 54 | end 55 | acc 56 | end 57 | end 58 | 59 | def init_defaults 60 | @light_on = false 61 | @blending = false 62 | @bouncing = @bouncing_angle = 0 63 | @x_pos = @look_up_or_down_pos = @y_angle = @look_up_or_down = 0 64 | @degree_radian_conversion = 0.0174532925 # pi / 180 65 | end 66 | 67 | def init_lights 68 | # see nehe07 for details on how lighting work 69 | @ambient_light = [0.5, 0.5, 0.5, 1] 70 | @diffuse_light = [1, 1, 1, 1] 71 | @light_postion = [0, 0, 2, 1] 72 | end 73 | def init_textures 74 | # see nehe07 for details on how filters work 75 | glGetError 76 | @nearest = Texture.new(self) 77 | glBindTexture(GL_TEXTURE_2D, @nearest.info.tex_name) 78 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST) 79 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST) 80 | 81 | @linear = Texture.new(self) 82 | glBindTexture(GL_TEXTURE_2D, @linear.info.tex_name) 83 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 84 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR) 85 | 86 | @minimap = Texture.new(self) 87 | glBindTexture(GL_TEXTURE_2D, @minimap.info.tex_name) 88 | texture = glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_FLOAT) 89 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 90 | 91 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST) 92 | gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 256, 256, GL_RGB, GL_FLOAT, texture) 93 | @filters = [@nearest.info.tex_name, @linear.info.tex_name, @minimap.info.tex_name] 94 | end 95 | 96 | def init_scene 97 | #basics of creating a scene. see lesson 1 and others 98 | glEnable(GL_TEXTURE_2D) 99 | glBlendFunc(GL_SRC_ALPHA,GL_ONE) 100 | glShadeModel(GL_SMOOTH) 101 | glClearColor(0,0,0,0) 102 | glClearDepth(1) 103 | glEnable(GL_DEPTH_TEST) 104 | glDepthFunc(GL_LEQUAL) 105 | glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) 106 | end 107 | 108 | 109 | def add_perspective_to_scene 110 | # see lesson 01 111 | glMatrixMode(GL_PROJECTION) 112 | glLoadIdentity 113 | gluPerspective(45.0, width / height, 0.1, 100.0) 114 | glMatrixMode(GL_MODELVIEW) 115 | glLoadIdentity 116 | end 117 | 118 | def update 119 | @y_angle -= 1.5 if button_down? Gosu::Button::KbRight 120 | @y_angle += 1.5 if button_down? Gosu::Button::KbLeft 121 | 122 | if button_down?(Gosu::Button::KbUp) 123 | @x_pos -= Math.sin(@y_angle * @degree_radian_conversion) * 0.05 124 | @look_up_or_down_pos -= Math.cos(@y_angle * @degree_radian_conversion) * 0.05 125 | @bouncing_angle > 359 ? @bouncing_angle = 0 : @bouncing_angle += 10 # bouncing and bouncing angle gives illusion of walking 126 | @bouncing = Math.sin(@bouncing_angle * @degree_radian_conversion) / 20 # use sinusoid for bouncing 127 | end 128 | if button_down?(Gosu::Button::KbDown) 129 | @x_pos += Math.sin(@y_angle * @degree_radian_conversion) * 0.05 130 | @look_up_or_down_pos += Math.cos(@y_angle * @degree_radian_conversion) * 0.05 131 | @bouncing_angle <= 1 ? @bouncing_angle = 359 : @bouncing_angle -= 10 # bouncing and bouncing angle gives illusion of walking 132 | @bouncing = Math.sin(@bouncing_angle * @degree_radian_conversion) / 20 # use sinusoid for bouncing 133 | end 134 | @look_up_or_down -= 0.2 if button_down? Gosu::Button::KbPageUp 135 | @look_up_or_down += 0.2 if button_down? Gosu::Button::KbPageDown 136 | end 137 | 138 | def draw 139 | gl do 140 | init_scene 141 | add_perspective_to_scene 142 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # see lesson01 143 | 144 | glLightfv(GL_LIGHT1, GL_AMBIENT, @ambient_light) # see lighting lesson nehe07 145 | glLightfv(GL_LIGHT1, GL_DIFFUSE, @diffuse_light) 146 | glLightfv(GL_LIGHT1, GL_POSITION, @light_postion) 147 | glEnable(GL_LIGHT1) 148 | 149 | @light_on ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING) # see nehe07 150 | if @blending # for blending see nehe08 151 | glEnable(GL_BLEND) 152 | glDisable(GL_DEPTH_TEST) 153 | else 154 | glDisable(GL_BLEND) 155 | glEnable(GL_DEPTH_TEST) 156 | end 157 | 158 | # For user to be able to walk around normally we would move the camera around and draw the 3D environment relative to the camera position. 159 | # This is slow and hard to code. What we will do is this: 160 | # 1. Rotate and translate the camera position according to user commands 161 | # 2. Rotate the world around the origin in the opposite direction of the camera rotation (giving the illusion that the camera has been rotated) 162 | # 3. Translate the world in the opposite manner that the camera has been translated (again, giving the illusion that the camera has moved) 163 | x = -@x_pos 164 | y = -@bouncing - 0.25 165 | z = -@look_up_or_down_pos 166 | scene_angle = 360 - @y_angle 167 | 168 | glRotatef(@look_up_or_down,1,0,0) #rotate to be able to look up or down 169 | glRotatef(scene_angle,0,1,0); #rotate based on direction user is facing 170 | glTranslate(x, y, z) #translate the world in opposite of camera 171 | glBindTexture(GL_TEXTURE_2D, current_filter) #see lesson 01 172 | triangles.each do |triangle| 173 | draw_triangle(triangle) 174 | end 175 | end 176 | end 177 | 178 | def draw_triangle(triangle) 179 | glBegin(GL_TRIANGLES) 180 | glNormal3f(0, 0, 1) 181 | triangle.vertexes.each do |vertex| 182 | glTexCoord2f(vertex.u, vertex.v) 183 | glVertex3f(vertex.x, vertex.y, vertex.z) 184 | end 185 | glEnd 186 | end 187 | 188 | def change_filter! 189 | index = @filters.index(current_filter) 190 | index > 1 ? index = 0 : index += 1 191 | @current_filter = @filters[index] 192 | end 193 | 194 | def current_filter 195 | @current_filter ||= @filters.first 196 | end 197 | 198 | def button_down(id) 199 | case id 200 | when Gosu::Button::KbEscape then close 201 | when Gosu::Button::KbL then @light_on = !@light_on 202 | when Gosu::Button::KbF then change_filter! 203 | when Gosu::Button::KbB then @blending = !@blending 204 | end 205 | end 206 | end 207 | 208 | window = Window.new 209 | window.show --------------------------------------------------------------------------------