SFML community forums

Bindings - other languages => Python => Topic started by: shackra on January 19, 2013, 03:11:49 am

Title: [SOLVED] VertexArray & Vertex's tilemap nightmare
Post by: shackra on January 19, 2013, 03:11:49 am
Hello, hello! :D

I had a great progress on my framework, now, I have animated sprites :'D. BUT, I'm experiencing a lot of lag :-/ :(

 (http://www.youtube.com/watch?v=w8o7-sAnZ30)

A LOT! xd. I thought that was the tilemap drawing's fault, even if I'm drawing black squares on the screen (have to implement something to draw a color if no tmx file is passed), 10x10 pixels size in 80x60 tiles. Anyway, I want to use VertexArrays and Vertexs.

BOY! I don't have any idea at all about using VertexArrays to draw tilemaps, I was reading C++ and C# code but is like reading this:
Code: [Select]
使用系统;
使用SFML.Graphics;
使用SFML.Window;
使用测试;

命名空间SFML.Utils
{
    公共的委托无效TileProvider(X,Y,诠释层,出彩的颜色,出IntRect REC);
    MapRenderer:可绘制对象类
    {
        私人只读持股量TileSize;
        公共只读整型层;

        私人诠释的高度;
        私人诠释宽度;

        私人Vector2i偏移;
        私人顶点顶点;

        提供私人TileProvider;
        私人纹理质感;

        ,公共MapRenderer(纹理质地,TileProvider供应商,持股量tileSize=16,智力层=1)
        {
            (供应商== NULL | |层<= 0)抛出新的ArgumentException();
            this.provider供应商;

            TileSize tileSize;
            层=层;

            顶点=新的顶点[0];
            this.texture质感;

        }

        公共无效刷新()
        {
            RefreshLocal(0,0,宽度,高度);
        }

        私人无效RefreshLocal(左,诠释顶部,诠释的权利,诠释底部)
        {
            (VAR Y =顶部<底部,Y++)
                (VAR所述=左,X权; X ++)
                {
                    刷新(X + offset.X,Y+ offset.Y);
                }
        }

xD
anyway, get the idea, I don't understand ANYTHING! even that I can read C++ code. My question is:

How should I use VertexArray and Vertexs in order to draw tiles? because something that is confusing for me is the choosing a color for the Vertex. What's the idea of using that? Why you don't use a reference to a texture instead? Should I inherit from Drawable class and use the VertexArray and Vertex as an attributes?

I also like the idea of drawing only the vertex that the user sees (what he sees through sfml.View) but I don't know how to proceed, so, maybe a lay explication/mentoring might be helpful (once you understand how to use Vertex) for this.

cheers!
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: Sonkun on January 23, 2013, 03:01:57 am
Hello!

I see you wrote that four days ago, so sorry to be late on this. Don't hesitate to ask your questions via my private email address (in case I don't answer soon and you should get faster answers too :p). I'll make an effort to check the forum more often.

I'm aware there are performance issues (#65 (https://github.com/Sonkun/python-sfml/issues/65)) when doing intensive computation with vectors (since they're still handled at Python level) but I don't think this is your case. Note: this issue should be fixed soon since fused type Cython feature is now fixed in last stable release.

About Vertex and VertexArray:
First I would suggest to read the documentation, Vertex (http://python-sfml.org/api/graphics.html#vertex) and VertexArray (http://python-sfml.org/api/graphics.html#vertexarray), but I admit this is not enough to apprehend what is really going on and thus, write efficient code.

SFML is based on OpenGL. Basically, OpenGL only knows vertices location. Then you tell OpenGL to draw these vertices and how to link them to make shapes. E.g: You'll need four vertices to make a rectangle. Note that SFML use Vertex and VertexArray internally to draw your shapes, your sprites, etc.

As sf.VertexArray inherits from sf.Drawable, once you have defined your vertices and stored them in a VertexArray, you'll be able to draw as a traditional drawable (sprite, shape, text):
window.draw(vertex_array)

To try it out:
import sfml as sf
window = sf.RenderWindow(sf.VideoMode(640, 480), "pysfml")
lines = sf.VertexArray(sf.PrimitiveType.LINES_STRIP, 2)
lines[0].position = (10, 10)
lines[1].position = (100, 10)

lines.append(sf.Vertex((100, 100)))

lines.resize(4)
lines[3].position = (10, 100)

window.clear()
window.draw(lines)
window.display()
raw_input()
 

I'm glad you have animations working :) and hope you'll get your performance issues solved quickly!
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: shackra on January 24, 2013, 02:12:13 am
cool, a square!

I'm glad you have animations working :) and hope you'll get your performance issues solved quickly!

Yes, I did by filling the screen with white when no TMX file is passed to my AbstractScene class, just watch:

 (http://www.youtube.com/watch?v=ZRKxZcACyiY)

However, I'm trying to wrap my mind on this code that archives what I want https://github.com/SFML/SFML/wiki/Source:-TileMap-Render :(

EDIT:

I'm trying to undestand Tile-mapping with Vertexs... I wrote an example that goes like this:

#!/usr/bin/env python2
# coding: utf-8

import sfml

class Mapa(sfml.Drawable):
    def __init__(self, texture):
        sfml.Drawable.__init__(self)
        self.vertexarray = sfml.VertexArray(sfml.PrimitiveType.QUADS)
        self.texture = texture
       
    def draw(self, target, states):
        states.texture = self.texture
        target.draw(self.vertexarray, states)
       
def main():
    wn = sfml.RenderWindow(sfml.VideoMode(800, 600), "Prueba de Vertexs")
    wn.vertical_synchronization = True
    wn.framerate_limit = 60
   
    textura = sfml.Texture.from_file("textura.png")
    mapa = Mapa(textura)
    # Creamos una serie de vertexs conforme al mapa
    v1 = sfml.Vertex(sfml.Vector2(100, 1), sfml.Color.BLUE, sfml.Vector2(0, 0))
    v2 = sfml.Vertex(sfml.Vector2(300, 32), sfml.Color.RED, sfml.Vector2(0, 32))
    v3 = sfml.Vertex(sfml.Vector2(45, 64), sfml.Color.BLACK, sfml.Vector2(0, 64))
    v4 = sfml.Vertex(sfml.Vector2(32, 96), sfml.Color.YELLOW, sfml.Vector2(32, 0))
    # Existen más baldosas pero lo dejare hasta ahí
    for vertex in [v1, v2, v3, v4]:
        mapa.vertexarray.append(vertex)
       
    while wn.opened:
        for event in wn.events:
            if isinstance(event, sfml.CloseEvent):
                wn.close()
               
        wn.clear(sfml.Color.WHITE)
        wn.draw(mapa)
        wn.display()
       
if __name__ == "__main__":
    main()
 

and I got this:

(http://ompldr.org/vaDc3YQ/Captura%20de%20pantalla%20de%202013-01-23%2022:21:22.png)

Not what I was expecting xd. I'm using this image as texture:
(http://ompldr.org/vaDc3Yg/textura.png)

any help? :)
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: Sonkun on January 24, 2013, 04:47:55 pm
Unfortunately OpenGL doesn't support concave shape :D And by consequence, SFML neither :( But you can build them from multiple convex shapes if you really need (be warned, it's pain in the ass). But tiles are convex shapes so for your tile engine using Vertex and VertexArray, you're fine.

In your snipped code, you tried to construct a concave shape which renders badly, so you should try with a rectangle to start. This shape is built from vertices which all have a color, so your shape is filled with a gradient color (interpolation).  Then, you applied a texture on top of that which merges the texture and the gradient color and give you at the end a weird shape :). The third argument in Vertex constructor tex_coords tells OpenGL what part of your texture is used to fill the shape.

To experiment:

1) Start with a rectangle without texture
2) Then, try with white color points and a texture
3) Make your shape convex (other than a rectangle)
3) Modify tex_coords to fill your shape with different part of your texture

#!/usr/bin/env python2
# coding: utf-8

import sfml

class Mapa(sfml.Drawable):
    def __init__(self, texture):
        sfml.Drawable.__init__(self)
        self.vertexarray = sfml.VertexArray(sfml.PrimitiveType.QUADS)
        self.texture = texture
       
    def draw(self, target, states):
        states.texture = self.texture
        target.draw(self.vertexarray, states)
       
def main():
    wn = sfml.RenderWindow(sfml.VideoMode(800, 800), "Prueba de Vertexs")
    wn.vertical_synchronization = True
    wn.framerate_limit = 60
   
    textura = sfml.Texture.from_file("textura.png")
    mapa = Mapa(textura)

    # Creamos una serie de vertexs conforme al mapa
    v1 = sfml.Vertex(sfml.Vector2(10, 10), sfml.Color.WHITE, sfml.Vector2(0, 0))
    v2 = sfml.Vertex(sfml.Vector2(600, 50), sfml.Color.WHITE, sfml.Vector2(86, 0))
    v3 = sfml.Vertex(sfml.Vector2(450, 450), sfml.Color.WHITE, sfml.Vector2(86, 86))
    v4 = sfml.Vertex(sfml.Vector2(10, 300), sfml.Color.WHITE, sfml.Vector2(0, 86))
    v5 = sfml.Vertex(sfml.Vector2(10, 10), sfml.Color.WHITE, sfml.Vector2(0, 0))

    # Existen más baldosas pero lo dejare hasta ahí
    for vertex in [v1, v2, v3, v4, v5]:
        mapa.vertexarray.append(vertex)
       
    while wn.is_open:
        for event in wn.events:
            if isinstance(event, sfml.CloseEvent):
                wn.close()
               
        wn.clear(sfml.Color.WHITE)
        wn.draw(mapa)
        wn.display()
       
if __name__ == "__main__":
    main()
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: shackra on January 24, 2013, 05:59:10 pm
(http://ompldr.org/vaDdldw/Captura%20de%20pantalla%20de%202013-01-24%2010:09:38.png)

cool! :)

I feel like I'm not have the right idea about Vertex's position and text-coords (and sfml.PrimitiveType.QUADS). For instance, which position (on screen) and what's wrapping (from my texture) does
v1 = sfml.Vertex(sfml.Vector2(10, 10), sfml.Color.WHITE, sfml.Vector2(0, 0))
,
v2 = sfml.Vertex(sfml.Vector2(600, 50), sfml.Color.WHITE, sfml.Vector2(86, 0))
and
v3 = sfml.Vertex(sfml.Vector2(450, 450), sfml.Color.WHITE, sfml.Vector2(86, 86))
why 5 vertex and no 4 or 3? (that depends on the sfml.PrimitiveType.*?)

If you can add screenshots/pictures to your explanation, I'll appreciate that!

cheers!
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: Sonkun on January 24, 2013, 09:19:01 pm
This topic is rather related to how OpenGL work to render 2d vertices and its documentation might help you understand. Because SFML just provides wrappers to make things more convenient.

You're right, the fifth vertex is not necessary (and shouldn't even exist).

It's quite easy to understand, just keep things simple: you define 2d vertices (location + color), then tell OpenGL how to draw them (sf.PrimitiveType.QUAD is what you need here).

OpenGL will fill your shape with the colors you gave to your vertices. If you used four red vertices, your shape will be red. If you used multiple colors, you'll get a gradient color.

Additionally you can fill your shape with a texture as your screenshot shows it.

But now you can combine both and you'll get this result.
(http://ompldr.org/taDdrMw) (http://ompldr.org/vaDdrMw/Screenshot from 2013-01-24 21:02:57.png)

Now, use tex_coords to use the top left corner of your texture by replacing  86 with 46.
    v1 = sfml.Vertex(sfml.Vector2(10, 10), sfml.Color.RED, sfml.Vector2(0, 0))
    v2 = sfml.Vertex(sfml.Vector2(600, 50), sfml.Color.RED, sfml.Vector2(86, 0))
    v3 = sfml.Vertex(sfml.Vector2(450, 450), sfml.Color.RED, sfml.Vector2(86, 86))
    v4 = sfml.Vertex(sfml.Vector2(10, 300), sfml.Color.RED, sfml.Vector2(0, 86))
And you'll get this:

(http://ompldr.org/taDdqZA) (http://ompldr.org/vaDdqZA/Screenshot from 2013-01-24 19:22:36.png)
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: shackra on January 24, 2013, 10:07:04 pm
ok, ok, I'm getting the idea now.

Looks like you can only make one shape per vertexarray, no? how it comes for tilemapping? I'm missing something?
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: G. on January 24, 2013, 10:11:03 pm
You can (and will) have more than 4 vertices in your vertex array. ;)
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: shackra on January 28, 2013, 02:26:53 am
(http://img138.imageshack.us/img138/3897/capturadepantallade2013i.png) (http://imageshack.us/photo/my-images/138/capturadepantallade2013i.png/)

    # Creamos una serie de vertexs conforme al mapa
    v1 = sfml.Vertex(sfml.Vector2(0, 0), sfml.Color.WHITE, sfml.Vector2(0, 0))
    v2 = sfml.Vertex(sfml.Vector2(32*2, 0), sfml.Color.WHITE, sfml.Vector2(32, 0))
    v3 = sfml.Vertex(sfml.Vector2(32*2, 32*2), sfml.Color.WHITE, sfml.Vector2(32, 32))
    v4 = sfml.Vertex(sfml.Vector2(0, 32*2), sfml.Color.WHITE, sfml.Vector2(0, 32))
    v5 = sfml.Vertex(sfml.Vector2(32*2, 0), sfml.Color.WHITE, sfml.Vector2(64, 64))
    v6 = sfml.Vertex(sfml.Vector2(64*2, 0), sfml.Color.WHITE, sfml.Vector2(95, 64))
    v7 = sfml.Vertex(sfml.Vector2(64*2, 32*2), sfml.Color.WHITE, sfml.Vector2(95, 95))
    v8 = sfml.Vertex(sfml.Vector2(32*2, 32*2), sfml.Color.WHITE, sfml.Vector2(64, 95))
 

Ok, I think that I'm getting the idea now... what about moving vertex to just show the ones that the user can see? D:
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: Sonkun on January 28, 2013, 07:47:57 pm
I tried to understand the C++ code (about tile rendering using Vertex and VertexArray) but couldn't figure out why it would faster thus, sorry, I cannot help you about that.

By the way, seems you're mastering drawing shapes/tiles at hand, once you understand everything I won't mind a feedback :p
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: eXpl0it3r on January 28, 2013, 07:55:46 pm
I tried to understand the C++ code (about tile rendering using Vertex and VertexArray) but couldn't figure out why it would faster
The main reason is, that you only have one draw call for all the vertices, instead of N draw calls for N sprites (with 4 vertices). GPUs are built to process millions of vertices at once, thus there shouldn't be a problem passing on an huge array. ;)
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: Sonkun on January 28, 2013, 10:10:18 pm
Woaw, that's very interesting! I'm quite new to OpenGL, how do you set many textures to be all drawn in one call ? (I assumed you have one texture per tile.)
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: eXpl0it3r on January 28, 2013, 10:23:50 pm
(I assumed you have one texture per tile.)
Nope, you use one texture with all tiles on (if it's not too big) and then you simply set the texture coordinates you want your vertices to map to. ;)
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: Sonkun on January 28, 2013, 10:48:36 pm
Things get clearer now :p Thanks for the tip! :)
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: shackra on January 29, 2013, 06:50:28 am
I tried to understand the C++ code (about tile rendering using Vertex and VertexArray) but couldn't figure out why it would faster
The main reason is, that you only have one draw call for all the vertices, instead of N draw calls for N sprites (with 4 vertices). GPUs are built to process millions of vertices at once, thus there shouldn't be a problem passing on an huge array. ;)

However, I'm worried about perfomance with huge maps (8000x2000~ tiles), but what I don't get at all is the process of "moving" the right vertexs to the left top corner of the screen in order to start drawing the tiles.
Trying to figure out which Vertex are inside the View rect isn't good Idea either because some points of the 4 that compose the vertex will not been draw, thus, showing just three, two or one of them (as when you delete one vertice of a plane in Blender 3D, the plane lose its face!)

Maybe I should ask for more commentaries in that source code...

By the way, seems you're mastering drawing shapes/tiles at hand, once you understand everything I won't mind a feedback :p

No problem ;)
Title: AW: Re: VertexArray & Vertex's tilemap nightmare
Post by: eXpl0it3r on January 29, 2013, 12:15:44 pm
However, I'm worried about perfomance with huge maps (8000x2000~ tiles)
Once you run into performance issues, there are many possible optimization. One of the most common one is the divide the screen space into multiple vertex arrays and thrn only draw the ones that are actually visible.

but what I don't get at all is the process of "moving" the right vertexs to the left top corner of the screen in order to start drawing the tiles.
I've no idea what you're talking about here... ;)

Trying to figure out which Vertex are inside the View rect isn't good Idea either because some points of the 4 that compose the vertex will not been draw, thus, showing just three, two or one of them
In the logic part for culling you don't 'think' about points but about quads - you don't see 4 individual points, but a package of 4 points.
Title: Re: AW: Re: VertexArray & Vertex's tilemap nightmare
Post by: shackra on January 29, 2013, 10:15:39 pm
but what I don't get at all is the process of "moving" the right vertexs to the left top corner of the screen in order to start drawing the tiles.
I've no idea what you're talking about here... ;)
never mind xd

Trying to figure out which Vertex are inside the View rect isn't good Idea either because some points of the 4 that compose the vertex will not been draw, thus, showing just three, two or one of them
In the logic part for culling you don't 'think' about points but about quads - you don't see 4 individual points, but a package of 4 points.

Hmm, yes, indeed that approach makes more sense! :)

EDIT:

I'm doing some progress but without testing it...
So, I'm thinking on packages of 4 points as eXpl0it3r told me, and I must say that this is really easy than I thought before. Consider the following image:

(http://ompldr.org/vaGFndw/vertexs%20quad.png) (http://ompldr.org/vaGFndw/vertexs quad.png)

The trick here is to calculate correctly the coordinates for the first vertex (Vertex1 or v1), and then, use the position or tex_coords of the first Vertex to calculate the other 3 vertex of a Quad:

# We calculate the first vertex
v1 = sfml.Vertex(tex_coods=sfml.Vector2(
        float(x), float(y)))

# Then use v1.tex_coords to calculate the others
v2 = sfml.Vertex(tex_coords=sfml.Vector2(
        v1.tex_coords.x + tilewidth,
        v1.tex_coords.y))
v3 = sfml.Vertex(tex_coords=sfml.Vector2(
        v1.tex_coords.x + tilewidth,
        v1.tex_coords.y + tileheight))
v4 = sfml.Vertex(tex_coords=sfml.Vector2(
        v1.tex_coords.x,
        v1.tex_coords.y + tileheight))

# store the quad somewhere
tileimg = (v1, v2, v3, v4,)
 

very easy, right?
This should (yes, I didn't run any test yet) work also for positioning the quads on screen. Orthographic or Isometric maps, that no matters, just calculate the first vertex position correctly and everything else should flow naturally! 
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: shackra on January 31, 2013, 08:58:11 pm
(http://ompldr.org/vaGFzbw/Captura%20de%20pantalla%20de%202013-01-31%2013:53:27.png) (http://ompldr.org/vaGFzbw/Captura%20de%20pantalla%20de%202013-01-31%2013:53:27.png)

almost there!!...
Title: Re: VertexArray & Vertex's tilemap nightmare
Post by: shackra on February 01, 2013, 12:54:53 am
There is!!

(http://ompldr.org/vaGF3bg/Captura%20de%20pantalla%20de%202013-01-31%2017:45:11.png) (http://ompldr.org/vaGF3bg/Captura%20de%20pantalla%20de%202013-01-31%2017:45:11.png)

All tiles are drawn on screen, I need to implement that stuff drawing just those tiles that are visible!