1 2 3 4  | struct game_memory {
    float player_x;
    float player_y;
}
 | 
1 2 3 4  | struct transient_memory {
    vertex vertices[1000];
    int vertices_count;
}
 | 
1 2 3 4  | struct entity_chunk {
    entity entities[1000];
    entity_chunk* next;
}
 | 
sneiderlein
2. We pass a pointer to the block to the game loop, and the game loop casts the block to the layout/struct it expects: that way it can divide the memory into useful chunks as defined by the struct.
1 2 3 4 5 6 7  | |-----------------------------------| <- Memory we get from the win32 layer. |game_state|other things------------| <- we want to treat it like this. game_state* state = (game_state*) memory; // memory is void*. This is not the actual code from handmade hero. // Those next two lines are the values you would use to create a memory arena for the rest of the memory. void* rest_of_the_memory = memory + sizeof( game_state ); u64 rest_of_the_memory_size = memory_size - sizeof( game_state );  | 
1 2 3 4 5 6 7 8  | |game_state|------------------------| push(...) |game_state|x|----------------------| push(...) |game_state|x|x|--------------------| BeginTemporary(...) |game_state|x|x|--------------------| push(...) |game_state|x|x|y|------------------| push(...) |game_state|x|x|y|y|----------------| EndTemporary(...) |game_state|x|x|--------------------| push(...) |game_state|x|x|x|------------------|  | 
1 2 3 4 5  | |game_state|x|x|--------------------| createSubArena(...) |game_state|x|x|------|-------------| push(sub, ...) |game_state|x|x|y|----|-------------| push(sub, ...) |game_state|x|x|y|y|--|-------------| push(main, ...) |game_state|x|x|y|y|--|x|-----------|  | 
1  | p_to_the_rest = pointer_to_the_beginning + sizeof(game_state);  | 
1 2 3 4 5 6 7 8 9 10 11 12 13 14  | static void* allocate(int size, void* start){
    
    // check that it doesn't overflow
    assert((game_state->last_pointer + size) <= game_state->memory_size);
    // I would dereference the pointer to write to it, right?
    *game_state->last_pointer = *start;
    // update the position of the last_pointer
    game_state->last_pointer += size;
    
    // return pointer to the newly allocated data
    return game_state->last_pointer - size;
}
 | 
1 2 3 4 5 6 7 8  | static void push_vertex(Vertex vertex){
    vertices[last_vertex_index++] = vertex;
}
static void render(){
   glBufferData(...push all the vertices to GPU...);
   //            mode       first      count
   glDrawArrays(GL_TRIANGLES, 0, last_vertex_index);
}
 | 
sneiderlein
5. Or maybe a better Idea would be to do it modern opengl way (how I understand it), where several primitive shapes are created and stored on GPU on initialization, and we could bind a correct VAO and send a transform matrix as a uniform before each draw to change shapes size, rotation and position. Could someone please give an example for this? I'm a little lost on the specifics:
a. Do you need to use some projection matrix like orthographic?
b. Do you need to manage the Z positions of vertices? Or you could somehow rely on drawing order and discard the Depth Buffer completely?
c. Maybe a math library recommendation? GLM is the most mentioned, but I would appreciate some generic free, and more c-style API. So far I found gb_math, and there is even a library called HandmadeMath.
I'm having trouble including these libraries though, I get a lot of undefined identifier errors.
Appreciate your help!
1 2 3 4 5  | foreach(object in draw_queue){
glBindVertexArray(object.vao);
glUniformMatrix4fv(modelMatrix, 1, false, &object.modelMatrix);
glDrawArrays(GL_TRIANGLES, 0, object .last_vertex_index);
}
 | 
ratchetfreak
A: you don't need a perspective matrix. The vertex shader's output is expected to be in clip space where the geometry to be within the boundaries defined by -w < x, y, z < w. The convention is to use the model matrix to put the vertex data int a world space and then use the view-perspective matrix to transform that into clipspace.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68  | static void* allocate(int size, void* start){
    
    // Here you compare a pointer and a size.
    // You need to either compare 2 pointers or 2 size.
    // - replace game_state->memory_size with game_state->last_memory_address
    // - or replace game_state->last_pointer with game_state->used_memory;
    assert((game_state->last_pointer + size) <= game_state->memory_size);
    // You don't want to de-reference pointers here.
    // If you de-reference them you modify the content (what the address is pointing to).
    // Here we want to modify or store the address of the content.
    *game_state->last_pointer = *start;
    // You didn't de-reference here which is good.
    game_state->last_pointer += size;
    
    // return pointer to the newly allocated data
    return game_state->last_pointer - size;
}
// Here is your function "fixed"
typedef struct GameState {
    ...
    void* last_pointer;
    void* last_memory_address;
    ...
} GameState;
...
game_state->last_pointer = memory + sizeof( GameState );
game_state->last_memory_address = game_state->last_pointer + ( memory_size - sizeof( GameState ) );
...
void* allocate( int size ) {
    void* result;
    assert( game_state->last_pointer + size <= game_state->last_memory_address );
    result = game_state->last_pointer;
    game_state->last_pointer += size;
    return result;
}
// But this seems less intuitive to me than what Casey is doing in handmade hero.
// Memory arena.
typedef struct Data {
    void* base; // The first address of "user" memory. It never changes.
    size_t reserved; // The amount of "user" memory. It never changes.
    size_t used; // The amount of "user" memory used.
} Data;
...
data->base = memory + sizeof( GameState );
data->reserved = memory_size - sizeof( GameState );
data->used = 0;
...
void* allocate( Data* memory, size_t size ) {
    void* result = 0;
    assert( memory->used + size <= memory->reserved );
    if ( memory->used + size <= memory->reserved ) {
        result = memory->base + memory->used;
        memory->used += size;
    }
    return result;
}
 | 
1 2  | #define HANDMADE_MATH_IMPLEMENTATION #include "HandmadeMath.h"  | 
mrmixer
For example, in your renderer: how many vertex do you think you will have at a maximum ? 100 ? 1000 ? 100000 ?
Don't be afraid to allocate too much during development, on modern computer you virtually have infinite memory.The memory is totally finite.