SFML community forums

Bindings - other languages => General => Topic started by: Rowad on June 29, 2013, 12:35:33 am

Title: Can't modify Vertex of a VertexArray
Post by: Rowad on June 29, 2013, 12:35:33 am
Hi !

I use rbSFML in my project. It works like a charm but I can't figure out how to get VertexArray to work properly.
My code :
require 'sfml'

include SFML


class MainWindow
  def initialize(width, height)
    @window = RenderWindow.new([width, height], "VertexArray")
   
    @vertices = VertexArray.new(Triangles, 3)
   
    @vertices[0].position = [100, 100]
    @vertices[1].position = [200, 100]
    @vertices[2].position = [200, 200]
   
    @vertices[0].color = Color::Red
    @vertices[1].color = Color::Green
    @vertices[2].color = Color::Blue
   
    update
  end

  def update
    while @window.open?
      @window.each_event do |event|
         @window.close if event.type == Event::Closed
      end
      @window.clear
      @window.draw(@vertices)
      @window.display
    end
  end
 
end

MainWindow.new(640, 480)

But the triangle isn't drawn :/

I've done some testing and it seems that "@vertices[id]" return a new Vertex so I can't modify the Vertex of VertexArray.
For example, if I do something like that :
    @vertices = VertexArray.new(Triangles, 3)
    vertex = @vertices[0]
    vertex.position = [100, 100]
    p @vertices[0].position == vertex.position #=> false
The vertex in the VertexArray doesn't have the new position.

The only way I've find to do what I want is to clear the VertexArray and fill it with new Vertex (by using the "append" function) each time I want to modify a Vertex.

I've tried with a ruby array instead of a VertexArray. Works well but it's pretty slow.

So how can I easily change the Vertex position/color/texture of a VertexArray ?

I use the latest version of rbSFML on github and SFML2.0.



Thanks in advance ;)
Title: Re: Can't modify Vertex of a VertexArray
Post by: Groogy on June 29, 2013, 03:24:10 pm
Ah this is something on my todo list I have to remember to fix.

The VertexArray returns a copy of the Vertex and not a reference. Getting it to return a reference won't be an easy task though.

You can do something like this:

vertex = SFML::Vertex.new
# do changes
array[0] = vertex
# do changes
array[1] = vertex

SFML::Vertex is a pure Ruby object itself, so it's really lightweight so this should not perform any performances issues for you.

Edit: Also #append is super fast actually. The vertex array in SFML is just a wrapper above a std::vector, so the size is cached and even if you clear the array the memory won't be free'd.
Title: Re: Can't modify Vertex of a VertexArray
Post by: Rowad on June 29, 2013, 07:30:44 pm
Thanks for the answer !

You can do something like this:

vertex = SFML::Vertex.new
# do changes
array[0] = vertex
# do changes
array[1] = vertex
But in this example, array is a "ruby array" ? Because I don't know how to do that with a VertexArray.

And I really can't use a ruby array in my project :
I draw a tilemap with 8x8 tiles on a window of 640x480, so 4800 quads.

This code with a VertexArray :
require 'sfml'

include SFML

class MainWindow
  QUAD_SIZE = 8
  def initialize(width, height)
    @window = RenderWindow.new([width, height], "VertexArray")
    @window.framerate_limit = 60
    @vertices = VertexArray.new(Quads, 0)
   
    for x in 0...@window.get_size.x/QUAD_SIZE
      for y in 0...@window.get_size.y/QUAD_SIZE
        color = [Color::Red, Color::Green, Color::Blue].sample
        @vertices.append(Vertex.new([x*QUAD_SIZE, y*QUAD_SIZE], color))
        @vertices.append(Vertex.new([(x+1)*QUAD_SIZE, y*QUAD_SIZE], color))
        @vertices.append(Vertex.new([(x+1)*QUAD_SIZE, (y+1)*QUAD_SIZE], color))
        @vertices.append(Vertex.new([x*QUAD_SIZE, (y+1)*QUAD_SIZE], color))
      end
    end

    update
  end

  def update
    while @window.open?
      @window.each_event do |event|
         @window.close if event.type == Event::Closed
      end
      @window.clear
      @window.draw(@vertices)
      @window.display
    end
  end
 
end
MainWindow.new(640, 480)
 
Run smoothly with stable 60FPS

But the same code with a ruby array instead of a VertexArray :
require 'sfml'

include SFML

class MainWindow
  QUAD_SIZE = 8
  def initialize(width, height)
    @window = RenderWindow.new([width, height], "VertexArray")
    @window.framerate_limit = 60
    @vertices = Array.new
   
    for x in 0...@window.get_size.x/QUAD_SIZE
      for y in 0...@window.get_size.y/QUAD_SIZE
        color = [Color::Red, Color::Green, Color::Blue].sample
        @vertices.push(Vertex.new([x*QUAD_SIZE, y*QUAD_SIZE], color))
        @vertices.push(Vertex.new([(x+1)*QUAD_SIZE, y*QUAD_SIZE], color))
        @vertices.push(Vertex.new([(x+1)*QUAD_SIZE, (y+1)*QUAD_SIZE], color))
        @vertices.push(Vertex.new([x*QUAD_SIZE, (y+1)*QUAD_SIZE], color))
      end
    end

    update
  end

  def update
    while @window.open?
      @window.each_event do |event|
         @window.close if event.type == Event::Closed
      end
      @window.clear
      @window.draw(@vertices, Quads, RenderStates::Default)
      @window.display
    end
  end
 
end
MainWindow.new(640, 480)
Give me around 20FPS.


+ I really need a way to modify a particular Vertex :
I have animated tiles, and it's pretty slow to clear the VertexArray, loop through all the 4800tiles, re-create each Vertex just to change the texture coordinates of one tile :/
Title: Re: Can't modify Vertex of a VertexArray
Post by: Groogy on June 29, 2013, 08:55:29 pm
Aight, I will put a []= operator in the class tomorrow.

I want references to the individual vertices, but that would mean that I have to wrap the sf::Vertex class, they have to be dynamically allocated, and I have to manage the references between them and other classes(like sf::VertexArray). As it is now Ruby does it for me since the object is a light weight ruby object that is just there temporarily. The Ruby GC is quite good at reusing small objects with small life times.