
I’m still coding my way back to where I was before I decided to switch to C instead of C++. I updated the documentation with the new libs (I have to write hundreds of comments though…sigh…).
Graphics
The graphics library is a wrapper for OpenGL. A lot of functions are not doing much more than OpenGL does, but here a a few features that are really helpful:
- minimize OpenGL calls by saving active ids for buffers, textures, states, blending functions, etc. into a general state
- push / pop state
- GfxAttributeFormat struct to help with attributes enabling in vertex arrays
- helper to link shader attributes (parsing shader, specify attributes locations, automatic binding, …)
- helper to create different types of framebuffers (like for render to texture)
I still have a lot of C++ code to convert, like a direct 2D API, but one of the thing I like the most is a shader generator (doing things from simple texturing to Phong lighting).
I have been following LearnOpenGL for a while, and it helped me a lot building my C++ code. Now my objective is to go through each tutorial and make a sample out of it, using my own tools.
The four images above are actually the first few tutorials.
I probably won’t try PBR but I’m determined to get as far as the deferred renderer.
That will give me solid tools for rendering cool stuff later on.
In parallel I think of starting to implement a GUI, I had one before in C++ but I ended up hating it, as it was persistent and events-based. I’m really interested in the immediate mode GUI paradigm so I’ll venture that way.
Input
For the input library, I decided to beef up the previous C++ code to now support multiple devices. I used RAWINPUT and managed to get it working pretty quickly, but now I’m dreading the day I have to implement this part on Linux or Android. It’s still a work in progress but I have a a few features:
- support up to 4 mouse/keyboard (and soon gamepads too?)
- abstraction of input devices, events and virtual keys to avoid dealing with platform specific code
- read current input state for each mouse / keyboard (+active keyboard layout, active keyboard locks)
- subscribe to input event callbacks
- detect if devices are added / removed
Code Example
Below is an example of code for the triangle test:
/*
* basic_triangle.c
* Another Memory Ends - <amedevcentral@gmail.com>
*/
#include "graphics.h"
const size_t gc_core_memory_size = 0;
bool quit = false;
LRESULT CALLBACK WndProc(HWND hwnd, uint message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_QUIT)
quit = true;
if (message == WM_CLOSE)
quit = true;
return DefWindowProc(hwnd, message, wParam, lParam);
}
typedef struct {
vec2 pos;
vec4 color;
} Vertex;
int main(int argc, char** argv)
{
c_core_init(C_OUTPUT_FULL, 0);
(void)argc;
(void)argv;
Window window;
gfx_initialize();
c_window_initialize(&window, "basic triangle", 320, 240, c_window_style_default(), WndProc);
gfx_win32_set_pixel_format(window.hDC, 24, 16, 8);
gfx_id context = gfx_context_create_win32(window.hDC);
gfx_context_set(context);
ColorVec4 clear_color = i_color_to_vec4(&gc_color_transparent);
gfx_clear_color_set(&clear_color);
bstr vertex_shader = bstr_init(
"#version 330 core\n"
"in vec2 pos;\n"
"in vec4 color;\n"
"out vec4 frag_color;\n"
"void main()\n"
"{\n"
" frag_color = color;\n"
" gl_Position = vec4(pos, 0, 1);\n"
"}\n");
bstr fragment_shader = bstr_init(
"#version 330 core\n"
"out vec4 color;\n"
"in vec4 frag_color;\n"
"void main()\n"
"{\n"
" color = frag_color;\n"
"}\n");
GfxShaderLink link;
link.link_type = GFX_SHADER_LINK_DEFAULT_BINDING;
gfx_id shader = gfx_shader_program_create(&vertex_shader, &fragment_shader, &link);
GfxAttributeFormat format = gfx_attribute_format_init();
gfx_attribute_format_add(&format, "pos", GFX_ATTRIBUTE_VEC2);
gfx_attribute_format_add(&format, "color", GFX_ATTRIBUTE_VEC4);
gfx_id vertex_array = gfx_vertex_array_create();
gfx_id vertex_buffer = gfx_vertex_buffer_create();
gfx_vertex_array_bind(vertex_array);
gfx_vertex_buffer_bind(vertex_buffer);
gfx_attributes_enable_interleaved(&format);
Vertex vertex[3];
vertex[0].pos.x = -0.5f;
vertex[0].pos.y = -0.5f;
vertex[0].color = i_color_to_vec4(&gc_color_red);
vertex[1].pos.x = 0.0f;
vertex[1].pos.y = 0.5f;
vertex[1].color = i_color_to_vec4(&gc_color_green);
vertex[2].pos.x = 0.5f;
vertex[2].pos.y = -0.5f;
vertex[2].color = i_color_to_vec4(&gc_color_blue);
gfx_vertex_buffer_copy_data((const uint8*)&vertex, sizeof(Vertex) * 3, GFX_BUFFER_STATIC);
gfx_vertex_array_bind(0);
c_window_show(&window);
while (quit == false)
{
c_window_process_messages(&window);
gfx_framebuffer_bind(0);
gfx_viewport_set_values(0, 0, 320, 240);
gfx_clear(true, false, false);
gfx_shader_program_use(shader);
gfx_vertex_array_bind(vertex_array);
gfx_draw_vertices(GFX_VERTEX_TRIANGLE, 3);
c_window_swap_buffers(&window);
}
gfx_shader_program_delete(shader);
gfx_vertex_array_delete(vertex_array);
gfx_vertex_buffer_delete(vertex_buffer);
gfx_context_release();
gfx_context_delete(context);
c_window_terminate(&window);
gfx_terminate();
c_core_terminate();
c_pause_program();
return 0;
}