• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GML [Solved] Vertex Buffer TexCoord

Alireza

Member
Hello guys
I had decided to use primitives to draw a sprite, to be precise I wanted to use pr_trianglelist. But then I realized that primitives can have a limited number of vertexes and if there are more than a 1000 of them the rest of them wont get drawn (look at picture 1), To fix this problem the sprite can be controlled by several objects (this is not very logical) or vertex buffer can be used.
After I used the vertex buffer I encounter a problem with calculating the correct UV of the sprite (picture 2), however this gets even stranger...if the size of the sprite is one of the powers of 2 and its located in a seperate texture page the problem with calculating the UV is solved (picture 3).
When the sprite is not one of the powers of 2 how do I calculate UV?

The code of the object that draws the sprite:

Create event :
Code:
sprite                = sTwo;
spriteWidth            = sprite_get_width(sprite);
spriteHeight        = sprite_get_height(sprite);
texture                = sprite_get_texture(sprite, image_index);
uvs                    = texture_get_uvs(texture);
uvLeft                = uvs[0];
uvTop                  = uvs[1];
uvRight              = uvs[2];
uvBottom            = uvs[3];
xStart = xstart;
yStart = ystart;
pointsNumberWidth   = 10;
pointsNumberHeight    = 8;
segmentWidth        = spriteWidth / (pointsNumberWidth - 1);
segmentHeight       = spriteHeight / (pointsNumberHeight - 1);
widthTex            = 1 / (pointsNumberWidth - 1);
heightTex              = 1 / (pointsNumberHeight - 1);
// Create vertex format
vertex_format_begin();
vertex_format_add_position();
vertex_format_add_texcoord();
vertex_format_add_color();
vertexFormat = vertex_format_end();
Step event :
Code:
// Move object
if(mouse_check_button(mb_left))
{
    xStart = mouse_x;
    yStart = mouse_y;
}
Draw event :
Code:
// Debug points
draw_circle_color(xStart, yStart, 8, c_red, c_red, false);
draw_circle_color(xStart + spriteWidth, yStart + spriteHeight, 8, c_red, c_red, false);

var _vertexBuffer = vertex_create_buffer();
vertex_begin(_vertexBuffer, vertexFormat);

for(var _i = 0; _i < (pointsNumberHeight - 1); ++_i)
{
    for(var _j = 0; _j < (pointsNumberWidth - 1); ++_j)
    {
        var _pointOneX        = xStart + _j * segmentWidth;
        var _pointOneY        = yStart + _i * segmentHeight;
        var _pointOneXTex    = uvLeft + (_j * widthTex);
        var _pointOneYTex    = uvTop + (_i * heightTex);
     
        var _pointTwoX        = xStart + (_j + 1) * segmentWidth;
        var _pointTwoY        = yStart + _i * segmentHeight;
        var _pointTwoXTex    = uvLeft + ((_j + 1) * widthTex);
        var _pointTwoYTex    = uvTop + (_i * heightTex);
     
        var _pointThreeX        = xStart + (_j + 1) * segmentWidth;
        var _pointThreeY        = yStart + (_i + 1) * segmentHeight;
        var _pointThreeXTex        = uvLeft + ((_j + 1) * widthTex);
        var _pointThreeYTex        = uvTop + ((_i + 1) * heightTex);
     
        // Triangle one
        vertex_position(_vertexBuffer, _pointOneX, _pointOneY);
        vertex_texcoord(_vertexBuffer, _pointOneXTex, _pointOneYTex);
        vertex_color(_vertexBuffer, c_white, 1);
     
        vertex_position(_vertexBuffer, _pointTwoX, _pointTwoY);
        vertex_texcoord(_vertexBuffer, _pointTwoXTex, _pointTwoYTex);
        vertex_color(_vertexBuffer, c_white, 1);
     
        vertex_position(_vertexBuffer, _pointThreeX, _pointThreeY);
        vertex_texcoord(_vertexBuffer, _pointThreeXTex, _pointThreeYTex);
        vertex_color(_vertexBuffer, c_white, 1);
    }
}

vertex_end(_vertexBuffer);
vertex_submit(_vertexBuffer, pr_trianglelist, texture);
vertex_delete_buffer(_vertexBuffer);
 

Attachments

Ido-f

Member
iirc, sprite_get_texture gives you a pointer to the sprite's texture page.
So when you're assigning the uvs variable using texture_get_uvs you're getting the uv's for that texture page, which I believe will always be 0 to 1.
What you actually need is the uv start and end information of the sprite within its texture page.
So try using sprite_get_uvs instead for the uvs variable - then you also wouldn't need to have the sprite in a seperate texture page (which would be a downside for performance).
 
Last edited:

Alireza

Member
iirc, sprite_get_texture gives you a pointer to the sprite's texture page.
So when you're assigning the uvs variable using texture_get_uvs you're getting the uv's for that texture page, which I believe will always be 0 to 1.
What you actually need is the uv start and end information of the sprite within its texture page.
So try using sprite_get_uvs instead for the uvs variable - then you also wouldn't need to have the sprite in a seperate texture page (which would be a downside for performance).
Thanks for the guide
All I needed to do was change how to calculate widthTex and heightTex in the Create event.

Code:
sprite              = sTwo;
spriteWidth        = sprite_get_width(sprite);
spriteHeight    = sprite_get_height(sprite);
texture            = sprite_get_texture(sprite, image_index);
uvs                = sprite_get_uvs(sprite, image_index);
uvLeft            = uvs[0];
uvTop            = uvs[1];
uvRight            = uvs[2];
uvBottom        = uvs[3];
xStart = xstart;
yStart = ystart;
pointsNumberWidth    = 70;
pointsNumberHeight    = 50;
segmentWidth        = spriteWidth / (pointsNumberWidth - 1);
segmentHeight        = spriteHeight / (pointsNumberHeight - 1);
widthTex    = (uvRight - uvLeft) / (pointsNumberWidth - 1);
heightTex    = (uvBottom - uvTop) / (pointsNumberHeight - 1);

// Create vertex format
vertex_format_begin();
vertex_format_add_position();
vertex_format_add_texcoord();
vertex_format_add_color();
vertexFormat = vertex_format_end();
 
Let me expand on the information returned by sprite_get_uvs.

Elements 0 through 3 contains the left, top, right, and bottom uv coordinates.

_tl = _uvs[0];
_tt = _uvs[1];
_tr = _uvs[2];
_tb = _uvs[3];

The next four elements contain information about how the transparent regions around your sprite image have been cropped when it was compiled to the texture page. This allows you to position the vertices correctly without causing the sprite image to appear distorted.

Elements 4 and 5 are how many pixels have been cropped off the left and top sides of the sprite image.

Elements 6 and 7 are the size of the sprite image on the texture page as a proportion of the original sprite's width and height.

If you draw a sprite as a quad, the following bit of code can calculate the location of the sides of this quad relative to the origin of the sprite.

_uvs = sprite_get_uvs( _sprite, _sub );
_tx = _uvs[4];
_ty = _uvs[5];
_th = _uvs[6];
_tv = _uvs[7];
_pl = -sprite_get_xoffset(_sprite) + _tx;
_pt = -sprite_get_yoffset(_sprite) + _ty;
_pr = _pl + sprite_get_width(_sprite) * _th;
_pb = _pt + sprite_get_height(_sprite) * _tv;
 
Top