buffer_copy_stride

This function copies the given number of items from a source buffer to a destination buffer, where all items have the same size in bytes and are spaced apart evenly by a different number of bytes in the source and destination buffer.

You can use this function with buffers that store items and their attributes in a structured way, e.g. game data, vertex data or any other data in a known format.

NOTE You cannot copy to the same buffer.

The function call belonging to the above diagram would look as follows: buffer_copy_stride(src_buffer, 6, 2, 6, 3, dest_buffer, 8, 2);

You can interpret the source offset as the sum of two offsets: an offset to the start of the item data and an offset within the item (i.e. which attribute of the item to copy).

Stride

The stride is the number of bytes to go from one item to the next. A positive value moves forward, a negative value moves backward.

For example, in case of GameMaker's default vertex format the stride value is 24 (3*4+4*1+2*4). The number of bytes to move from one (x, y, z) position in the buffer to the next is 24, the number of bytes to move from one colour value to the next is also 24, as well as the number of bytes to move from one UV to the next.

You "select" the attribute you want to copy by changing the offset, meanwhile the stride remains unchanged: 

How It Works

Usage Notes

 

Syntax:

buffer_copy_stride(src_buffer, src_offset, src_size, src_stride, src_count, dest_buffer, dest_offset, dest_stride);

ArgumentTypeDescription
src_bufferBufferThe buffer containing the source data
src_offsetRealThe offset, in bytes, in the source buffer to start copying bytes. When negative, it is subtracted from the buffer size.
src_sizeRealThe size, in bytes, of a single item to copy
src_strideRealThe number of bytes between two items. This value can be negative and be set to 0.
src_countRealThe number of items to copy
dest_bufferBufferThe buffer to copy the data to
dest_offsetRealThe offset, in bytes, in the destination buffer to write the data. This offset can be negative.
dest_strideRealThe number of bytes between two items in the destination buffer. This value can be negative.

 

Returns:

N/A

 

Example 1: Basic Usage

var _num_items = 200;
var _attribute_size = buffer_sizeof(buffer_u16);
var _itemsize_source = buffer_sizeof(buffer_f32) + _attribute_size;
buff_source = buffer_create(_num_items * _itemsize_source, buffer_fixed, 1);
buff_destination = buffer_create(_num_items * _attribute_size, buffer_fixed, 1);

var _i = 0;
repeat(_num_items)
{
    buffer_write(buff_source, buffer_f32, random_range(-100, 100));
    buffer_write(buff_source, buffer_u16, _i++);
}

buffer_copy_stride(buff_source, 4, _attribute_size, _itemsize_source, _num_items, buff_destination, 0, _attribute_size);

The above code shows basic usage of the buffer_copy_stride function. First, a couple of temporary variables are defined that store the number of items in source and destination buffer, the stride of the source buffer and the size of an item. Two buffers of fixed size are then created, one to store the source data and one to store the destination data. The references to them are stored in the variables buff_source and buff_destination respectively. Next, the source buffer has 200 items written to it using buffer_write. Every item consists of one random buffer_f32 value between -100 and 100 followed by a buffer_f16 value that stores an index. Finally, the second buffer_f16 element of each item is copied to the destination buffer using buffer_copy_stride. The first buffer_f16 value is written to byte 0 (as dest_offset is set to 0), the next one is written to byte 2 (dest_stride is set to _itemsize which is 2), the next one to byte 4, and so on. After the function call, buff_destination will contain the 200 buffer_f16 values in buff_source one right after the other, with no bytes in-between.

 

Example 2: Negative Offset & Stride

var _item_size = buffer_sizeof(buffer_f32);
var _num_items = 100;

var _i = 0;
buff_numbers = buffer_create(_num_items * _item_size, buffer_fixed, 4);
repeat(_num_items) buffer_write(buff_numbers, buffer_f32, _i++);

buff_data = buffer_create(2048, buffer_fixed, 4);
buffer_copy_stride(buff_numbers, -_item_size, _item_size, -_item_size, _num_items, buff_data, 0, 12);

The above code first initialises two temporary variables that are used in the code that follows: the size of a single item _item_size and the number of items _num_items. It then creates a new buffer of a fixed size with room for this number of items. The byte alignment can be set to 4 since every item is stored at an integer multiple of 4 bytes. Next, a repeat loop writes the values 0 to 100 to the buffer, using buffer_write. After that, another fixed-size buffer of 2048 bytes is created and stored in the variable buff_data. Finally, buffer_copy_stride is called to write the numbers in the source buffer buff_numbers to the destination buffer buff_data. Because of the negative value of the source offset, the last number in the buffer is the first one to be written. Also, the numbers are traversed backwards because of the negative value of the source stride. The destination stride of 12 makes sure the numbers are spaced 12 bytes apart in buff_data. As a result buff_data contains the numbers in reverse order, with 12 bytes between each of them.

 

Example 3: Stride set to 0

var _item_size = buffer_sizeof(buffer_f32);
buff_source = buffer_create(_item_size, buffer_fixed, 4);
buff_destination = buffer_create(16 * _item_size, buffer_fixed, 4);

buffer_write(buff_source, buffer_f32, 1);

buffer_copy_stride(buff_source, 0, _item_size, 0, 4, buff_destination, 0, 5 * _item_size);

The above code shows how you can use a stride value of 0 to keep copying the same value multiple times to a destination buffer.

First, the size of an item is set to the size of a float (buffer_f32) and stored in _item_size. Next, the source and destination buffer are created with a fixed size and an alignment of 4 (since floats always align to multiples of 4 bytes). The source buffer can only store a single float, the destination buffer can store 16 floats. Then, the value 1 is written to the source buffer. Finally, this value is copied a total of 4 times using buffer_copy_stride with a destination stride value of 5 times the item size. After the function has finished buff_destination will contain the values of an identity matrix.

 

Example 4: Interleaving Data from Multiple Buffers

Create Event

vertex_format_begin();
array_foreach([vertex_format_add_position_3d, vertex_format_add_colour, vertex_format_add_texcoord], script_execute);
vertex_format = vertex_format_end();

buff_positions_xyz = buffer_base64_decode("JqwCQwuLi0J5DIBBcQc3Q27Ar0NNpBZD+WSqQ8B9OEPB0YtD");
buff_colours_rgba = buffer_base64_decode("Ud93/wghI//D2cr/");
buff_uvs = buffer_base64_decode("9KQyP69/UT9Uxak+ybENPzKNZzwxS1A9");

buff_vertex_data = buffer_create(3 * 24, buffer_fixed, 1);
buffer_copy_stride(buff_positions_xyz, 0, 3 * 4, 3 * 4, 3, buff_vertex_data, 0, 24);
buffer_copy_stride(buff_colours_rgba, 0, 4 * 1, 4 * 1, 3, buff_vertex_data, 12, 24);
buffer_copy_stride(buff_uvs, 0, 2 * 4, 2 * 4, 3, buff_vertex_data, 16, 24);
vb = vertex_create_buffer_from_buffer(buff_vertex_data, vertex_format);

Draw Event

vertex_submit(vb, pr_trianglelist, -1);

The above example shows how to join together data that's stored as attributes in separate buffers. The data are combined into a single buffer, in which the data are interleaved.

First, in the Create event, the default vertex format is created and assigned to an instance variable vertex_format. Then the three buffers containing the attribute data are created from base64-encoded data: buff_positions_xyz stores the (x, y, z) position data of 3 vertices, buff_colours_rgba stores their RGBA colour data and buff_uvs their UV data. The values of each attribute are stored one after the other, e.g. buff_positions_xyz stores the (x, y, z) position of the first vertex, followed by the (x, y, z) position of the second vertex, followed by that of the third vertex, etc.

After that, another buffer buff_vertex_data is created to store the interleaved vertex data. Each of the three calls to buffer_copy_stride then reads the values of each attribute (position, colour and uv) and places them in the correct positions in the destination buffer, leaving room for the other attributes to be written by the next call to the function. Finally a vertex buffer is created from the data in the buffer.

In the Draw event, the vertex buffer is submitted. This will draw a triangle.