• 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!

SOLVED Problems moving data from buffer into vertex buffer

Hi.

I've made an exporter for blender that exports models for importing into gamemaker.
First, it writes the number of mesh objects in the scene. For every mesh object in the scene: it saves the object's position, scale, rotation, number of triangles, then followed by the vertex data of the mesh. For the vertex data, it writes the position, normal, colour and texcoord of every triangle corner. The vertex data is laidout in the same way a vertex buffer is laid out in memory in gamemaker.

I've made the following script for importing these model files:
GML:
var _buff = buffer_load(_filepath);
var _num_objects = buffer_read(_buff, buffer_u32);
var _mesh_array = array_create(_num_objects);
var _offset = 4; //offset starts after num_objects

for (var _i = 0; _i < _num_objects; _i++) {
    var _obj_pos = new vec3(
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32)
    );
    var _obj_rot = new vec3(
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32)
    );
    var _obj_scale = new vec3(
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32)
    );
    var _num_triangles = buffer_read(_buff, buffer_u32);

    _offset += 40; //pos, rot, scale and num_triangles advances offset by 40 bytes
    var _vbuff = vertex_create_buffer_from_buffer_ext(_buff, global.standard_vertex_format, _offset, _num_triangles*3);
    _offset += _num_triangles*3*36; //total size of single vertex is 36 bytes

    _mesh_array[@_i] = {
        position     : _obj_pos,
        rotation     : _obj_rot,
        scale        : _obj_scale,
        vbuffer      : _vbuff
    };
}

ds_map_replace(global.asset_map, _filepath, _mesh_array);
return _mesh_array;
This script works perfectly:
yes.png

However, I plan on adding more features to my game that will require more control over how the data is imported. Instead of reading in a vertex buffer all at once, I want to be able to read in each vertex individually. This makes it much easier to modify or add additional data to each vertex depending on how the model will be used. Example: adding additional uv channels and data to each vertex, etc...

I made the following script in an attempt to achieve this:
GML:
var _buff = buffer_load(_filepath);
var _num_objects = buffer_read(_buff, buffer_u32);
var _mesh_array = array_create(_num_objects);

for (var _i = 0; _i < _num_objects; _i++) {
    var _obj_pos = new vec3(
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32)
    );
    var _obj_rot = new vec3(
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32)
    );
    var _obj_scale = new vec3(
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32),
        buffer_read(_buff, buffer_f32)
    );
    var _num_triangles = buffer_read(_buff, buffer_u32);

    var _vbuff = vertex_create_buffer();
    vertex_begin(_vbuff, global.standard_vertex_format);
    for (var _j = 0; _j < _num_triangles; _j++) {
        for (var _k = 0; _k < 3; _k++) {
            vertex_position_3d(_vbuff,
                buffer_read(_buff, buffer_f32),
                buffer_read(_buff, buffer_f32),
                buffer_read(_buff, buffer_f32));

            vertex_normal(_vbuff,
                buffer_read(_buff, buffer_f32),
                buffer_read(_buff, buffer_f32),
                buffer_read(_buff, buffer_f32));

            vertex_color(_vbuff,
                make_color_rgb(
                    buffer_read(_buff, buffer_u8),
                    buffer_read(_buff, buffer_u8),
                    buffer_read(_buff, buffer_u8)),
                buffer_read(_buff, buffer_u8));

            vertex_texcoord(_vbuff,
                buffer_read(_buff, buffer_f32),
                buffer_read(_buff, buffer_f32));

            //additional game data here...
        }
    }
    vertex_end(_vbuff);

    _mesh_array[@_i] = {
        position     : _obj_pos,
        rotation     : _obj_rot,
        scale        : _obj_scale,
        vbuffer      : _vbuff
    };
}

ds_map_replace(global.asset_map, _filepath, _mesh_array);
return _mesh_array;
It works, but it rotates the model...
It looks like it's swapping the x and z of every vertex...
no.png
Not only that, but it also swaps the u and v coordinates...
The exporter and data is exactly the same in both cases. I also opened the file in a hex editor and verified that the data was correct, the x, y, z and uv are written in the correct order, etc...
I would really like to know why this happens, and what gamemaker wierdness is at play here.

What differences are there between creating a vertex buffer manually vs with vertex_create_buffer_from_buffer?

Any tips would be very much appreciated.
Thanks.
 
Last edited:

Bart

WiseBart
That code looks okay at first sight. There is one thing that comes to mind, though.
Is there a possibility that GM doesn't assign the values of the function arguments in the order that you're expecting? You're working with buffer_read, which reads the values in order, so the first call to it will read x, the second y and the third z. But in what order are the function arguments assigned by GM?
That could well explain what you're seeing. If GM assigns the values of function arguments backwards X and Z would get swapped (i.e. XYZ changes to ZYX) and U and V as well (UV changes to VU). The same for normal and color.
It's something you won't have in the other case where you're using vertex_create_buffer_from_buffer_ext.
 
Is there a possibility that GM doesn't assign the values of the function arguments in the order that you're expecting?
I did some experimenting and it turns out that when you pass expressions as function parameters, the expressions are executed in the reverse order that they are passed in.
GML:
test = function(_x, _y, _z) {
    show_debug_message(
    "x: "   + string(_x) +
    "\ny: " + string(_y) +
    "\nz: " + string(_z));
};

print = function(_val) {
    show_debug_message(string(_val));
    return _val;
};

test(print(1), print(2), print(3));
The above creates the following output:
Code:
3
2
1
x: 1
y: 2
z: 3
So passing in multiple buffer_read calls will naturally assign the values in the wrong order.
 
Top