Rework Gfx_Image stuff
This commit is contained in:
parent
ebaa52c326
commit
83c0371dcb
6 changed files with 182 additions and 98 deletions
|
@ -83,9 +83,6 @@ typedef struct Draw_Frame {
|
||||||
|
|
||||||
Matrix4 projection;
|
Matrix4 projection;
|
||||||
Matrix4 view;
|
Matrix4 view;
|
||||||
|
|
||||||
Gfx_Handle garbage_stack[4096];
|
|
||||||
u64 garbage_stack_count;
|
|
||||||
} Draw_Frame;
|
} Draw_Frame;
|
||||||
// This frame is passed to the platform layer and rendered in os_update.
|
// This frame is passed to the platform layer and rendered in os_update.
|
||||||
// Resets every frame.
|
// Resets every frame.
|
||||||
|
@ -196,40 +193,3 @@ Draw_Quad *draw_image_xform(Gfx_Image *image, Matrix4 xform, Vector2 size, Vecto
|
||||||
#define COLOR_WHITE ((Vector4){1.0, 1.0, 1.0, 1.0})
|
#define COLOR_WHITE ((Vector4){1.0, 1.0, 1.0, 1.0})
|
||||||
#define COLOR_BLACK ((Vector4){0.0, 0.0, 0.0, 1.0})
|
#define COLOR_BLACK ((Vector4){0.0, 0.0, 0.0, 1.0})
|
||||||
|
|
||||||
Gfx_Image *load_image_from_disk(string path, Allocator allocator) {
|
|
||||||
string png;
|
|
||||||
bool ok = os_read_entire_file(path, &png, allocator);
|
|
||||||
if (!ok) return 0;
|
|
||||||
|
|
||||||
Gfx_Image *image = alloc(allocator, sizeof(Gfx_Image));
|
|
||||||
|
|
||||||
// Use stb_image to load and decode the PNG
|
|
||||||
int width, height, channels;
|
|
||||||
stbi_set_flip_vertically_on_load(1); // stb_image can flip the image on load
|
|
||||||
unsigned char* stb_data = stbi_load_from_memory(png.data, png.count, &width, &height, &channels, STBI_rgb_alpha);
|
|
||||||
|
|
||||||
if (!stb_data) {
|
|
||||||
dealloc(allocator, image);
|
|
||||||
dealloc_string(allocator, png);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
image->data = stb_data;
|
|
||||||
image->width = width;
|
|
||||||
image->height = height;
|
|
||||||
image->gfx_handle = GFX_INVALID_HANDLE; // This is handled in gfx
|
|
||||||
image->allocator = allocator;
|
|
||||||
|
|
||||||
dealloc_string(allocator, png);
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete_image(Gfx_Image *image) {
|
|
||||||
stbi_image_free(image->data); // Free the image data allocated by stb_image
|
|
||||||
image->width = 0;
|
|
||||||
image->height = 0;
|
|
||||||
draw_frame.garbage_stack[draw_frame.garbage_stack_count] = image->gfx_handle;
|
|
||||||
draw_frame.garbage_stack_count += 1;
|
|
||||||
dealloc(image->allocator, image);
|
|
||||||
}
|
|
|
@ -15,6 +15,14 @@ int entry(int argc, char **argv) {
|
||||||
Gfx_Image *hammer_image = load_image_from_disk(STR("oogabooga/examples/hammer.png"), get_heap_allocator());
|
Gfx_Image *hammer_image = load_image_from_disk(STR("oogabooga/examples/hammer.png"), get_heap_allocator());
|
||||||
assert(hammer_image, "Failed loading hammer.png");
|
assert(hammer_image, "Failed loading hammer.png");
|
||||||
|
|
||||||
|
void *my_data = alloc(get_heap_allocator(), 32*32*4);
|
||||||
|
memset(my_data, 0xffffffff, 32*32*4);
|
||||||
|
Gfx_Image *my_image = make_image(32, 32, 4, my_data, get_heap_allocator());
|
||||||
|
for (int *c = (int*)my_data; c < (int*)my_data+16*16; c += 1) {
|
||||||
|
*c = 0xff0000ff;
|
||||||
|
}
|
||||||
|
gfx_set_image_data(my_image, 0, 0, 16, 16, my_data);
|
||||||
|
|
||||||
seed_for_random = os_get_current_cycle_count();
|
seed_for_random = os_get_current_cycle_count();
|
||||||
|
|
||||||
const float64 fps_limit = 69000;
|
const float64 fps_limit = 69000;
|
||||||
|
@ -94,7 +102,7 @@ int entry(int argc, char **argv) {
|
||||||
Matrix4 hammer_xform = m4_scalar(1.0);
|
Matrix4 hammer_xform = m4_scalar(1.0);
|
||||||
hammer_xform = m4_rotate_z(hammer_xform, (f32)now);
|
hammer_xform = m4_rotate_z(hammer_xform, (f32)now);
|
||||||
hammer_xform = m4_translate(hammer_xform, v3(-.25f, -.25f, 0));
|
hammer_xform = m4_translate(hammer_xform, v3(-.25f, -.25f, 0));
|
||||||
draw_image_xform(hammer_image, hammer_xform, v2(.5f, .5f), COLOR_RED);
|
draw_image_xform(my_image, hammer_xform, v2(.5f, .5f), COLOR_RED);
|
||||||
|
|
||||||
Vector2 hover_position = v2_rotate_point_around_pivot(v2(-.5, -.5), v2(0, 0), (f32)now);
|
Vector2 hover_position = v2_rotate_point_around_pivot(v2(-.5, -.5), v2(0, 0), (f32)now);
|
||||||
Vector2 local_pivot = v2(.125f, .125f);
|
Vector2 local_pivot = v2(.125f, .125f);
|
||||||
|
|
|
@ -22,8 +22,8 @@ typedef struct alignat(16) D3D11_Vertex {
|
||||||
|
|
||||||
ID3D11Debug *d3d11_debug = 0;
|
ID3D11Debug *d3d11_debug = 0;
|
||||||
|
|
||||||
ID3D11Device* d3d11_device = 0;
|
ID3D11Device *d3d11_device = 0;
|
||||||
ID3D11DeviceContext* d3d11_context = 0;
|
ID3D11DeviceContext *d3d11_context = 0;
|
||||||
ID3D11RenderTargetView *d3d11_window_render_target_view = 0;
|
ID3D11RenderTargetView *d3d11_window_render_target_view = 0;
|
||||||
ID3D11Texture2D *d3d11_back_buffer = 0;
|
ID3D11Texture2D *d3d11_back_buffer = 0;
|
||||||
D3D_DRIVER_TYPE d3d11_driver_type = 0;
|
D3D_DRIVER_TYPE d3d11_driver_type = 0;
|
||||||
|
@ -518,23 +518,6 @@ void gfx_update() {
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
tm_scope_cycles("Frame setup") {
|
tm_scope_cycles("Frame setup") {
|
||||||
///
|
|
||||||
// purge garbage
|
|
||||||
for (u64 i = 0; i < draw_frame.garbage_stack_count; i++) {
|
|
||||||
ID3D11ShaderResourceView *view = draw_frame.garbage_stack[i];
|
|
||||||
ID3D11Resource *resource = 0;
|
|
||||||
VTABLE(GetResource, view, &resource);
|
|
||||||
|
|
||||||
ID3D11Texture2D *texture = 0;
|
|
||||||
hr = VTABLE(QueryInterface, resource, &IID_ID3D11Texture2D, (void**)&texture);
|
|
||||||
if (SUCCEEDED(hr)) {
|
|
||||||
D3D11Release(view);
|
|
||||||
D3D11Release(texture);
|
|
||||||
log("Destroyed an image");
|
|
||||||
} else {
|
|
||||||
panic("Unhandled D3D11 resource deletion");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
// Maybe resize swap chain
|
// Maybe resize swap chain
|
||||||
|
@ -595,33 +578,6 @@ void gfx_update() {
|
||||||
int texture_index = -1;
|
int texture_index = -1;
|
||||||
|
|
||||||
if (q->image) {
|
if (q->image) {
|
||||||
if (!q->image->gfx_handle) {
|
|
||||||
D3D11_TEXTURE2D_DESC desc = ZERO(D3D11_TEXTURE2D_DESC);
|
|
||||||
desc.Width = q->image->width;
|
|
||||||
desc.Height = q->image->height;
|
|
||||||
desc.MipLevels = 1;
|
|
||||||
desc.ArraySize = 1;
|
|
||||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
||||||
desc.SampleDesc.Count = 1;
|
|
||||||
desc.SampleDesc.Quality = 0;
|
|
||||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
|
||||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
|
||||||
desc.CPUAccessFlags = 0;
|
|
||||||
desc.MiscFlags = 0;
|
|
||||||
|
|
||||||
D3D11_SUBRESOURCE_DATA data = ZERO(D3D11_SUBRESOURCE_DATA);
|
|
||||||
data.pSysMem = q->image->data;
|
|
||||||
data.SysMemPitch = q->image->width * 4; // #Magicvalue assuming 4 channels
|
|
||||||
|
|
||||||
ID3D11Texture2D* texture = 0;
|
|
||||||
HRESULT hr = VTABLE(CreateTexture2D, d3d11_device, &desc, &data, &texture);
|
|
||||||
win32_check_hr(hr);
|
|
||||||
|
|
||||||
hr = VTABLE(CreateShaderResourceView, d3d11_device, (ID3D11Resource*)texture, 0, &q->image->gfx_handle);
|
|
||||||
win32_check_hr(hr);
|
|
||||||
|
|
||||||
log_verbose("Created an image of width %d and height %d.", q->image->width, q->image->height);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last_texture == q->image->gfx_handle) {
|
if (last_texture == q->image->gfx_handle) {
|
||||||
texture_index = (int)(num_textures-1);
|
texture_index = (int)(num_textures-1);
|
||||||
|
@ -742,3 +698,75 @@ void gfx_update() {
|
||||||
reset_draw_frame(&draw_frame);
|
reset_draw_frame(&draw_frame);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void gfx_init_image(Gfx_Image *image, void *data) {
|
||||||
|
D3D11_TEXTURE2D_DESC desc = ZERO(D3D11_TEXTURE2D_DESC);
|
||||||
|
desc.Width = image->width;
|
||||||
|
desc.Height = image->height;
|
||||||
|
desc.MipLevels = 1;
|
||||||
|
desc.ArraySize = 1;
|
||||||
|
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
desc.SampleDesc.Count = 1;
|
||||||
|
desc.SampleDesc.Quality = 0;
|
||||||
|
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||||
|
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||||
|
desc.CPUAccessFlags = 0;
|
||||||
|
desc.MiscFlags = 0;
|
||||||
|
|
||||||
|
D3D11_SUBRESOURCE_DATA data_desc = ZERO(D3D11_SUBRESOURCE_DATA);
|
||||||
|
data_desc.pSysMem = data;
|
||||||
|
data_desc.SysMemPitch = image->width * image->channels;
|
||||||
|
|
||||||
|
ID3D11Texture2D* texture = 0;
|
||||||
|
HRESULT hr = VTABLE(CreateTexture2D, d3d11_device, &desc, &data_desc, &texture);
|
||||||
|
win32_check_hr(hr);
|
||||||
|
|
||||||
|
hr = VTABLE(CreateShaderResourceView, d3d11_device, (ID3D11Resource*)texture, 0, &image->gfx_handle);
|
||||||
|
win32_check_hr(hr);
|
||||||
|
|
||||||
|
log_verbose("Created an image of width %d and height %d.", image->width, image->height);
|
||||||
|
}
|
||||||
|
void gfx_set_image_data(Gfx_Image *image, u32 x, u32 y, u32 w, u32 h, void *data) {
|
||||||
|
assert(image && data, "Bad parameters passed to gfx_set_image_data");
|
||||||
|
|
||||||
|
ID3D11ShaderResourceView *view = image->gfx_handle;
|
||||||
|
ID3D11Resource *resource = NULL;
|
||||||
|
VTABLE(GetResource, view, &resource);
|
||||||
|
|
||||||
|
assert(resource, "Invalid image passed to gfx_set_image_data");
|
||||||
|
|
||||||
|
assert(x+w < image->width && y+h < image->height, "Specified subregion in image is out of bounds");
|
||||||
|
|
||||||
|
ID3D11Texture2D *texture = NULL;
|
||||||
|
HRESULT hr = VTABLE(QueryInterface, resource, &IID_ID3D11Texture2D, (void**)&texture);
|
||||||
|
assert(SUCCEEDED(hr), "Expected gfx resource to be a texture but it wasn't");
|
||||||
|
|
||||||
|
D3D11_BOX destBox;
|
||||||
|
destBox.left = x;
|
||||||
|
destBox.right = x + w;
|
||||||
|
destBox.top = y;
|
||||||
|
destBox.bottom = y + h;
|
||||||
|
destBox.front = 0;
|
||||||
|
destBox.back = 1;
|
||||||
|
|
||||||
|
// #Incomplete bit-width 8 assumed
|
||||||
|
VTABLE(UpdateSubresource, d3d11_context, resource, 0, &destBox, data, w * image->channels, 0);
|
||||||
|
|
||||||
|
log_verbose("Updated image data at region (%u, %u) with dimensions (%u, %u).", x, y, w, h);
|
||||||
|
}
|
||||||
|
void gfx_deinit_image(Gfx_Image *image) {
|
||||||
|
ID3D11ShaderResourceView *view = image->gfx_handle;
|
||||||
|
ID3D11Resource *resource = 0;
|
||||||
|
VTABLE(GetResource, view, &resource);
|
||||||
|
|
||||||
|
ID3D11Texture2D *texture = 0;
|
||||||
|
HRESULT hr = VTABLE(QueryInterface, resource, &IID_ID3D11Texture2D, (void**)&texture);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
D3D11Release(view);
|
||||||
|
D3D11Release(texture);
|
||||||
|
log("Destroyed an image");
|
||||||
|
} else {
|
||||||
|
panic("Unhandled D3D11 resource deletion");
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,15 +18,106 @@
|
||||||
forward_global const Gfx_Handle GFX_INVALID_HANDLE;
|
forward_global const Gfx_Handle GFX_INVALID_HANDLE;
|
||||||
|
|
||||||
typedef struct Gfx_Image {
|
typedef struct Gfx_Image {
|
||||||
u32 width, height;
|
u32 width, height, channels;
|
||||||
u8 *data;
|
|
||||||
Gfx_Handle gfx_handle;
|
Gfx_Handle gfx_handle;
|
||||||
Allocator allocator;
|
Allocator allocator;
|
||||||
} Gfx_Image;
|
} Gfx_Image;
|
||||||
|
|
||||||
|
Gfx_Image *make_image(u32 width, u32 height, u32 channels, void *initial_data, Allocator allocator);
|
||||||
|
Gfx_Image *load_image_from_disk(string path, Allocator allocator);
|
||||||
|
void delete_image(Gfx_Image *image);
|
||||||
|
|
||||||
|
void gfx_init_image(Gfx_Image *image, void *data);
|
||||||
|
void gfx_set_image_data(Gfx_Image *image, u32 x, u32 y, u32 w, u32 h, void *data);
|
||||||
|
void gfx_deinit_image(Gfx_Image *image);
|
||||||
|
|
||||||
|
#define FONT_ATLAS_WIDTH 4096
|
||||||
|
#define FONT_ATLAS_HEIGHT 4096
|
||||||
|
#define MAX_FONT_HEIGHT 256
|
||||||
|
|
||||||
|
typedef struct Gfx_Font_Metrics {
|
||||||
|
u32 latin_ascent;
|
||||||
|
u32 latin_descent;
|
||||||
|
|
||||||
|
u32 max_ascent;
|
||||||
|
u32 max_descent;
|
||||||
|
|
||||||
|
u32 line_height;
|
||||||
|
u32 line_spacing;
|
||||||
|
|
||||||
|
} Gfx_Font_Metrics;
|
||||||
|
typedef struct Gfx_Font_Atlas {
|
||||||
|
Gfx_Image image;
|
||||||
|
|
||||||
|
} Gfx_Font_Atlas;
|
||||||
|
typedef struct Gfx_Font_Variation {
|
||||||
|
u32 height;
|
||||||
|
Gfx_Font_Metrics metrics;
|
||||||
|
u32 codepoint_range_per_atlas;
|
||||||
|
Hash_Table atlases; // u32 atlas_index, Gfx_Font_Atlas
|
||||||
|
bool initted;
|
||||||
|
} Gfx_Font_Variation;
|
||||||
typedef struct Gfx_Font {
|
typedef struct Gfx_Font {
|
||||||
u32 width, height;
|
Gfx_Font_Variation variations[MAX_FONT_HEIGHT]; // Variation per font height
|
||||||
u8 *data;
|
|
||||||
Gfx_Handle gfx_handle;
|
|
||||||
Allocator allocator;
|
Allocator allocator;
|
||||||
} Gfx_Font;
|
} Gfx_Font;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// initial_data can be null to leave image data uninitialized
|
||||||
|
Gfx_Image *make_image(u32 width, u32 height, u32 channels, void *initial_data, Allocator allocator) {
|
||||||
|
Gfx_Image *image = alloc(allocator, sizeof(Gfx_Image) + width*height*channels);
|
||||||
|
|
||||||
|
assert(channels > 0 && channels <= 4, "Only 1, 2, 3 or 4 channels allowed on images. Got %d", channels);
|
||||||
|
|
||||||
|
image->width = width;
|
||||||
|
image->height = height;
|
||||||
|
image->gfx_handle = GFX_INVALID_HANDLE; // This is handled in gfx
|
||||||
|
image->allocator = allocator;
|
||||||
|
image->channels = 4;
|
||||||
|
|
||||||
|
gfx_init_image(image, initial_data);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gfx_Image *load_image_from_disk(string path, Allocator allocator) {
|
||||||
|
string png;
|
||||||
|
bool ok = os_read_entire_file(path, &png, allocator);
|
||||||
|
if (!ok) return 0;
|
||||||
|
|
||||||
|
Gfx_Image *image = alloc(allocator, sizeof(Gfx_Image));
|
||||||
|
|
||||||
|
int width, height, channels;
|
||||||
|
stbi_set_flip_vertically_on_load(1);
|
||||||
|
unsigned char* stb_data = stbi_load_from_memory(png.data, png.count, &width, &height, &channels, STBI_rgb_alpha);
|
||||||
|
|
||||||
|
if (!stb_data) {
|
||||||
|
dealloc(allocator, image);
|
||||||
|
dealloc_string(allocator, png);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
image->width = width;
|
||||||
|
image->height = height;
|
||||||
|
image->gfx_handle = GFX_INVALID_HANDLE; // This is handled in gfx
|
||||||
|
image->allocator = allocator;
|
||||||
|
image->channels = 4;
|
||||||
|
|
||||||
|
dealloc_string(allocator, png);
|
||||||
|
|
||||||
|
gfx_init_image(image, stb_data);
|
||||||
|
|
||||||
|
stbi_image_free(stb_data);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_image(Gfx_Image *image) {
|
||||||
|
// Free the image data allocated by stb_image
|
||||||
|
image->width = 0;
|
||||||
|
image->height = 0;
|
||||||
|
gfx_deinit_image(image);
|
||||||
|
dealloc(image->allocator, image);
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
|
||||||
// Very naive implementation for now but it should be cache efficient so not really a
|
// Very naive implementation but it should be very cache efficient so it's alright
|
||||||
// problem until very large (in which case you should probably write your own data structure
|
// for non-excessive use for now.
|
||||||
// anyways)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
|
|
@ -1081,8 +1081,6 @@ void oogabooga_run_tests() {
|
||||||
print("OK!\n");
|
print("OK!\n");
|
||||||
|
|
||||||
|
|
||||||
// #Temporary
|
|
||||||
// This makes entire os freeze in release lol
|
|
||||||
#if CONFIGURATION != RELEASE
|
#if CONFIGURATION != RELEASE
|
||||||
print("Thread bombing allocator... ");
|
print("Thread bombing allocator... ");
|
||||||
Thread* threads[100];
|
Thread* threads[100];
|
||||||
|
|
Reference in a new issue