ext/gl_buffer.c in ray-0.1.1 vs ext/gl_buffer.c in ray-0.2.0
- old
+ new
@@ -46,25 +46,71 @@
*ptr = say_buffer_create(ray_get_vtype(vtype), ray_buf_type(type), 256);
return self;
}
-/* Unbinds any buffer that was bound. */
+/* @return [Boolean] True if the buffer has instance-specific data */
static
+VALUE ray_gl_buffer_has_instance(VALUE self) {
+ return say_buffer_has_instance(ray_rb2buffer(self)) ? Qtrue : Qfalse;
+}
+
+/* Unbinds any bound buffer */
+static
VALUE ray_gl_buffer_unbind(VALUE self) {
say_buffer_unbind();
return Qnil;
}
-/* Binds the receiver */
+/* Unbinds any bound VBO from array buffer */
static
+VALUE ray_gl_buffer_unbind_vbo(VALUE self) {
+ say_buffer_unbind_vbo();
+ return Qnil;
+}
+
+/* Binds the receiver, allowing to draw data stored in it */
+static
VALUE ray_gl_buffer_bind(VALUE self) {
say_buffer_bind(ray_rb2buffer(self));
return self;
}
+/* Binds the receivers's VBO as an OpenGL array buffer */
+static
+VALUE ray_gl_buffer_bind_vbo(VALUE self) {
+ say_buffer_bind_vbo(ray_rb2buffer(self));
+ return self;
+}
+
/*
+ * Binds the receivers's VBO containing instance data as an OpenGL array buffer
+ */
+static
+VALUE ray_gl_buffer_bind_instance_vbo(VALUE self) {
+ say_buffer_bind_instance_vbo(ray_rb2buffer(self));
+ return self;
+}
+
+/*
+ * @return [Integer] The identifier of the OpenGL buffer used by the buffer
+ */
+static
+VALUE ray_gl_buffer_vbo(VALUE self) {
+ return ULONG2NUM(say_buffer_get_vbo(ray_rb2buffer(self)));
+}
+
+/*
+ * @return [Integer] The identifier of the OpenGL buffer used by the buffer to
+ * store per-instance data
+ */
+static
+VALUE ray_gl_buffer_instance_vbo(VALUE self) {
+ return ULONG2NUM(say_buffer_get_instance_vbo(ray_rb2buffer(self)));
+}
+
+/*
* @overload [](id)
* @param [Integer] id
* @return [Ray::GL::Vertex, Ray::Vertex] The vertex at the given index.
*/
static
@@ -121,12 +167,83 @@
memcpy(say_buffer_get_vertex(buf, index), ptr, byte_size);
return vertex;
}
+/*
+ * @overload get_instance(id)
+ * @param [Integer] id
+ * @return [Ray::GL::Vertex::Instance] The instance at the given index
+ */
+static
+VALUE ray_gl_buffer_get_instance(VALUE self, VALUE i) {
+ say_buffer *buf = ray_rb2buffer(self);
+ if (!say_buffer_has_instance(buf))
+ rb_raise(rb_eRuntimeError, "buffer has no instance data");
+
+ size_t size = say_buffer_get_instance_size(buf);
+ size_t index = NUM2ULONG(i);
+
+ if (index >= size)
+ return Qnil;
+
+ VALUE klass = rb_const_get(rb_iv_get(self, "@vertex_type"),
+ rb_intern("Instance"));
+ VALUE object = rb_funcall(klass, RAY_METH("allocate"), 0);
+
+ size_t byte_size = NUM2INT(rb_iv_get(klass, "@vertex_instance_size"));
+
+ void *ptr = NULL;
+ Data_Get_Struct(object, void, ptr);
+
+ memcpy(ptr, say_buffer_get_instance(buf, index), byte_size);
+
+ return object;
+}
+
/*
+ * @overload set_intance(id, value)
+ * @param [Integer] id
+ * @param [Ray::GL::Vertex::Instance] value The instance to set the given
+ * index.
+ */
+static
+VALUE ray_gl_buffer_set_instance(VALUE self, VALUE i, VALUE vertex) {
+ rb_check_frozen(self);
+
+ say_buffer *buf = ray_rb2buffer(self);
+
+ if (!say_buffer_has_instance(buf))
+ rb_raise(rb_eRuntimeError, "buffer has no instance data");
+
+ VALUE klass = rb_const_get(rb_iv_get(self, "@vertex_type"),
+ rb_intern("Instance"));
+ if (!RAY_IS_A(vertex, klass)) {
+ rb_raise(rb_eTypeError, "Can't convert %s into %s",
+ RAY_OBJ_CLASSNAME(vertex), rb_class2name(klass));
+ }
+
+ size_t size = say_buffer_get_instance_size(buf);
+ size_t index = NUM2ULONG(i);
+
+ if (index >= size) {
+ rb_raise(rb_eRangeError, "%zu is outside of range 0...%zu",
+ size, index);
+ }
+
+ size_t byte_size = NUM2INT(rb_iv_get(klass, "@vertex_instance_size"));
+
+ void *ptr = NULL;
+ Data_Get_Struct(vertex, void, ptr);
+
+ memcpy(say_buffer_get_instance(buf, index), ptr, byte_size);
+
+ return vertex;
+}
+
+/*
* @overload update(range = 0...size)
* @param [Range<Integer>] range Indices of vertices to update
*
* Updates a part of the buffer.
*
@@ -174,10 +291,64 @@
}
return self;
}
+/*
+ * @overload update_instance(range = 0...size)
+ * @param [Range<Integer>] range (see #update)
+ *
+ * Updates a part of the buffer's instance-specific data
+ *
+ * @overload update_instance(first, size)
+ * @param (see #update)
+ */
+static
+VALUE ray_gl_buffer_update_instance(int argc, VALUE *argv, VALUE self) {
+ say_buffer *buf = ray_rb2buffer(self);
+ size_t max_index = say_buffer_get_instance_size(buf);
+
+ if (!say_buffer_has_instance(buf))
+ rb_raise(rb_eRuntimeError, "buffer has no per-instance data");
+
+ if (argc == 0)
+ say_buffer_update_instance(buf);
+ else if (argc == 2) {
+ size_t begin = NUM2ULONG(argv[0]);
+ size_t end = NUM2ULONG(argv[1]);
+
+ if (end > max_index)
+ end = max_index;
+
+ if (begin > end || begin > max_index)
+ return self;
+
+ size_t size = (end - begin) + 1;
+
+ say_buffer_update_instance_part(buf, begin, size);
+ }
+ else {
+ VALUE range;
+ rb_scan_args(argc, argv, "1", &range); /* raise exception */
+
+ size_t begin = NUM2ULONG(rb_funcall(range, RAY_METH("begin"), 0));
+ size_t end = NUM2ULONG(rb_funcall(range, RAY_METH("end"), 0));
+
+ if (end > max_index)
+ end = max_index;
+
+ if (begin > end || begin > max_index)
+ return self;
+
+ size_t size = (end - begin) + 1;
+
+ say_buffer_update_instance_part(buf, begin, size);
+ }
+
+ return self;
+}
+
/* @return [Integer] Size of the buffer (amount of vertices it contains) */
static
VALUE ray_gl_buffer_size(VALUE self) {
return ULONG2NUM(say_buffer_get_size(ray_rb2buffer(self)));
}
@@ -193,11 +364,37 @@
rb_check_frozen(self);
say_buffer_resize(ray_rb2buffer(self), NUM2ULONG(size));
return self;
}
+/* @return [Integer] Amount of per-instance blocks in the buffer */
+static
+VALUE ray_gl_buffer_instance_size(VALUE self) {
+ say_buffer *buf = ray_rb2buffer(self);
+ if (!say_buffer_has_instance(buf))
+ return Qnil;
+ return ULONG2NUM(say_buffer_get_instance_size(buf));
+}
+
/*
+ * @overload resize_instance(size)
+ * @param [Integere] size (see #resize)
+ *
+ * Resizes the buffer's instance data, alsos causing it to be updated.
+ */
+static
+VALUE ray_gl_buffer_resize_instance(VALUE self, VALUE size) {
+ rb_check_frozen(self);
+ say_buffer *buf = ray_rb2buffer(self);
+ if (!say_buffer_has_instance(buf))
+ rb_raise(rb_eRuntimeError, "buffer has no per-instance data");
+ say_buffer_resize_instance(buf, NUM2ULONG(size));
+ return self;
+}
+
+
+/*
* Document-class: Ray::GL::Buffer
*
* Buffers are a low-level way to push vertices onto the GPU so you can draw
* them. They are used interally by higher level classes, such as
* Ray::BufferRenderer; Ray also keeps global buffers to store the vertices of
@@ -209,16 +406,40 @@
void Init_ray_gl_buffer() {
ray_cGLBuffer = rb_define_class_under(ray_mGL, "Buffer", rb_cObject);
rb_define_alloc_func(ray_cGLBuffer, ray_gl_buffer_alloc);
rb_define_method(ray_cGLBuffer, "initialize", ray_gl_buffer_init, 2);
+ rb_define_method(ray_cGLBuffer, "has_instance?", ray_gl_buffer_has_instance,
+ 0);
+
rb_define_singleton_method(ray_cGLBuffer, "unbind", ray_gl_buffer_unbind, 0);
+ rb_define_singleton_method(ray_cGLBuffer, "unbind_vbo",
+ ray_gl_buffer_unbind_vbo, 0);
rb_define_method(ray_cGLBuffer, "bind", ray_gl_buffer_bind, 0);
+ rb_define_method(ray_cGLBuffer, "bind_vbo", ray_gl_buffer_bind_vbo, 0);
+ rb_define_method(ray_cGLBuffer, "bind_instance_vbo",
+ ray_gl_buffer_bind_instance_vbo, 0);
+ rb_define_method(ray_cGLBuffer, "vbo", ray_gl_buffer_vbo, 0);
+ rb_define_method(ray_cGLBuffer, "instance_vbo", ray_gl_buffer_instance_vbo,
+ 0);
+
rb_define_method(ray_cGLBuffer, "[]", ray_gl_buffer_get, 1);
rb_define_method(ray_cGLBuffer, "[]=", ray_gl_buffer_set, 2);
+ rb_define_method(ray_cGLBuffer, "get_instance", ray_gl_buffer_get_instance,
+ 1);
+ rb_define_method(ray_cGLBuffer, "set_instance", ray_gl_buffer_set_instance,
+ 2);
+
rb_define_method(ray_cGLBuffer, "update", ray_gl_buffer_update, -1);
+ rb_define_method(ray_cGLBuffer, "update_instance",
+ ray_gl_buffer_update_instance, -1);
rb_define_method(ray_cGLBuffer, "size", ray_gl_buffer_size, 0);
rb_define_method(ray_cGLBuffer, "resize", ray_gl_buffer_resize, 1);
+
+ rb_define_method(ray_cGLBuffer, "instance_size", ray_gl_buffer_instance_size,
+ 0);
+ rb_define_method(ray_cGLBuffer, "resize_instance",
+ ray_gl_buffer_resize_instance, 1);
}