Post

Dicas Rápidas no C++

Conceitos de C/C++

  1. Se não vamos modificar uma struct ou se ela não for muito grande podemos passar por valor ao invés de referência.
  2. Se há variáveis globais que fazem parte do mesmo contexto, podem ser usadas em uma struct. Isso também ajuda a flexibilizar o programa podendo passar outras structs.
  3. Funções pequenas e que processam poucas coisas podem ser funções inline.
  4. A stack começa com um número maior e vai diminuindo conforma alocamos mais dados nela. Isso significa que o primeiro pointeiro após a função main irá te mostrar o tamanho disponível na stack naquela momento.
  5. const não é útil porque const não é constante de verdade devido a casos de aliasing e ponteiros. Outro ponto é que não há otimização por parte do compilador quando se usa const. Logo, só é uma digitação a mais para o programador.
1
2
3
4
5
// item 4.
void main() { 
    // aqui tem o endereço do maior valor da stack (e o disponivel)
    My_Struct struct = {};
}

O parâmetro -F<num> do compilador permite definir o tamanho da stack. Podemos testar o tamanho dela criando um array e inicializando ele com zero.

Criando uma struct que represente o BackBuffer

1
2
3
4
5
6
7
8
9
struct Back_Buffer {
    BITMAPINFO info;
    void *memory;
    int width;
    int height;
    int pitch;
}

static Back_Buffer g_back_buffer;

Refatorando o Gradiente

Vamos refatorar o gradiente usado no artigo anterior.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
internal void 
render_gradient(Back_Buffer buffer, int x_offset, int y_offset) 
{
    uint8 *row = (uint8 *) buffer.memory; 
    for(int y = 0; y < buffer.height; y++) {

        uint32 *pixel = (uint32 *) row;
        for (int x = 0; x < buffer.width; x++) {
            uint8 b = (x + x_offset);
            uint8 g = (y + y_offset);
            *pixel = ((g << 8) | b);
            *pixel++;
        }
        row += buffer.pitch;
    }
    
}

Refatorando o Redimensionamento da Janela

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
internal void 
resize_window(Back_Buffer *buffer, int width, int height) 
{
    if (buffer->memory) {
        VirtualFree(&buffer->memory, 0, MEM_RELEASE);
    }

    buffer->width  = width;
    buffer->height = height;
    int bytes_per_pixel = 4;

    buffer->info.bmiHeader.biSize = sizeof(buffer->info.bmiHeader);
    buffer->info.bmiHeader.biWidth = buffer->width;
    buffer->info.bmiHeader.biHeight = -buffer->height; 
    buffer->info.bmiHeader.biPlanes = 1; 
    buffer->info.bmiHeader.biBitCount = 32;
    buffer->info.bmiHeader.biCompression = BI_RGB;

    int bitmap_memory_size = buffer->width * buffer->height * bytes_per_pixel;
    buffer->memory = VirtualAlloc(0,
                                  bitmap_memory_size,
                                  MEM_COMMIT,
                                  PAGE_READWRITE);

    buffer->pitch = buffer->width * bytes_per_pixel;
}

Refatorando a Atualização da Janela

1
2
3
4
5
6
7
8
9
10
11
internal void 
update_window(HDC context, Back_Buffer buffer, int x, int y, int window_width, int window_height) 
{
    StretchDIBits(context,
                  0, 0, window_width, window_height,
                  0, 0, buffer.width, buffer.height,
                  buffer.memory,
                  &buffer.info,
                  DIB_RGB_COLORS,
                  SRCCOPY);
}

Reduzindo DRY (Don’t Repeat Yourself)

Há vários trechos de código onde usamos GetClientRect. Vamos reduzir com uma função que retorna o tamanho da janela. Essa função é uma boa candidata a ser inline.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct Window_Size {
    int width;
    int height;
}


internal inline
Window_Size get_window_size(HWND window) {
    Window_Size window_size;

    RECT client_rect;
    GetClientRect(window, &client_rect);
    window_size.width  = client_rect.right  - client_rect.left;
    window_size.height = client_rect.bottom - client_rect.top;

    return window_size;
}

Agora, trocamos as chamadas de GetClientRect para nossa nova função.

Adicionando Stretch para redimensionamento

Sempre que mudamos o tamanho da janela, o WM_SIZE cria um novo backbuffer com uma nova proporção. Isso faz com que na hora do update, a janela não se redimensiona. Vamos comentar a linha do resize dentro do WM_SIZE usar uma única vez na função main.

Para redimensionar, vamos definir uma única vez a chamada do resize_window com uma tamanho pré-definido para que quando houver um resize, a função de update faça o stretch do nosso backbuffer de acordo com a janela desejada.

1
2
3
4
5
// create window

resize_window(Back_Buffer *buffer, int width, int height) 

// ... main loop
Esta postagem está licenciada sob CC BY 4.0 pelo autor.