diff options
| author | Tom Black <[email protected]> | 2015-10-04 20:12:32 -0400 |
|---|---|---|
| committer | Tom Black <[email protected]> | 2015-10-04 20:12:32 -0400 |
| commit | d70e4d425eab3848226215d42b3a81b8e191de1a (patch) | |
| tree | 197bd95fe7bf5a6479aceb646a8549cb1cf57183 | |
| download | ruby2d-d70e4d425eab3848226215d42b3a81b8e191de1a.tar.gz ruby2d-d70e4d425eab3848226215d42b3a81b8e191de1a.zip | |
First!
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | Gemfile | 3 | ||||
| -rw-r--r-- | Rakefile | 34 | ||||
| -rw-r--r-- | assets/app.icns | bin | 0 -> 55701 bytes | |||
| -rwxr-xr-x | bin/ruby2d | 116 | ||||
| -rw-r--r-- | examples/input.rb | 50 | ||||
| -rw-r--r-- | examples/simple.rb | 13 | ||||
| -rw-r--r-- | examples/triangle.rb | 10 | ||||
| -rw-r--r-- | ext/ruby2d/extconf.rb | 61 | ||||
| -rw-r--r-- | ext/ruby2d/ruby2d.c | 235 | ||||
| -rw-r--r-- | lib/ruby2d.rb | 17 | ||||
| -rw-r--r-- | lib/ruby2d/application.rb | 39 | ||||
| -rw-r--r-- | lib/ruby2d/color.rb | 72 | ||||
| -rw-r--r-- | lib/ruby2d/dsl.rb | 27 | ||||
| -rw-r--r-- | lib/ruby2d/exceptions.rb | 12 | ||||
| -rw-r--r-- | lib/ruby2d/image.rb | 23 | ||||
| -rw-r--r-- | lib/ruby2d/quad.rb | 50 | ||||
| -rw-r--r-- | lib/ruby2d/rectangle.rb | 57 | ||||
| -rw-r--r-- | lib/ruby2d/sound.rb | 19 | ||||
| -rw-r--r-- | lib/ruby2d/square.rb | 26 | ||||
| -rw-r--r-- | lib/ruby2d/text.rb | 51 | ||||
| -rw-r--r-- | lib/ruby2d/triangle.rb | 45 | ||||
| -rw-r--r-- | lib/ruby2d/version.rb | 5 | ||||
| -rw-r--r-- | lib/ruby2d/window.rb | 132 | ||||
| -rw-r--r-- | ruby2d.gemspec | 20 | ||||
| -rw-r--r-- | tests/testcard.rb | 134 |
27 files changed, 1256 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cec3cb5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.gem +Gemfile.lock diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f1ba4c1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tests/media"] + path = tests/media + url = https://github.com/simple2d/test_media.git @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gemspec diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..022193e --- /dev/null +++ b/Rakefile @@ -0,0 +1,34 @@ +# require 'rake/testtask' + +task default: 'all' + +# Rake::TestTask.new do |t| +# t.test_files = FileList['test/*_test.rb'] +# t.verbose = true +# end + +desc "Build Gem" +task :build do + puts "==> uninstall gem" + system "gem uninstall ruby2d --executables" + + puts "==> build gem" + system "gem build ruby2d.gemspec --verbose" + + puts "==> install gem" + system "gem install ruby2d-0.0.0.gem --local" # --verbose +end + + +desc "Run Testcard" +task :testcard do + Rake::Task['build'].invoke + system '( cd tests/ ; ruby testcard.rb )' +end + + +desc "Test and Build" +task :all do + # Rake::Task['test'].invoke + Rake::Task['build'].invoke +end diff --git a/assets/app.icns b/assets/app.icns Binary files differnew file mode 100644 index 0000000..8485724 --- /dev/null +++ b/assets/app.icns diff --git a/bin/ruby2d b/bin/ruby2d new file mode 100755 index 0000000..f131ab1 --- /dev/null +++ b/bin/ruby2d @@ -0,0 +1,116 @@ +#!/usr/bin/env ruby +require 'ruby2d/version' + +class String + def colorize(c); "\e[#{c}m#{self}\e[0m" end + def error; colorize('1;31') end + def bold; colorize('1') end +end + + +def build_native(rb_file) + if `which mruby`.empty? + puts "", + " mruby not found!".error, "", + " mruby is needed to build a native Ruby 2D applications.".bold, "", + " Install using Homebrew on OS X:", + " brew install mruby", "" + exit + end + + `mkdir -p build` + `mrbc -Bruby2d_app_symbol -obuild/app.c #{rb_file}` + + open('build/app.c', 'a') do |f| + f << %( +#include "mruby.h" +#include "mruby/irep.h" + +int main(void) { + mrb_state *mrb = mrb_open(); + if (!mrb) { /* handle error */ } + mrb_load_irep(mrb, ruby2d_app_symbol); + mrb_close(mrb); +} + ) + end + + `cc -std=c99 -lmruby build/app.c -o build/app` +end + + +def build_package + require 'fileutils' + + icon_path = "#{Gem::Specification.find_by_name('ruby2d').gem_dir}/assets/app.icns" + + FileUtils.mkpath "build/App.app/Contents/MacOS" + FileUtils.mkpath "build/App.app/Contents/Resources" + FileUtils.cp icon_path, "build/App.app/Contents/Resources" + + info_plist = %( +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleExecutable</key> + <string>app</string> + <key>CFBundleIconFile</key> + <string>app.icns</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>1.0</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> +</dict> +</plist> +) + + File.open("build/App.app/Contents/Info.plist", 'w') { |f| f.write(info_plist) } + + FileUtils.cp "build/app", "build/App.app/Contents/MacOS/" + + puts "App written to `build/App.app`." +end + + +# Command line usage and tree ################################################## + +usage = " +Usage: ruby2d [-v|--version] + <command> <options> + +Summary of commands and options: + build Build the application... + native ...compile with mruby. + web ...for web platform. + package Create application package. + -v|--version Prints the installed version. + +" + +case ARGV[0] +when 'build' + puts "Running build..." + case ARGV[1] + when 'native' + puts "Running build native..." + build_native ARGV[2] + when 'web' + puts "Running build web..." + else + puts usage + end +when 'package' + puts "Running package..." + build_package +when '-v', '--version' + puts Ruby2D::VERSION +else + puts usage +end + +exit diff --git a/examples/input.rb b/examples/input.rb new file mode 100644 index 0000000..a39a29c --- /dev/null +++ b/examples/input.rb @@ -0,0 +1,50 @@ +require 'ruby2d' + +set width: 200, height: 100 + +on key: 'a' do + puts "a pressed!" +end + +show + +# on :mouse 'up' do +# +# end +# +# on :mouse 'down' do +# +# end +# +# on :key 'a' do +# +# end +# +# on :key_down 'a' do +# +# end +# +# on :mouse 'click' do +# +# end +# +# on :mouse 'right' do +# +# end +# +# on :mouse 'left' do +# +# end +# +# +# on key: 'any' do +# +# end +# +# on key: 'a' do +# +# end +# +# on key: 'shift' do +# +# end diff --git a/examples/simple.rb b/examples/simple.rb new file mode 100644 index 0000000..ca8e99f --- /dev/null +++ b/examples/simple.rb @@ -0,0 +1,13 @@ +require 'ruby2d' + +# Set the window size +set width: 300, height: 200 + +# Create a new shape +s = Square.new + +# Give it some color +s.color = 'red' + +# Show the window +show diff --git a/examples/triangle.rb b/examples/triangle.rb new file mode 100644 index 0000000..71f0bbf --- /dev/null +++ b/examples/triangle.rb @@ -0,0 +1,10 @@ +require 'ruby2d' + +Triangle.new(320, 50, 540, 430, 100, 430, +[ + [1.0, 0, 0, 1.0], + [0, 1.0, 0, 1.0], + [0, 0, 1.0, 1.0] +]) + +show diff --git a/ext/ruby2d/extconf.rb b/ext/ruby2d/extconf.rb new file mode 100644 index 0000000..96c9eb4 --- /dev/null +++ b/ext/ruby2d/extconf.rb @@ -0,0 +1,61 @@ +require 'mkmf' + +errors = [] + +class String + def colorize(c); "\e[#{c}m#{self}\e[0m" end + def error; colorize('1;31') end + def bold; colorize('1') end +end + +def print_errors(errors) + puts " +#{"== Ruby 2D Installation Errors =============================".bold} + + Ruby 2D found some problems and was not installed: + + #{errors.join("\n ").error} + +#{"============================================================".bold} + +" +end + + +# Add space to flags +$LDFLAGS << ' ' + +# Mac OS +if RUBY_PLATFORM =~ /darwin/ + + # if `which simple2d`.empty? && has brew + # brew tap simple2d/tap + # brew install simple2d + # end + + if `which simple2d`.empty? + errors << "Simple 2D not found!" + print_errors(errors) + exit + end + + $LDFLAGS << `simple2d --libs` + +# Windows +elsif RUBY_PLATFORM =~ /mingw/ + +# Linux +else + + # if `which simple2d`.empty? + # install simple2d using script + # end + + $LDFLAGS << `simple2d --libs` + +end + +# Remove any newlines in flags +$LDFLAGS.gsub!(/\n/, ' ') + +create_makefile('ruby2d/ruby2d') diff --git a/ext/ruby2d/ruby2d.c b/ext/ruby2d/ruby2d.c new file mode 100644 index 0000000..1c4442a --- /dev/null +++ b/ext/ruby2d/ruby2d.c @@ -0,0 +1,235 @@ +#include <ruby.h> +#include <simple2d.h> + +#define TRIANGLE 1 +#define QUAD 2 +#define IMAGE 3 +#define TEXT 4 + +static VALUE ruby2d_module; +static VALUE ruby2d_window_klass; +static VALUE c_data_klass; + +VALUE self; +Window *window; + + +struct image_data { + Image img; +}; + +struct text_data { + Text txt; +}; + +struct sound_data { + Sound snd; +}; + + +static void free_image(struct image_data *data) { + S2D_FreeImage(data->img); +} + +static VALUE init_image(char *path) { + struct image_data *data = ALLOC(struct image_data); + data->img = S2D_CreateImage(path); + return Data_Wrap_Struct(c_data_klass, NULL, free_image, data); +} + + + +static void free_text(struct text_data *data) { + S2D_FreeText(data->txt); +} + +static VALUE init_text(char *font, char *msg, int size) { + struct text_data *data = ALLOC(struct text_data); + data->txt = S2D_CreateText(font, msg, size); + return Data_Wrap_Struct(c_data_klass, NULL, free_text, data); +} + + + +void on_key(const char *key) { + rb_funcall(self, rb_intern("key_callback"), 1, rb_str_new2(key)); +} + +void on_key_down(const char *key) { + rb_funcall(self, rb_intern("key_down_callback"), 1, rb_str_new2(key)); +} + + +void update() { + // Set the cursor + rb_iv_set(self, "@mouse_x", INT2NUM(window->mouse.x)); + rb_iv_set(self, "@mouse_y", INT2NUM(window->mouse.y)); + + // Call update proc, `window.update` + rb_funcall(self, rb_intern("update_callback"), 0); +} + + +void render() { + + // Read window objects + VALUE objects = rb_iv_get(self, "@objects"); + int num_objects = NUM2INT(rb_funcall(objects, rb_intern("count"), 0)); + + // Switch on each object type + for (int i = 0; i < num_objects; ++i) { + + VALUE el = rb_ary_entry(objects, i); + int type_id = NUM2INT(rb_iv_get(el, "@type_id")); + + // Switch on the object's type_id + switch(type_id) { + + case TRIANGLE: { + VALUE c1 = rb_iv_get(el, "@c1"); + VALUE c2 = rb_iv_get(el, "@c2"); + VALUE c3 = rb_iv_get(el, "@c3"); + + S2D_DrawTriangle( + NUM2DBL(rb_iv_get(el, "@x1")), + NUM2DBL(rb_iv_get(el, "@y1")), + NUM2DBL(rb_iv_get(c1, "@r")), + NUM2DBL(rb_iv_get(c1, "@g")), + NUM2DBL(rb_iv_get(c1, "@b")), + NUM2DBL(rb_iv_get(c1, "@a")), + + NUM2DBL(rb_iv_get(el, "@x2")), + NUM2DBL(rb_iv_get(el, "@y2")), + NUM2DBL(rb_iv_get(c2, "@r")), + NUM2DBL(rb_iv_get(c2, "@g")), + NUM2DBL(rb_iv_get(c2, "@b")), + NUM2DBL(rb_iv_get(c2, "@a")), + + NUM2DBL(rb_iv_get(el, "@x3")), + NUM2DBL(rb_iv_get(el, "@y3")), + NUM2DBL(rb_iv_get(c3, "@r")), + NUM2DBL(rb_iv_get(c3, "@g")), + NUM2DBL(rb_iv_get(c3, "@b")), + NUM2DBL(rb_iv_get(c3, "@a")) + ); + } + break; + + case QUAD: { + VALUE c1 = rb_iv_get(el, "@c1"); + VALUE c2 = rb_iv_get(el, "@c2"); + VALUE c3 = rb_iv_get(el, "@c3"); + VALUE c4 = rb_iv_get(el, "@c4"); + + S2D_DrawQuad( + NUM2DBL(rb_iv_get(el, "@x1")), + NUM2DBL(rb_iv_get(el, "@y1")), + NUM2DBL(rb_iv_get(c1, "@r")), + NUM2DBL(rb_iv_get(c1, "@g")), + NUM2DBL(rb_iv_get(c1, "@b")), + NUM2DBL(rb_iv_get(c1, "@a")), + + NUM2DBL(rb_iv_get(el, "@x2")), + NUM2DBL(rb_iv_get(el, "@y2")), + NUM2DBL(rb_iv_get(c2, "@r")), + NUM2DBL(rb_iv_get(c2, "@g")), + NUM2DBL(rb_iv_get(c2, "@b")), + NUM2DBL(rb_iv_get(c2, "@a")), + + NUM2DBL(rb_iv_get(el, "@x3")), + NUM2DBL(rb_iv_get(el, "@y3")), + NUM2DBL(rb_iv_get(c3, "@r")), + NUM2DBL(rb_iv_get(c3, "@g")), + NUM2DBL(rb_iv_get(c3, "@b")), + NUM2DBL(rb_iv_get(c3, "@a")), + + NUM2DBL(rb_iv_get(el, "@x4")), + NUM2DBL(rb_iv_get(el, "@y4")), + NUM2DBL(rb_iv_get(c4, "@r")), + NUM2DBL(rb_iv_get(c4, "@g")), + NUM2DBL(rb_iv_get(c4, "@b")), + NUM2DBL(rb_iv_get(c4, "@a")) + ); + } + break; + + case IMAGE: { + if (rb_iv_get(el, "@data") == Qnil) { + VALUE data = init_image(RSTRING_PTR(rb_iv_get(el, "@path"))); + rb_iv_set(el, "@data", data); + } + + struct image_data *data; + Data_Get_Struct(rb_iv_get(el, "@data"), struct image_data, data); + + data->img.x = NUM2DBL(rb_iv_get(el, "@x")); + data->img.y = NUM2DBL(rb_iv_get(el, "@y")); + S2D_DrawImage(data->img); + } + break; + + case TEXT: { + if (rb_iv_get(el, "@data") == Qnil) { + + VALUE data = init_text( + RSTRING_PTR(rb_iv_get(el, "@font")), + RSTRING_PTR(rb_iv_get(el, "@text")), + NUM2DBL(rb_iv_get(el, "@size")) + ); + + rb_iv_set(el, "@data", data); + } + + struct text_data *data; + Data_Get_Struct(rb_iv_get(el, "@data"), struct text_data, data); + + data->txt.x = NUM2DBL(rb_iv_get(el, "@x")); + data->txt.y = NUM2DBL(rb_iv_get(el, "@y")); + S2D_DrawText(data->txt); + } + break; + } + } +} + + +/* + * Ruby2D::Window#show + */ +static VALUE ruby2d_show(VALUE s) { + self = s; + + char *title = RSTRING_PTR(rb_iv_get(self, "@title")); + int width = NUM2INT(rb_iv_get(self, "@width")); + int height = NUM2INT(rb_iv_get(self, "@height")); + + window = S2D_CreateWindow( + title, width, height, update, render + ); + + window->on_key = on_key; + window->on_key_down = on_key_down; + + S2D_Show(window); + + return Qnil; +} + + +/* + * Ruby C extension init + */ +void Init_ruby2d() { + + // Ruby2D + ruby2d_module = rb_define_module("Ruby2D"); + + // Ruby2D::Window + ruby2d_window_klass = rb_define_class_under(ruby2d_module, "Window", rb_cObject); + + // Ruby2D::Window#show + rb_define_method(ruby2d_window_klass, "show", ruby2d_show, 0); + + // Ruby2D::CData + c_data_klass = rb_define_class_under(ruby2d_module, "CData", rb_cObject); +} diff --git a/lib/ruby2d.rb b/lib/ruby2d.rb new file mode 100644 index 0000000..3e8ab78 --- /dev/null +++ b/lib/ruby2d.rb @@ -0,0 +1,17 @@ +# ruby2d.rb + +require 'ruby2d/window' +require 'ruby2d/application' +require 'ruby2d/color' +require 'ruby2d/quad' +require 'ruby2d/rectangle' +require 'ruby2d/square' +require 'ruby2d/triangle' +require 'ruby2d/image' +require 'ruby2d/text' +require 'ruby2d/dsl' +require 'ruby2d/exceptions' +require 'ruby2d/ruby2d' # load native extension + +include Ruby2D::DSL +include Ruby2D diff --git a/lib/ruby2d/application.rb b/lib/ruby2d/application.rb new file mode 100644 index 0000000..ebef2b5 --- /dev/null +++ b/lib/ruby2d/application.rb @@ -0,0 +1,39 @@ +# application.rb + +module Ruby2D::Application + class << self + @@window = Ruby2D::Window.new + + def get(sym) + @@window.get(sym) + end + + def set(opts) + @@window.set(opts) + end + + def on(mouse: nil, key: nil, &proc) + @@window.on(mouse: mouse, key: key, &proc) + end + + def add(o) + @@window.add(o) + end + + def remove(o) + @@window.remove(o) + end + + def clear + @@window.clear + end + + def update(&proc) + @@window.update(&proc) + end + + def show + @@window.show + end + end +end diff --git a/lib/ruby2d/color.rb b/lib/ruby2d/color.rb new file mode 100644 index 0000000..9c7bc32 --- /dev/null +++ b/lib/ruby2d/color.rb @@ -0,0 +1,72 @@ +# color.rb + +module Ruby2D + class Color + + attr_reader :r, :g, :b, :a + + def initialize(c) + case c + when 'black' + @r, @g, @b, @a = to_f([0, 0, 0, 255]) + when 'gray' + @r, @g, @b, @a = to_f([170, 170, 170, 255]) + when 'silver' + @r, @g, @b, @a = to_f([221, 221, 221, 255]) + when 'white' + @r, @g, @b, @a = to_f([255, 255, 255, 255]) + when 'navy' + @r, @g, @b, @a = to_f([0, 31, 63, 255]) + when 'blue' + @r, @g, @b, @a = to_f([0, 116, 217, 255]) + when 'aqua' + @r, @g, @b, @a = to_f([127, 219, 255, 255]) + when 'teal' + @r, @g, @b, @a = to_f([57, 204, 204, 255]) + when 'olive' + @r, @g, @b, @a = to_f([61, 153, 112, 255]) + when 'green' + @r, @g, @b, @a = to_f([46, 204, 64, 255]) + when 'lime' + @r, @g, @b, @a = to_f([1, 255, 112, 255]) + when 'yellow' + @r, @g, @b, @a = to_f([255, 220, 0, 255]) + when 'orange' + @r, @g, @b, @a = to_f([255, 133, 27, 255]) + when 'red' + @r, @g, @b, @a = to_f([255, 65, 54, 255]) + when 'maroon' + @r, @g, @b, @a = to_f([133, 20, 75, 255]) + when 'fuchsia' + @r, @g, @b, @a = to_f([240, 18, 190, 255]) + when 'purple' + @r, @g, @b, @a = to_f([177, 13, 201, 255]) + when 'brown' + @r, @g, @b, @a = to_f([102, 51, 0, 255]) + when 'random' + @r, @g, @b, @a = rand(0..1.0), rand(0..1.0), rand(0..1.0), 1.0 + when Array + @r, @g, @b, @a = to_f([c[0], c[1], c[2], c[3]]) + else + # raise Error, "Color does not exist!" + puts "Error! Bad color." + end + end + + private + + # Convert from Uint8 (0..255) to Float (0..1.0) + def to_f(a) + b = [] + a.each do |n| + if n.class == Fixnum + b.push(n / 255.0) + else + b.push(n) + end + end + return b + end + + end +end diff --git a/lib/ruby2d/dsl.rb b/lib/ruby2d/dsl.rb new file mode 100644 index 0000000..c5bed09 --- /dev/null +++ b/lib/ruby2d/dsl.rb @@ -0,0 +1,27 @@ +# dsl.rb + +module Ruby2D::DSL + def hello + puts "hi" + end + + def get(sym) + Ruby2D::Application.get(sym) + end + + def set(opts) + Ruby2D::Application.set(opts) + end + + def on(mouse: nil, key: nil, &proc) + Ruby2D::Application.on(mouse: mouse, key: key, &proc) + end + + def update(&proc) + Ruby2D::Application.update(&proc) + end + + def show + Ruby2D::Application.show + end +end diff --git a/lib/ruby2d/exceptions.rb b/lib/ruby2d/exceptions.rb new file mode 100644 index 0000000..6f8416b --- /dev/null +++ b/lib/ruby2d/exceptions.rb @@ -0,0 +1,12 @@ +# exceptions.rb + +module Ruby2D + class Error < StandardError + def initialize(msg) + super(msg) + puts msg + puts "Occurred in:" + puts " " + caller.last, "\n" + end + end +end diff --git a/lib/ruby2d/image.rb b/lib/ruby2d/image.rb new file mode 100644 index 0000000..280d742 --- /dev/null +++ b/lib/ruby2d/image.rb @@ -0,0 +1,23 @@ +# image.rb + +module Ruby2D + class Image + + attr_accessor :x, :y + + def initialize(x, y, path) + + unless File.exists? path + raise Ruby2D::Error, "Cannot find image file!" + end + + @type_id = 3 + @x, @y, @path = x, y, path + + if defined? Ruby2D::DSL + Ruby2D::Application.add(self) + end + end + + end +end diff --git a/lib/ruby2d/quad.rb b/lib/ruby2d/quad.rb new file mode 100644 index 0000000..f496cc1 --- /dev/null +++ b/lib/ruby2d/quad.rb @@ -0,0 +1,50 @@ +# quad.rb + +module Ruby2D + class Quad + # Coordinates in clockwise order, starting at top left: + # x1,y1 == top left + # x2,y2 == top right + # x3,y3 == bottom right + # x4,y4 == bottom left + attr_accessor :x1, :y1, :c1, + :x2, :y2, :c2, + :x3, :y3, :c3, + :x4, :y4, :c4 + + attr_reader :color + + def initialize(x1, y1, x2, y2, x3, y3, x4, y4, c='white') + @type_id = 2 + @x1, @y1, @x2, @y2, @x3, @y3, @x4, @y4 = x1, y1, x2, y2, x3, y3, x4, y4 + @color = c + update_color(c) + + if defined? Ruby2D::DSL + Ruby2D::Application.add(self) + end + end + + def color=(c) + @color = c + update_color(c) + end + + private + + def update_color(c) + # If a 2D array + if c.class == Array && c.all? { |el| el.class == Array } + @c1 = Ruby2D::Color.new(c[0]) + @c2 = Ruby2D::Color.new(c[1]) + @c3 = Ruby2D::Color.new(c[2]) + @c4 = Ruby2D::Color.new(c[3]) + else + @c1 = Ruby2D::Color.new(c) + @c2 = Ruby2D::Color.new(c) + @c3 = Ruby2D::Color.new(c) + @c4 = Ruby2D::Color.new(c) + end + end + end +end diff --git a/lib/ruby2d/rectangle.rb b/lib/ruby2d/rectangle.rb new file mode 100644 index 0000000..45a0cee --- /dev/null +++ b/lib/ruby2d/rectangle.rb @@ -0,0 +1,57 @@ +# rectangle.rb + +module Ruby2D + class Rectangle < Ruby2D::Quad + + attr_reader :x, :y, :width, :height + + def initialize(x, y, w, h, c='white') + @type_id = 2 + @x, @y, @width, @height, @color = x, y, w, h, c + update_coords(x, y, w, h) + update_color(c) + + if defined? Ruby2D::DSL + Ruby2D::Application.add(self) + end + end + + def x=(x) + @x = @x1 = x + @x2 = x + @width + @x3 = x + @width + @x4 = x + end + + def y=(y) + @y = @y1 = y + @y2 = y + @y3 = y + @height + @y4 = y + @height + end + + def width=(w) + @width = w + update_coords(@x, @y, w, @height) + end + + def height=(h) + @height = h + update_coords(@x, @y, @width, h) + end + + private + + def update_coords(x, y, w, h) + @x1 = x + @y1 = y + @x2 = x + w + @y2 = y + @x4 = x + @y4 = y + h + @x3 = x + w + @y3 = y + h + end + + end +end diff --git a/lib/ruby2d/sound.rb b/lib/ruby2d/sound.rb new file mode 100644 index 0000000..edbbef9 --- /dev/null +++ b/lib/ruby2d/sound.rb @@ -0,0 +1,19 @@ +# sound.rb + +module Ruby2D + class Sound + + def initialize(window, path) + unless File.exists? path + raise Error, "Cannot find sound file!" + end + window.create_audio(self, path) + @window, @path = window, path + end + + def play + @window.play_audio(self) + end + + end +end diff --git a/lib/ruby2d/square.rb b/lib/ruby2d/square.rb new file mode 100644 index 0000000..6614c06 --- /dev/null +++ b/lib/ruby2d/square.rb @@ -0,0 +1,26 @@ +# square.rb + +module Ruby2D + class Square < Ruby2D::Rectangle + + attr_reader :size + + def initialize(x=0, y=0, s=100, c='white') + @type_id = 2 + @x, @y, @color = x, y, c + @width = @height = @size = s + update_coords(x, y, s, s) + update_color(c) + + if defined? Ruby2D::DSL + Ruby2D::Application.add(self) + end + end + + def size=(s) + self.width = self.height = @size = s + end + + private :width=, :height= + end +end diff --git a/lib/ruby2d/text.rb b/lib/ruby2d/text.rb new file mode 100644 index 0000000..bd4637f --- /dev/null +++ b/lib/ruby2d/text.rb @@ -0,0 +1,51 @@ +# text.rb + +module Ruby2D + class Text + + attr_accessor :x, :y, :size, :text + + def initialize(x=0, y=0, size=20, text="Hello World!", font="Arial", c="white") + if font.include? '.' + unless File.exists? font + raise Error, "Cannot find font file!" + else + @font = font + end + else + @font = resolve_path(font) + end + + @type_id = 4 + @x, @y, @size = x, y, size + @text, @color = text, c + update_color(c) + + if defined? Ruby2D::DSL + Ruby2D::Application.add(self) + end + end + + def color=(c) + @color = c + update_color(c) + end + + private + + def resolve_path(font) + if RUBY_PLATFORM =~ /darwin/ + font_path = "/Library/Fonts/#{font}.ttf" + unless File.exists? font_path + raise Error, "Cannot find system font!" + end + end + font_path + end + + def update_color(c) + @c = Ruby2D::Color.new(c) + end + + end +end diff --git a/lib/ruby2d/triangle.rb b/lib/ruby2d/triangle.rb new file mode 100644 index 0000000..a4754ed --- /dev/null +++ b/lib/ruby2d/triangle.rb @@ -0,0 +1,45 @@ +# triangle.rb + +module Ruby2D + class Triangle + + attr_accessor :x1, :y1, :c1, + :x2, :y2, :c2, + :x3, :y3, :c3 + attr_reader :color + + def initialize(x1, y1, x2, y2, x3, y3, c='white') + @type_id = 1 + @x1, @y1 = x1, y1 + @x2, @y2 = x2, y2 + @x3, @y3 = x3, y3 + @color = c + update_color(c) + + if defined? Ruby2D::DSL + Ruby2D::Application.add(self) + end + end + + def color=(c) + update_color(c) + @color = c + end + + private + + def update_color(c) + # If a 2D array + if c.class == Array && c.all? { |el| el.class == Array } + @c1 = Ruby2D::Color.new(c[0]) + @c2 = Ruby2D::Color.new(c[1]) + @c3 = Ruby2D::Color.new(c[2]) + else + @c1 = Ruby2D::Color.new(c) + @c2 = Ruby2D::Color.new(c) + @c3 = Ruby2D::Color.new(c) + end + end + + end +end diff --git a/lib/ruby2d/version.rb b/lib/ruby2d/version.rb new file mode 100644 index 0000000..a6ab2f1 --- /dev/null +++ b/lib/ruby2d/version.rb @@ -0,0 +1,5 @@ +# version.rb + +module Ruby2D + VERSION = '0.0.0' +end diff --git a/lib/ruby2d/window.rb b/lib/ruby2d/window.rb new file mode 100644 index 0000000..6011d42 --- /dev/null +++ b/lib/ruby2d/window.rb @@ -0,0 +1,132 @@ +# window.rb + +module Ruby2D + class Window + attr_reader :title, :width, :height, :mouse_x, :mouse_y + + def initialize(width: 640, height: 480, title: "Ruby 2D", fps: 60, vsync: true) + @width, @height, @title = width, height, title + @mouse_x = @mouse_y = 0 + @fps_cap = fps + @vsync = vsync + + @objects = [] + @keys = {} + @keys_down = {} + @update_proc = Proc.new {} + end + + def get(sym) + case sym + when :window + return self + when :title + return @title + when :width + return @width + when :height + return @height + when :mouse_x + return @mouse_x + when :mouse_y + return @mouse_y + end + end + + def set(opts) + if opts.include? :title + @title = opts[:title] + end + + if opts.include? :width + @width = opts[:width] + end + + if opts.include? :height + @height = opts[:height] + end + end + + def on(mouse: nil, key: nil, &proc) + puts "mouse: #{mouse}" + puts "key: #{key}" + # proc.call + key(key, &proc) + end + + def add(o) + case o + when nil + raise Error, "Cannot add '#{o.class}' to window!" + when Array + o.each { |x| add_object(x) } + else + add_object(o) + end + end + + def remove(o) + if o == nil + raise Error, "Cannot remove '#{o.class}' from window!" + end + + if i = @objects.index(o) + @objects.slice!(i) + true + else + false + end + end + + def clear + @objects.clear + end + + # Register key string with proc + def key(key, &proc) + @keys[key] = proc + true + end + + def key_callback(key) + key.downcase! + if @keys.has_key? key + @keys[key].call + end + end + + # Register key string with proc + def key_down(key, &proc) + @keys_down[key] = proc + true + end + + def key_down_callback(key) + key.downcase! + if @keys_down.has_key? key + @keys_down[key].call + end + end + + def update(&proc) + @update_proc = proc + true + end + + def update_callback + @update_proc.call + end + + private + + def add_object(o) + if [email protected]?(o) + @objects.push(o) + true + else + false + end + end + + end +end diff --git a/ruby2d.gemspec b/ruby2d.gemspec new file mode 100644 index 0000000..df03f5a --- /dev/null +++ b/ruby2d.gemspec @@ -0,0 +1,20 @@ +$:.push File.expand_path('../lib', __FILE__) +require 'ruby2d/version' + +Gem::Specification.new do |s| + s.name = 'ruby2d' + s.version = Ruby2D::VERSION + s.date = '2015-10-01' + s.author = 'Tom Black' + s.email = '@blacktm' + s.summary = 'Ruby 2D' + s.description = 'Make cross-platform 2D applications in Ruby.' + s.homepage = 'http://www.ruby2d.com' + s.license = 'MIT' + s.files = Dir.glob('lib/**/*') + + Dir.glob('assets/**/*') + + Dir.glob('ext/**/*.{c,rb}') + s.extensions = ['ext/ruby2d/extconf.rb'] + s.executables << 'ruby2d' + s.required_ruby_version = '>= 2.2.0' +end diff --git a/tests/testcard.rb b/tests/testcard.rb new file mode 100644 index 0000000..09bc40c --- /dev/null +++ b/tests/testcard.rb @@ -0,0 +1,134 @@ +require 'ruby2d' + +set width: 700, height: 500, title: "Ruby 2D – Testcard" + +# Read window attributes +puts " +=== Window Attributes === +Title: #{get :title} +Width: #{get :width} +Height: #{get :height} +Self: #{get :window}\n\n" + +# Primary colors +Rectangle.new(0, 0, 50, 100, [1.0, 0, 0, 1.0]) +Rectangle.new(50, 0, 50, 100, [0, 1.0, 0, 1.0]) +Rectangle.new(100, 0, 50, 100, [0, 0, 1.0, 1.0]) + +# Color strings +Rectangle.new(150, 0, 50, 50, 'black') +Rectangle.new(200, 0, 50, 50, 'gray') +Rectangle.new(250, 0, 50, 50, 'silver') +Rectangle.new(300, 0, 50, 50, 'white') +Rectangle.new(350, 0, 50, 50, 'navy') +Rectangle.new(400, 0, 50, 50, 'blue') +Rectangle.new(450, 0, 50, 50, 'aqua') +Rectangle.new(500, 0, 50, 50, 'teal') +Rectangle.new(550, 0, 50, 50, 'olive') + +Rectangle.new(150, 50, 50, 50, 'green') +Rectangle.new(200, 50, 50, 50, 'lime') +Rectangle.new(250, 50, 50, 50, 'yellow') +Rectangle.new(300, 50, 50, 50, 'orange') +Rectangle.new(350, 50, 50, 50, 'red') +Rectangle.new(400, 50, 50, 50, 'maroon') +Rectangle.new(450, 50, 50, 50, 'fuchsia') +Rectangle.new(500, 50, 50, 50, 'purple') +Rectangle.new(550, 50, 50, 50, 'brown') + +Rectangle.new(600, 0, 50, 50, 'random') +Rectangle.new(650, 0, 50, 50, 'random') +Rectangle.new(600, 50, 50, 50, 'random') +Rectangle.new(650, 50, 50, 50, 'random') + +# White to black gradient +Rectangle.new(0, 100, 700, 25, +[ + [1.0, 1.0, 1.0, 1.0], + [0.0, 0.0, 0.0, 0.0], # testing Float + [ 0, 0, 0, 0], # testing Fixnum + [1.0, 1.0, 1.0, 1.0] +]) + +# Color gradient +Rectangle.new(0, 125, 700, 50, +[ + [1.0, 0.0, 0.0, 1.0], + [0.0, 1.0, 0.0, 1.0], + [0.0, 0.0, 1.0, 1.0], + [1.0, 1.0, 0.0, 1.0] +]) + +# Transparancy +Rectangle.new(0, 165, 700, 35, +[ + [1.0, 1.0, 1.0, 0.0], + [1.0, 1.0, 1.0, 1.0], + [1.0, 1.0, 1.0, 1.0], + [1.0, 1.0, 1.0, 0.0] +]) + +# Triangles +Triangle.new(25, 200, 50, 250, 0, 250, [1.0, 0, 0, 1.0]) +Triangle.new(75, 200, 100, 250, 50, 250, [0, 1.0, 1, 1.0]) +Triangle.new(125, 200, 150, 250, 100, 250, [0, 0, 1.0, 1.0]) +Triangle.new(175, 200, 200, 250, 150, 250, +[ + [1.0, 0, 0, 1.0], + [0, 1.0, 0, 1.0], + [0, 0, 1.0, 1.0] +]) +Rectangle.new(200, 200, 50, 50, 'gray') # add background for transparancy +Triangle.new(225, 200, 250, 250, 200, 250, +[ + [1.0, 1.0, 1.0, 1.0], + [0.0, 0.0, 0.0, 1.0], + [1.0, 1.0, 1.0, 0.0] +]) + +# Quadrilaterals +Quad.new( + 300, 200, + 350, 200, + 300, 250, + 250, 250, + [ + [1.0, 0.0, 0.0, 1.0], + [0.0, 1.0, 0.0, 1.0], + [0.0, 0.0, 1.0, 1.0], + [1.0, 1.0, 0.0, 1.0] + ] +) + +Quad.new( + 250, 200, + 300, 200, + 350, 250, + 300, 250, + [ + [1.0, 1.0, 1.0, 0.0], + [1.0, 1.0, 1.0, 0.0], + [1.0, 1.0, 1.0, 1.0], + [1.0, 1.0, 1.0, 0.0] + ] +) + +# Images +Image.new(580, 180, "media/image.png") +Image.new(580, 290, "media/image.jpg") +Image.new(580, 400, "media/image.bmp") + +# Text +Text.new(0, 300) +# Text.new(0, 350, 30, "Hello Ruby 2D!") + + +# Pointer for mouse +pointer = Square.new(0, 0, 10, 'red') + +update do + pointer.x = (get :mouse_x) - 5 + pointer.y = (get :mouse_y) - 7 +end + +show |
