Skip to content

Instantly share code, notes, and snippets.

@monkstone
Created October 16, 2010 07:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monkstone/629550 to your computer and use it in GitHub Desktop.
Save monkstone/629550 to your computer and use it in GitHub Desktop.
Preston Lees multi-threaded star-field application modified to run on linux
# asynchronous_object.rb
#
# Copyright © 2009 Preston Lee. All rights reserved.
require 'thread'
class AsychronousObject
attr_reader :thread
attr_reader :update_frequency
attr_reader :last_updated
def initialize(freq)
@update_freqency = freq
# puts @update_freqency
@mutex = Mutex.new
start
end
def start
@last_updated = Time.now
@state = :active # or :inactive
# puts @mutex
@thread = Thread.new do
keep_going = true
while keep_going do
@mutex.synchronize do
# puts "going"
keep_going = false if @state == :inactive
end
if keep_going
now = Time.now
# puts "TL '#{@last_updated}' N #{now} F #{@update_freqency}"
update(@last_updated, now)
@last_updated = now
sleep @update_freqency
end
end
end
end
def update
puts "FAIL!"
raise "You need to implement this method!"
end
def activate
@mutex.synchronize do
case @state
when :active
# do nothing
when :inactive
start
end
end
end
def deactivate
@mutex.synchronize do
@state = :inactive
end
end
def join
@thread.join
end
end
# star.rb
#
# Copyright © 2009 Preston Lee. All rights reserved.
require 'asynchronous_object'
class Star < AsychronousObject
attr_reader :x, :y, :z, :dxs, :dys, :dzs,:clipping_plane
DEFAULT_UPDATE_FREQUENCY = 0.20 # In seconds.
DEFAULT_CLIPPING_PLANE = 1800 # The universe is a giant cube, with each side being this long.
def initialize(freq = DEFAULT_UPDATE_FREQUENCY, clip = DEFAULT_CLIPPING_PLANE)
@clipping_plane = clip
@dxs = rand(20) - 10 # X-axis movement per wall second.
@dys = rand(20) - 10 # Y-axis movement per wall second.
@dzs = rand(200) * 2 # Z-axis movement per wall second.
set_random_position
super(freq) # We have to do this last since a +Thread+ will be created that needs our instance variables instantiated.
end
def set_random_position
@x = rand(clipping_plane * 2) - clipping_plane
@y = rand(clipping_plane * 2) - clipping_plane
@z = rand(clipping_plane * 2) - clipping_plane
end
def set_new_position
set_random_position
@z = -1 * clipping_plane
end
def update(last, now)
# Check if the star is getting too far away from the universe, and move it back to a reasonable starting point if so.
# puts "CLIP NIL" if @clipping_plane.nil?
set_new_position if x >= clipping_plane
set_new_position if y >= clipping_plane
set_new_position if z >= clipping_plane
# puts "Updating star position. '#{freq}'"
# Figure out the translation required along each axis for this time period.
dtime = now - last
dx = dxs * dtime
dy = dys * dtime
dz = dzs * dtime
# Move the star.
@x += dx
@y += dy
@z += dz
#puts "Moving to #{@x}, #{@y}, #{@z}"
end
end
# Copyright © 2009 Preston Lee. All rights reserved.
require 'star'
require 'asynchronous_object'
class StarfieldStar < Star
include Processing::Proxy
def draw
push_matrix
translate(@x, @y, @z)
box(8)
pop_matrix
end
end
class Starfield < Processing::App
load_library :opengl
NUM_STARS = 200;
CAMERA_SPEED = 20 # Pixels per wall second.
CAMERA_ROTATE_SPEED = 0.08 # Radians per wall second.
FRAME_RATE = 30 # Target frame per second.
attr_accessor :stars, :in_setup
full_screen
def setup
if in_setup == nil # guard against repeatedly setting up opengl?
library_loaded?(:opengl) ? setup_opengl : render_mode(P3D)
in_setup = true
end
frame_rate FRAME_RATE
@moved = false
@x = 0
@y = 0
@z = 0
@rz = 0
@mouse_last_x = nil
@mouse_last_y = nil
@active = true
@active_mutex = Mutex.new
@stars = []
NUM_STARS.times do
@stars << StarfieldStar.new(1.0 / FRAME_RATE)
end
text_font load_font("Univers66.vlw.gz"), 10
end
def draw
background 0 # Paint the entire screen solid black.
fill(255)
color(100,255,255)
sphere(100)
# text("Moving starfield demo aoenu hreouh rcohurcoeuh arochuoaentuhoe u.", 0, 0, 0)
if !@moved
push_matrix
scale(5.0, 5.0, 5.0)
# translate(0, 100, 0)
text("Multi-threaded starfield simulation.", 0, 80, 0)
text("Move: A, S, D, W, R, F, Arrow Keys", 0, 100, 0)
text("Roll: Z, C", 0, 110, 0)
text("Look: click and drag mouse.", 0, 120, 0)
text("Pause/Resume: TAB", 0, 130, 0)
text("PrestonLee.com", 0, 150, 0)
pop_matrix
else
# puts "MOVED"
end
@stars.each do |s|
push_matrix
s.draw
pop_matrix
end
move_camera_for_frame
# move_for_frame()
# scale(5.0, 5.0, 5.0)
# text('aoeuaoeuao euaoeuaoeu')
# translate(@x, @y, @z)
# rotate_z(@rz)
end
def setup_opengl
render_mode OPENGL
hint DISABLE_OPENGL_ERROR_REPORT
hint ENABLE_OPENGL_4X_SMOOTH
end
def mouse_released
@mouse_last_x = nil
@mouse_last_y = nil
end
def mouse_dragged
@moved = true
@mouse_last_x = mouse_x if @mouse_last_x.nil?
@mouse_last_y = mouse_y if @mouse_last_y.nil?
dx = @mouse_last_x - mouse_x
dy = @mouse_last_y - mouse_y
begin_camera
if dx != 0
# puts "#{mouse_x} #{mouse_y}"
rotate_y radians(-dx) * 0.1
end
if dy != 0
rotate_x radians(dy) * 0.1
end
end_camera
@mouse_last_x = mouse_x
@mouse_last_y = mouse_y
end
def key_pressed
@moved = true
# puts "KEY_PRESSED: #{key_code}"
handle_camera_change_start
handle_pause_and_resume
end
def handle_pause_and_resume
case key_code
when TAB:
@active_mutex.synchronize do
@stars.each do |s|
@active ? s.deactivate : s.activate
end
@active = !@active
end
end
end
def key_released
# puts "KEY_RELEASED: #{key_code}"
handle_camera_change_stop
end
def handle_camera_change_start
begin_camera
case key_code
when UP:
@camera_move_z = -1
when DOWN, 's', 'o':
@camera_move_z = 1
when LEFT:
@camera_move_x = -1
when RIGHT:
@camera_move_x = 1
end
case key
when 'w', ',':
@camera_move_z = -1
when 's', 'o':
@camera_move_z = 1
when 'a':
@camera_move_x = -1
when 'd', 'e':
@camera_move_x = 1
when 'r', 'p':
@camera_move_y = -1
when 'f', 'u':
@camera_move_y = 1
when 'z', ';':
@camera_rotate_z = -1
when 'c', 'j':
@camera_rotate_z = 1
end
end_camera
end
def handle_camera_change_stop
begin_camera
case key_code
when UP, DOWN, 'w', ',', 's', 'o':
@camera_move_z = 0
when LEFT, RIGHT, 'a', 'd', 'e':
@camera_move_x = 0
end
case key
when 'w', ',', 's', 'o':
@camera_move_z = 0
when 'a', 'd', 'e':
@camera_move_x = 0
when 'r', 'p', 'f', 'u':
@camera_move_y = 0
when 'z', ';', 'c', 'j':
@camera_rotate_z = 0
end
end_camera
end
def move_camera_for_frame
begin_camera
@dx = (@camera_move_x || 0) * CAMERA_SPEED
@dy = (@camera_move_y || 0) * CAMERA_SPEED
@dz = (@camera_move_z || 0) * CAMERA_SPEED
@drz = (@camera_rotate_z || 0) * CAMERA_ROTATE_SPEED
@x += @dx
@y += @dy
@z += @dz
@rz += @drz
translate(@dx, 0, 0) if !@camera_move_x.nil? && @camera_move_x != 0
translate(0, @dy, 0) if !@camera_move_y.nil? && @camera_move_y != 0
translate(0, 0, @dz) if !@camera_move_z.nil? && @camera_move_z != 0
rotate_z(@drz) if !@camera_rotate_z.nil? && @camera_rotate_z != 0
end_camera
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment