Class: Ray::GL::Vertex

Inherits:
Object
  • Object
show all
Includes:
PP
Defined in:
lib/ray/gl/vertex.rb,
ext/gl_vertex.c

Defined Under Namespace

Classes: Instance

Constant Summary collapse

TypeMap =
ray_gl_vertex_types

Class Method Summary collapse

Instance Method Summary collapse

Methods included from PP

#pretty_print_attributes

Class Method Details

.default_for(type) ⇒ Object



117
118
119
120
121
122
123
124
125
# File 'lib/ray/gl/vertex.rb', line 117

def self.default_for(type)
  case type
  when :float, :int, :ubyte then 0
  when :bool                then true
  when :vector2             then Ray::Vector2[0, 0]
  when :vector3             then Ray::Vector3[0, 0, 0]
  when :color               then Ray::Color.white
  end
end

.define_layout(on, layout, vtype, instance = false) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/ray/gl/vertex.rb', line 127

def self.define_layout(on, layout, vtype, instance = false)
  argument_layout = layout.reject do |_, _, _, per_instance|
    per_instance ^ instance
  end

  on.class_eval do
    define_method :initialize do |*args|
      if args.size > layout.size
        msg = "wrong number of arguments: #{args.size} for" <<
          " #{layout.size}"
        raise ArgumentError, msg
      end

      argument_layout.each_with_index do |(attr, _, type, _), i|
        send("#{attr}=", args[i] || Vertex.default_for(type))
      end
    end

    layout.each_with_index do |(attr, _, type, per_instance), i|
      next if per_instance ^ instance

      offset = Vertex.offset_of(vtype, i)

      # Faster than define_method.
      module_eval(<<-eom, __FILE__, __LINE__)
        def #{attr}
          element(#{offset}, #{type.inspect})
        end

        def #{attr}=(val)
          set_element(#{offset}, #{type.inspect}, val)
        end
      eom

      alias_method "#{attr}?", attr if type == :bool
    end
  end
end

.instance_size(vtype) ⇒ Object



128
129
130
131
132
# File 'ext/gl_vertex.c', line 128

static
VALUE ray_gl_vertex_instance_size(VALUE self, VALUE vtype) {
  say_vertex_type *type = say_get_vertex_type(NUM2ULONG(vtype));
  return INT2FIX(say_vertex_type_get_instance_size(type));
}

.layoutObject



113
114
115
# File 'lib/ray/gl/vertex.rb', line 113

def self.layout
  @vertex_type_layout
end

.make(layout) ⇒ Object

Creates a new Vertex class with a custom layout. Layout is an array of arrays, where each row contains 3 or 4 elements:

  1. Attribute name in Ruby

  2. Attribute name in GLSL shaders

  3. Attribute type, one of the following symbols: float, int, ubyte, bool, color, vector2, vector3.

  4. Whether the attribute is only accessibel on a per-instance basis (as opposed to per-vertex, which is the default)

Getters and setters are created for all of the attributes.

Examples:

TestVertex = Ray::GL::Vertex.make [
  [:float,   "in_Float",    :float],
  [:int,     "in_Int",      :int],
  [:ubyte,   "in_Ubyte",    :ubyte],
  [:bool,    "in_Bool",     :bool],
  [:color,   "in_Color",    :color],
  [:vector2, "in_Vector2",  :vector2],
  [:vector3, "in_Vector3",  :vector3],

  # per-instance data
  [:instance_color, "magic", :color, true]
]

Parameters:



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ray/gl/vertex.rb', line 67

def self.make(layout)
  layout.each do |_, _, type, _|
    unless TypeMap.has_key? type
      raise ArgumentError, "unknown type in a vertex: #{type.inspect}"
    end
  end

  vtype = make_type layout.map { |_, *rest| rest }

  @vertex_classes[vtype] = Class.new self do
    # Be *very* careful with those values.
    @vertex_type_id     = vtype
    @vertex_type_size   = Vertex.size(vtype)
    @vertex_type_layout = layout

    if layout.any? { |_, _, _, per_instance| per_instance }
      const_set :Instance, Class.new(Ray::GL::Vertex::Instance) {
        @vertex_instance_type_id = vtype
        @vertex_instance_size    = Vertex.instance_size(vtype)
        @vertex_instance_layout  = layout

        class << self
          undef instance_classes
        end

        Vertex.define_layout self, layout, vtype, true
      }
    end

    class << self
      undef make
      undef make_type
      undef size
      undef offset_of
    end

    Vertex.define_layout self, layout, vtype, false
  end

  if @vertex_classes[vtype].const_defined? :Instance
    Instance.instance_classes[vtype] = @vertex_classes[vtype]::Instance
  end

  @vertex_classes[vtype]
end

.make_type(types) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'ext/gl_vertex.c', line 87

static
VALUE ray_gl_vertex_make_type(VALUE self, VALUE types) {
  size_t size = RARRAY_LEN(types);
  if (size == 0) {
    rb_raise(rb_eArgError, "can't create empty vertex type");
  }

  size_t vtype_id = say_vertex_type_make_new();
  say_vertex_type *vtype = say_get_vertex_type(vtype_id);

  for (size_t i = 0; i < size; i++) {
    VALUE element = RAY_ARRAY_AT(types, i);

    VALUE name = RAY_ARRAY_AT(element, 0);
    VALUE type = RAY_ARRAY_AT(element, 1);

    VALUE per_instance = RAY_ARRAY_AT(element, 2);

    char *c_name = say_strdup(StringValuePtr(name));
    say_vertex_elem_type c_type = NUM2INT(rb_hash_aref(ray_gl_vertex_types,
                                                       type));

    say_vertex_elem c_elem = {c_type, c_name, RTEST(per_instance)};
    say_vertex_type_push(vtype, c_elem);
  }

  return INT2FIX(vtype_id);
}

.offset_of(vtype, elem_id) ⇒ Object



116
117
118
119
120
# File 'ext/gl_vertex.c', line 116

static
VALUE ray_gl_vertex_offset_of(VALUE self, VALUE vtype, VALUE elem_id) {
  say_vertex_type *type = say_get_vertex_type(NUM2ULONG(vtype));
  return INT2FIX(say_vertex_type_get_offset(type, NUM2INT(elem_id)));
}

.size(vtype) ⇒ Object



122
123
124
125
126
# File 'ext/gl_vertex.c', line 122

static
VALUE ray_gl_vertex_size(VALUE self, VALUE vtype) {
  say_vertex_type *type = say_get_vertex_type(NUM2ULONG(vtype));
  return INT2FIX(say_vertex_type_get_size(type));
}

Instance Method Details

#pretty_print(q) ⇒ Object



175
176
177
178
179
180
181
182
# File 'lib/ray/gl/vertex.rb', line 175

def pretty_print(q)
  attr = []
  self.class.layout.each do |key, _, _, per_instance|
    attr << key unless per_instance
  end

  pretty_print_attributes q, attr
end

#to_sObject



166
167
168
169
170
171
172
173
# File 'lib/ray/gl/vertex.rb', line 166

def to_s
  pairs = []
  self.class.layout.each do |key, _, _, per_instance|
    pairs << "#{key}=#{send(key)}" unless per_instance
  end

  "#<#{self.class} #{pairs.join " "}>"
end