DanielGavin / ols

Language server for Odin
MIT License
382 stars 58 forks source link

ols crashing, idk why #315

Closed xzores closed 4 months ago

xzores commented 4 months ago

Something in the file below creates the following errors:

"[Info - 8:06:31 PM] Connection to server got closed. Server will restart. true [Info - 8:06:31 PM] Connection to server got closed. Server will restart. true [Info - 8:06:32 PM] Connection to server got closed. Server will restart. true [Info - 8:06:32 PM] Connection to server got closed. Server will restart. true [Error - 8:06:32 PM] The Odin Language Server Client server crashed 5 times in the last 3 minutes. The server will not be restarted. See the output for more information. "

The file:

package render;

import "core:fmt"
import "core:reflect"
import "core:runtime"
import "core:mem"
import "core:slice"
import "core:log"
import "core:math"

import glsl "core:math/linalg/glsl"
import linalg "core:math/linalg"

import "gl"
import glgl "gl/OpenGL"

get_attribute_id_from_name :: proc (name : string, loc := #caller_location) -> Attribute_id {

    location, ok := reflect.enum_from_name(Attribute_location, name);

    if !ok {
        fmt.panicf("The name : %v is not a valid Attribute_location", name, loc = loc);
    }

    return auto_cast location;
}

get_attribute_info_from_typeid :: proc (t : typeid, loc := #caller_location) -> []gl.Attribute_info_ex {

    ti := type_info_of(t);

    attribs := make([dynamic]gl.Attribute_info_ex);

    //Strip the name
    if named, ok := ti.variant.(runtime.Type_Info_Named); ok {
        ti = named.base;
    }

    if struct_type_info, ok := ti.variant.(runtime.Type_Info_Struct); ok {
        fields := reflect.struct_fields_zipped(t);
        for field in fields {

            normalized : bool = false;

            if val, ok := reflect.struct_tag_lookup(field.tag, "ignore"); ok {
                if val == "true" {
                    continue;
                }
                else if val == "false" {

                }
                else {
                    fmt.panicf("%v ignore tag must have the value of 'true' or 'false'", t, loc = loc);
                }
            }

            if val, ok := reflect.struct_tag_lookup(field.tag, "normalized"); ok {
                if val == "true" {
                    normalized = true;
                }
                else if val == "false" {
                    normalized = false;
                }
                else {
                    fmt.panicf("%v normalized tag must have the value of 'true' or 'false'", t, loc = loc);
                }
            }

            attrib_ex : gl.Attribute_info_ex = {
                location = get_attribute_id_from_name(field.name),
                attribute_type = gl.odin_type_to_attribute_type(field.type.id),
                offset = field.offset,
                stride = auto_cast reflect.size_of_typeid(t),
                normalized = normalized,
            }

            log.debugf("attrib_ex : %#v\n", attrib_ex);

            append(&attribs, attrib_ex);
        }

    }
    else{
        panic("Type must be a struct", loc = loc);
    }

    return attribs[:];
}

Default_vertex :: struct {
    position    : [3]f32,
    texcoord    : [2]f32,
    normal      : [3]f32,
}

Mesh_buffers :: struct {
    vao : Vao_id,
    vertex_data : gl.Resource,
    indices_buf : Maybe(gl.Resource),
    fence : gl.Fence, //Only used when streaming.
}

//mesh should be more complex, as it needs to handle:
    //static meshes                                                                         - done
    //Async upload                                                                          - done
    //Dynamicly changing the mesh (sync or async)                                           - done
    //Double/triple and auto buffering                                                      - this can be done now
    //Frustum culling should be a thing we handle                                           - We can do this when we have made a camera
    //Somehow there is also a need for instance drawing (closely realated to mesh)          - 
    //And we should make multidraw a thing too                                              - 
    //Occlusion culling should be handled somehow?                                          - 
    //If this supportes dynamic meshes, then we should have multiple VAO's                  - 
Mesh :: struct {

    vertex_count    : int,              //The amount of verticies
    triangle_count  : int,              //The amount of verticies

    data_type : typeid,
    buffering : Buffering,
    usage : Usage,
    indices_type : Index_buffer_type,

    //TODO bouding_distance for culling??

    //TODO make mesh implementation.
    //implementaion :
    current_resource : int,
    resources : [dynamic]Mesh_buffers,
}

Index_buffer_type :: gl.Index_buffer_type;

Buffering :: enum {
    single,
    double,
    trible,
    auto,
}

Usage :: enum {
    static_use  = auto_cast gl.Resource_usage.static_write,     //You cannot update this mesh
    dynamic_use = auto_cast gl.Resource_usage.dynamic_write,    //Will use BufferSubData for updates
    stream_use  = auto_cast gl.Resource_usage.stream_write,     //Will use persistent mapped buffer and fallback to unsyncronized mapped buffers.
}

@private
//Used internally for setup up a resource for a mesh
add_resource :: proc (mesh : ^Mesh, init_vertex_data : []u8, init_index_data : []u8, loc := #caller_location) {

    desc : gl.Resource_desc = {
        usage = cast(gl.Resource_usage)mesh.usage,
        buffer_type = .array_buffer,
        bytes_count = mesh.vertex_count * reflect.size_of_typeid(mesh.data_type),
    }

    attrib_info := get_attribute_info_from_typeid(mesh.data_type, loc);
    defer delete(attrib_info);

    vao := gl.gen_vertex_array();

    vertex_resouce := gl.make_resource_desc(desc, init_vertex_data, loc);
    gl.associate_buffer_with_vao(vao, vertex_resouce.buffer, attrib_info, loc);

    index_buf : Maybe(gl.Resource);

    switch mesh.indices_type {

        case .no_index_buffer:
            index_buf = nil;

        case .unsigned_short, .unsigned_int:
            s : int;
            if mesh.indices_type == .unsigned_short {
                s = size_of(u16);
            } else if mesh.indices_type == .unsigned_int {
                s = size_of(u32);
            }
            else {
                panic("???");
            }

            index_desc : gl.Resource_desc = {
                usage = cast(gl.Resource_usage)mesh.usage,
                buffer_type = .element_array_buffer,
                bytes_count = mesh.triangle_count * s,
            }
            index_buf = gl.make_resource_desc(index_desc, init_index_data, loc);
    }

    append(&mesh.resources, Mesh_buffers{vao, vertex_resouce, index_buf, {}});
}

Indicies_types :: union {
    []u16,
    []u32,
}

//vertex_data and index_data may be nil if no data is to be uploaded. 
make_mesh :: proc (vertex_data : []$T, index_data : Indicies_types, buffering : Buffering, usage : Usage, loc := #caller_location) -> Mesh {
    mesh : Mesh;

    if usage == .static_use {
        assert(buffering == .single, "It does not make sense to use anything else then single buffering for a static mesh", loc);
    }
    if usage == .stream_use {
        assert(buffering != .single, "It does not make sense to use single buffering for a streaming mesh", loc);
    }

    mesh.vertex_count = len(vertex_data);
    mesh.data_type = T;
    mesh.buffering = buffering;
    mesh.usage = usage;

    mesh_index_buf_data : []u8;
    switch indicies in index_data {
        case []u16:
            assert(indicies != nil, "there is no indicies index_data", loc);
            mesh.indices_type = .unsigned_short;
            mesh.triangle_count = len(indicies);
            mesh_index_buf_data = slice.reinterpret([]u8, indicies);
        case []u32:
            assert(indicies != nil, "there is no indicies index_data", loc);
            mesh.indices_type = .unsigned_int;
            mesh.triangle_count = len(indicies);
            mesh_index_buf_data = slice.reinterpret([]u8, indicies);
        case nil:
            mesh.indices_type = .no_index_buffer;
            mesh.triangle_count = 0;
            mesh_index_buf_data = nil;
    }

    switch mesh.buffering {
        case .single:
            add_resource(&mesh, slice.reinterpret([]u8,vertex_data), mesh_index_buf_data, loc);
        case .double:
            add_resource(&mesh, slice.reinterpret([]u8,vertex_data), mesh_index_buf_data, loc);
            add_resource(&mesh, slice.reinterpret([]u8,vertex_data), mesh_index_buf_data, loc);
        case .trible:
            add_resource(&mesh, slice.reinterpret([]u8,vertex_data), mesh_index_buf_data, loc);
            add_resource(&mesh, slice.reinterpret([]u8,vertex_data), mesh_index_buf_data, loc);
            add_resource(&mesh, slice.reinterpret([]u8,vertex_data), mesh_index_buf_data, loc);
        case .auto:
            //more will be added as the mesh needs it.
            add_resource(&mesh, slice.reinterpret([]u8,vertex_data), mesh_index_buf_data, loc);
    }

    return mesh;
}

destroy_mesh :: proc (mesh : Mesh) {

    for &res in mesh.resources {
        gl.destroy_resource(res.vertex_data);
        gl.discard_fence(&res.fence); //discarding an nil fence is allowed
        if ib, ok := res.indices_buf.?; ok {
            gl.destroy_resource(ib);
        }
        gl.delete_vertex_array(res.vao);
    }

    delete(mesh.resources);
}

//You can upload once per frame
upload_mesh_data :: proc(mesh : ^Mesh, data : []$T, loc := #caller_location) {

    assert(T == mesh.data_type, "The data type you are trying to upload does not match the meshes data type", loc);
    assert(mesh.vertex_count == len(data), "data is not the same length as vertex count (should that be legal?)", loc);

    buffers : Mesh_buffers = mesh.resources[mesh.current_resource];

    when ODIN_DEBUG {
        if mesh.usage == .stream_use && !gl.is_fence_ready(buffers.fence) {
            log.warnf("Preformence warning: upload_mesh_data sync is not ready, increase the amount of buffering\n");
        }
    }

    if mesh.usage == .stream_use {
        gl.sync_fence(&buffers.fence);
    }

    switch mesh.usage {
        case .static_use:
            panic("Cannot upload to a static mesh");
        case .dynamic_use:
            gl.buffer_upload_sub_data(&buffers.vertex_data, 0, slice.reinterpret([]u8, data));
        case .stream_use:
            dst : []u8 = gl.begin_buffer_write(&buffers.vertex_data);
            assert(len(dst) == len(data) * size_of(T), "length of buffer and length of data does not match", loc);
            mem.copy_non_overlapping(raw_data(dst), raw_data(data), len(dst));
            gl.end_buffer_writes(&buffers.vertex_data);
    }

    mesh.current_resource = (mesh.current_resource + 1) %% len(mesh.resources);
}

draw_mesh_single :: proc (mesh : ^Mesh, model_matrix : matrix[4,4]f32, loc := #caller_location) {
    assert(state.bound_shader != nil, "you must first begin the pipeline with begin_pipeline", loc);

    set_uniform(state.bound_shader, .model_mat, model_matrix);
    set_uniform(state.bound_shader, .inv_model_mat, linalg.matrix4_inverse(model_matrix));

    mvp := state.prj_mat * state.view_mat * model_matrix;
    set_uniform(state.bound_shader, .mvp, mvp);
    set_uniform(state.bound_shader, .inv_mvp, linalg.matrix4_inverse(mvp));

    buffers : ^Mesh_buffers = &mesh.resources[mesh.current_resource];
    switch mesh.indices_type {
        case .no_index_buffer:
            gl.draw_arrays(buffers.vao, .triangles, 0, mesh.vertex_count);
        case .unsigned_short, .unsigned_int:
            if i_buf, ok := buffers.indices_buf.?; ok {
                gl.draw_elements(buffers.vao, .triangles, mesh.triangle_count, mesh.indices_type, i_buf.buffer);
            }
            else {
                panic("The mesh does not have a index buffer", loc);
            }
    }

    if mesh.usage == .stream_use {
        gl.discard_fence(&buffers.fence);
        buffers.fence = gl.place_fence();
    }
}

/*
Reserve_behavior :: enum {
    skinny,     //Don't reserve more then needed
    moderate,   //Reserve 1.5x the needed at resize and shrink down when going below 50% use. (including padding)
    thick,      //Reserve 2x needed and don't shrink.
}

Mesh :: struct(A : typeid) where intrinsics.type_is_enum(A) {
    using _ : Mesh_data(A),

    implementation : union {
        Mesh_identifiers(A),    //It is a standalone mesh, drawing happens with draw_mesh_single.
    },

    //If set it will be used for frustum (and maybe occlusion culling).
    bounding_distance : Maybe(f32),
}
*/

//converts a index buffer and an vertex arrsay into a vertex arrray without an index buffer
//Used internally
convert_to_non_indexed :: proc (verts : []$T, indices : Indicies_types) -> (new_verts : []T){

    vert_index : int = 0;

    switch index in indices {
        case []u16:
            new_verts = make([]T, len(index));
            for ind in index {
                new_verts[vert_index] = verts[ind];
                vert_index += 1;
            }
        case []u32:
            new_verts = make([]T, len(index));
            for ind in index {
                new_verts[vert_index] = verts[ind];
                vert_index += 1;
            }
        case:
            panic("??");
    }

    return;
}

@(require_results)
generate_quad :: proc(size : [3]f32, position : [3]f32, use_index_buffer : bool, alloc := context.allocator) -> (verts : []Default_vertex, indices : []u16) {

    context.allocator = alloc;

    if use_index_buffer {
        verts = make([]Default_vertex, 4)
        _indices := make([]u16, 6);

        verts[0] = Default_vertex{[3]f32{0,0,0} * size + position - {0.5,0.5,0}, {0,0}, {0,0,1}};
        verts[2] = Default_vertex{[3]f32{0,1,0} * size + position - {0.5,0.5,0}, {0,1}, {0,0,1}};
        verts[3] = Default_vertex{[3]f32{1,1,0} * size + position - {0.5,0.5,0}, {1,1}, {0,0,1}};
        verts[1] = Default_vertex{[3]f32{1,0,0} * size + position - {0.5,0.5,0}, {1,0}, {0,0,1}};

        _indices[0] = 0;
        _indices[1] = 1;
        _indices[2] = 2;
        _indices[3] = 2;
        _indices[5] = 3;
        _indices[4] = 1;
        indices = _indices;
    }
    else {
        verts = make([]Default_vertex, 6)
        indices = nil;

        verts[0] = Default_vertex{[3]f32{0,0,0} * size + position - {0.5,0.5,0}, {0,0}, {0,0,1}};
        verts[1] = Default_vertex{[3]f32{1,0,0} * size + position - {0.5,0.5,0}, {1,0}, {0,0,1}};
        verts[2] = Default_vertex{[3]f32{0,1,0} * size + position - {0.5,0.5,0}, {0,1}, {0,0,1}};

        verts[3] = Default_vertex{[3]f32{0,1,0} * size + position - {0.5,0.5,0}, {0,1}, {0,0,1}};
        verts[4] = Default_vertex{[3]f32{1,0,0} * size + position - {0.5,0.5,0}, {1,0}, {0,0,1}};
        verts[5] = Default_vertex{[3]f32{1,1,0} * size + position - {0.5,0.5,0}, {1,1}, {0,0,1}};
    }

    return;
}

//returns a static mesh containing a quad.
@(require_results)
make_mesh_quad :: proc(size : [3]f32, position : [3]f32, use_index_buffer : bool) -> (res : Mesh) {

    vert, index := generate_quad(size, position, use_index_buffer);

    if index == nil {
        res = make_mesh(vert, nil, .single, .static_use);
    }
    else {
        res = make_mesh(vert, index, .single, .static_use);
        delete(index);
    }
    delete(vert);

    return;
}

@(require_results)
generate_circle :: proc(diameter : f32, positon : [3]f32, sectors : int, use_index_buffer : bool, loc := #caller_location) -> (verts : []Default_vertex, indices : []u16) {

    vertices := make([dynamic]Default_vertex);
    temp_indices := make([dynamic]u16, 0, 3 * (sectors+1), context.temp_allocator);
    defer delete(vertices);
    defer delete(temp_indices);

    for phi in 0..<sectors {
        //TODO this does not reuse verticies!
        angle : f32 = f32(phi);

        t := f32(angle - 1) / f32(sectors) * 2 * math.PI;
        t2 := f32(angle) / f32(sectors) * 2 * math.PI;
        x := math.cos(t);
        y := math.sin(t);
        x2 := math.cos(t2);
        y2 := math.sin(t2);

        vert    := [3]f32{x, y, 0} * 2;
        vert2   := [3]f32{x2, y2, 0} * 2;

        //the center only added once
        if len(vertices) == 0 {
            append(&vertices,   Default_vertex{[3]f32{0,0,0} *  diameter / 4 + positon, [2]f32{0,0} + 0.5,  [3]f32{0,0,1}});
        }

        if len(vertices) == 1 {
            append(&vertices,   Default_vertex{vert * diameter / 4 + positon,           vert.xy/4 + 0.5,    [3]f32{0,0,1}});
        }

        append(&vertices,       Default_vertex{vert2 * diameter / 4 + positon,          vert2.xy/4 + 0.5,   [3]f32{0,0,1}});

        append(&temp_indices, 0);
        append(&temp_indices, auto_cast (len(vertices) - 2));
        append(&temp_indices, auto_cast (len(vertices) - 1));
    }

    if use_index_buffer {
        verts = make([]Default_vertex, len(vertices));
        indices = make([]u16, len(temp_indices));

        for v, i in vertices {
            verts[i] = v;   //convert from 2D to 3D
        }
        for ii, i in temp_indices {
            indices[i] = ii;
        }
    }
    else {
        non_indexed := convert_to_non_indexed(vertices[:], temp_indices[:]);
        verts = non_indexed;
    }

    return;
}

//returns a static mesh containing a circle.
@(require_results)
make_mesh_circle :: proc(diameter : f32, position : [3]f32, sectors : int, use_index_buffer : bool) -> (res : Mesh) {

    vert, index := generate_circle(diameter, position, sectors, use_index_buffer);

    if index == nil {
        res = make_mesh(vert, nil, .single, .static_use);
    }
    else {
        res = make_mesh(vert, index, .single, .static_use);
        delete(index);
    }
    delete(vert);

    return;
}

//
@(require_results)
generate_cube :: proc(size : [3]f32, position : [3]f32, use_index_buffer : bool, loc := #caller_location) -> (verts : []Default_vertex, indices : []u16) {

    corners : [24]Default_vertex = {
        //XP
        Default_vertex{{1,0,0}, {0,0}, {1,0,0}},    
        Default_vertex{{1,1,0}, {1,0}, {1,0,0}},
        Default_vertex{{1,1,1}, {1,1}, {1,0,0}},
        Default_vertex{{1,0,1}, {0,1}, {1,0,0}},

        //XN
        Default_vertex{{0,0,0}, {0,0}, {-1,0,0}},
        Default_vertex{{0,0,1}, {0,1}, {-1,0,0}},
        Default_vertex{{0,1,1}, {1,1}, {-1,0,0}},
        Default_vertex{{0,1,0}, {1,0}, {-1,0,0}},

        //YP
        Default_vertex{{0,1,0}, {0,0}, {0,1,0}},
        Default_vertex{{0,1,1}, {0,1}, {0,1,0}},
        Default_vertex{{1,1,1}, {1,1}, {0,1,0}},
        Default_vertex{{1,1,0}, {1,0}, {0,1,0}},

        //YN
        Default_vertex{{0,0,0}, {0,0}, {0,-1,0}},
        Default_vertex{{1,0,0}, {1,0}, {0,-1,0}},
        Default_vertex{{1,0,1}, {1,1}, {0,-1,0}},
        Default_vertex{{0,0,1}, {0,1}, {0,-1,0}},

        //ZP
        Default_vertex{{0,0,1}, {0,0}, {0,0,1}},
        Default_vertex{{1,0,1}, {1,0}, {0,0,1}},
        Default_vertex{{1,1,1}, {1,1}, {0,0,1}},
        Default_vertex{{0,1,1}, {0,1}, {0,0,1}},

        //ZN
        Default_vertex{{0,0,0}, {0,0}, {0,0,-1}},
        Default_vertex{{0,1,0}, {0,1}, {0,0,-1}},
        Default_vertex{{1,1,0}, {1,1}, {0,0,-1}},
        Default_vertex{{1,0,0}, {1,0}, {0,0,-1}},
    };

    odering : [6]u16 = {
        0, 1, 2,
        0, 2, 3,
    }

    indices = make([]u16, 36);

    index : int = 0;
    for i in 0..<6 {
        for o in odering {
            indices[index] = o + 4 * cast(u16)i;
            index += 1;
        }
    }

    verts = make([]Default_vertex, 24);
    for c,i in corners {
        verts[i] = Default_vertex{(c.position - {0.5,0.5,0.5} + position) * size, c.texcoord, c.normal};
    }

    if !use_index_buffer {
        new_verts := convert_to_non_indexed(verts, indices);
        delete(verts);
        delete(indices);
        verts = new_verts;
        indices = nil;
    }

    return;
}

//returns a static mesh containing a circle.
@(require_results)
make_mesh_cube :: proc(size : [3]f32, position : [3]f32, use_index_buffer : bool) -> (res : Mesh) {

    vert, index := generate_cube(size, position, use_index_buffer);

    if index == nil {
        res = make_mesh(vert, nil, .single, .static_use);
    }
    else {
        res = make_mesh(vert, index, .single, .static_use);
        delete(index);
    }
    delete(vert);

    return;
}

@(require_results)
generate_cylinder :: proc(offset : [3]f32, transform : matrix[4, 4]f32, stacks : int, sectors : int, use_index_buffer : bool, loc := #caller_location) -> (verts : []Default_vertex, indices : []u16) {

    vertices := make([dynamic]Default_vertex);
    temp_indices := make([dynamic]u16, 0, 3 * (sectors+1), context.temp_allocator);
    defer delete(vertices);
    defer delete(temp_indices);

    for up in 0..=stacks {

        y : f32 = f32(up) / f32(stacks);

        for phi in 0..<sectors {

            angle : f32 = f32(phi);

            x := math.cos_f32(f32(angle) / f32(sectors-1) * 2 * math.PI);
            z := math.sin_f32(f32(angle) / f32(sectors-1) * 2 * math.PI);

            vert := [4]f32{x / 2 + offset.x, y + offset.y - 0.5, z / 2 + offset.z, 0};

            append(&vertices, Default_vertex{ linalg.mul(transform, vert).xyz, [2]f32{f32(phi) / f32(sectors-1), f32(up) / f32(stacks)}, [3]f32{x,0,z}});

            if up != 0 {
                below_neg   := up * sectors + ((phi - 1) %% sectors) - sectors;
                below_i     := up * sectors + phi - sectors;
                this        := up * sectors + phi;
                pos         := up * sectors + ((phi + 1) %% sectors);
                append(&temp_indices, u16(below_i), u16(below_neg), u16(this)); 
                append(&temp_indices, u16(below_i), u16(this), u16(pos)); 
            }

        }
    }

    if use_index_buffer {
        verts = make([]Default_vertex, len(vertices)); 
        indices = make([]u16, len(temp_indices));

        for v, i in verts {
            verts[i] = v;
        }
        for ii, i in temp_indices {
            indices[i] = ii;
        }
    }
    else {
        verts = convert_to_non_indexed(vertices[:], temp_indices[:]);
        indices = nil;
    }

    return;
}

//returns a static mesh containing a circle.
@(require_results)
make_mesh_cylinder :: proc(offset : [3]f32, transform : matrix[4, 4]f32, stacks : int, sectors : int, use_index_buffer : bool) -> (res : Mesh) {

    vert, index := generate_cube(offset, transform, stacks, sectors, use_index_buffer);

    if index == nil {
        res = make_mesh(vert, nil, .single, .static_use);
    }
    else {
        res = make_mesh(vert, index, .single, .static_use);
        delete(index);
    }
    delete(vert);

    return;
}

/*
//This will not upload it
generate_cylinder :: proc(offset : [3]f32, transform : matrix[4, 4]f32, stacks : int, sectors : int, use_index_buffer : bool, loc := #caller_location) -> (cylinder : Mesh) {

    vertices := make([dynamic][3]f32, 0, 4 * stacks * (sectors+1), context.temp_allocator);
    texcoords := make([dynamic][2]f32, 0, 4 * stacks * (sectors+1), context.temp_allocator);
    normals := make([dynamic][3]f32, 0, 4 * stacks * (sectors+1), context.temp_allocator);
    indices := make([dynamic]u16, 0, 6 * stacks * (sectors+1), context.temp_allocator);

    for up in 0..=stacks {

        y : f32 = f32(up) / f32(stacks);

        for phi in 0..<sectors {

            angle : f32 = f32(phi);

            x := math.cos_f32(f32(angle) / f32(sectors-1) * 2 * math.PI);
            z := math.sin_f32(f32(angle) / f32(sectors-1) * 2 * math.PI);

            vert := [4]f32{x / 2 + offset.x, y + offset.y - 0.5, z / 2 + offset.z, 0};
            append(&vertices, linalg.mul(transform, vert).xyz);
            append(&texcoords, [2]f32{f32(phi) / f32(sectors-1), f32(up) / f32(stacks)});
            append(&normals, [3]f32{x,0,z});

            if up != 0 {
                below_neg   := up * sectors + ((phi - 1) %% sectors) - sectors;
                below_i     := up * sectors + phi - sectors;
                this        := up * sectors + phi;
                pos         := up * sectors + ((phi + 1) %% sectors);
                append(&indices, u16(below_i), u16(below_neg), u16(this)); 
                append(&indices, u16(below_i), u16(this), u16(pos)); 
            }

        }
    }

    //assert(indices[6 * stacks * sectors - 1] != 0)

    if use_index_buffer {

        cylinder.vertex_count = auto_cast len(vertices);
        cylinder.vertices = make([][3]f32,  cylinder.vertex_count);
        cylinder.texcoords = make([][2]f32, cylinder.vertex_count);
        cylinder.normals = make([][3]f32,   cylinder.vertex_count);
        cylinder_indices := make([]u16, len(indices));

        copy_slice(cylinder.vertices[:], vertices[:]);
        copy_slice(cylinder.texcoords[:], texcoords[:]);
        copy_slice(cylinder.normals[:], normals[:]);

        copy_slice(cylinder_indices[:], indices[:]);
        cylinder.indices = cylinder_indices;
    }
    else {

        cylinder.vertex_count = auto_cast len(indices);
        cylinder.vertices = make([][3]f32,  cylinder.vertex_count);
        cylinder.texcoords = make([][2]f32, cylinder.vertex_count);
        cylinder.normals = make([][3]f32,   cylinder.vertex_count);

        for v, i in indices {
            cylinder.vertices[i] = vertices[v];
            cylinder.texcoords[i] = texcoords[v]; 
            cylinder.normals[i] = normals[v];
        }
    }

    calculate_tangents(&cylinder);

    return;
}

//This will not upload it
generate_sphere :: proc(offset : [3]f32 = {0,0,0}, transform : matrix[4, 4]f32 = linalg.MATRIX4F32_IDENTITY, stacks : int = 10, sectors : int = 20, use_index_buffer := true, loc := #caller_location) -> (sphere : Mesh) {

    vertices := make([dynamic][3]f32, 0, 4 * stacks * (sectors+1), context.temp_allocator);
    texcoords := make([dynamic][2]f32, 0, 4 * stacks * (sectors+1), context.temp_allocator);
    normals := make([dynamic][3]f32, 0, 4 * stacks * (sectors+1), context.temp_allocator);
    indices := make([dynamic]u16, 0, 6 * stacks * (sectors+1), context.temp_allocator);

    stacks := stacks + 1;

    for up in 0..=stacks {

        theta := f32(up) / f32(stacks) * math.PI - math.PI / 2;
        y : f32 = math.sin(theta);

        for phi in 0..<sectors {

            angle : f32 = f32(phi);

            t := f32(angle) / f32(sectors-1) * 2 * math.PI;
            x := math.cos(t) * math.cos(theta);
            z := math.sin(t) * math.cos(theta);

            vert := [4]f32{x / 2 + offset.x, y / 2 + offset.y, z / 2 + offset.z, 0};
            append(&vertices, linalg.mul(transform, vert).xyz);
            append(&texcoords, [2]f32{f32(phi) / f32(sectors-1), f32(up) / f32(stacks)});
            append(&normals, [3]f32{x,0,z});

            if up != 0 {
                below_neg   := up * sectors + ((phi - 1) %% sectors) - sectors;
                below_i     := up * sectors + phi - sectors;
                this        := up * sectors + phi;
                pos         := up * sectors + ((phi + 1) %% sectors);
                append(&indices, u16(below_i), u16(below_neg), u16(this)); 
                append(&indices, u16(below_i), u16(this), u16(pos)); 
            }

        }
    }

    //assert(indices[6 * stacks * sectors - 1] != 0)

    if use_index_buffer {

        sphere.vertex_count = auto_cast len(vertices);
        sphere.vertices = make([][3]f32,    sphere.vertex_count);
        sphere.texcoords = make([][2]f32, sphere.vertex_count);
        sphere.normals = make([][3]f32,     sphere.vertex_count);
        sphere_indices := make([]u16, len(indices));

        copy_slice(sphere.vertices[:], vertices[:]);
        copy_slice(sphere.texcoords[:], texcoords[:]);
        copy_slice(sphere.normals[:], normals[:]);

        copy_slice(sphere_indices[:], indices[:]);
        sphere.indices = sphere_indices;
    }
    else {

        sphere.vertex_count = auto_cast len(indices);
        sphere.vertices = make([][3]f32,    sphere.vertex_count);
        sphere.texcoords = make([][2]f32, sphere.vertex_count);
        sphere.normals = make([][3]f32,     sphere.vertex_count);

        for v, i in indices {
            sphere.vertices[i] = vertices[v];
            sphere.texcoords[i] = texcoords[v]; 
            sphere.normals[i] = normals[v];
        }
    }

    calculate_tangents(&sphere);

    return;
}
*/
DanielGavin commented 4 months ago

Should not crash anymore.

xzores commented 4 months ago

The nightly update seems to have fixed, ty