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 view;
|
||||
|
||||
Gfx_Handle garbage_stack[4096];
|
||||
u64 garbage_stack_count;
|
||||
} Draw_Frame;
|
||||
// This frame is passed to the platform layer and rendered in os_update.
|
||||
// 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_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());
|
||||
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();
|
||||
|
||||
const float64 fps_limit = 69000;
|
||||
|
@ -94,7 +102,7 @@ int entry(int argc, char **argv) {
|
|||
Matrix4 hammer_xform = m4_scalar(1.0);
|
||||
hammer_xform = m4_rotate_z(hammer_xform, (f32)now);
|
||||
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 local_pivot = v2(.125f, .125f);
|
||||
|
|
|
@ -22,8 +22,8 @@ typedef struct alignat(16) D3D11_Vertex {
|
|||
|
||||
ID3D11Debug *d3d11_debug = 0;
|
||||
|
||||
ID3D11Device* d3d11_device = 0;
|
||||
ID3D11DeviceContext* d3d11_context = 0;
|
||||
ID3D11Device *d3d11_device = 0;
|
||||
ID3D11DeviceContext *d3d11_context = 0;
|
||||
ID3D11RenderTargetView *d3d11_window_render_target_view = 0;
|
||||
ID3D11Texture2D *d3d11_back_buffer = 0;
|
||||
D3D_DRIVER_TYPE d3d11_driver_type = 0;
|
||||
|
@ -518,23 +518,6 @@ void gfx_update() {
|
|||
HRESULT hr;
|
||||
|
||||
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
|
||||
|
@ -595,33 +578,6 @@ void gfx_update() {
|
|||
int texture_index = -1;
|
||||
|
||||
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) {
|
||||
texture_index = (int)(num_textures-1);
|
||||
|
@ -742,3 +698,75 @@ void gfx_update() {
|
|||
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;
|
||||
|
||||
typedef struct Gfx_Image {
|
||||
u32 width, height;
|
||||
u8 *data;
|
||||
u32 width, height, channels;
|
||||
Gfx_Handle gfx_handle;
|
||||
Allocator allocator;
|
||||
} 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 {
|
||||
u32 width, height;
|
||||
u8 *data;
|
||||
Gfx_Handle gfx_handle;
|
||||
Gfx_Font_Variation variations[MAX_FONT_HEIGHT]; // Variation per font height
|
||||
Allocator allocator;
|
||||
} 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
|
||||
// problem until very large (in which case you should probably write your own data structure
|
||||
// anyways)
|
||||
// Very naive implementation but it should be very cache efficient so it's alright
|
||||
// for non-excessive use for now.
|
||||
|
||||
/*
|
||||
|
||||
|
|
|
@ -1081,8 +1081,6 @@ void oogabooga_run_tests() {
|
|||
print("OK!\n");
|
||||
|
||||
|
||||
// #Temporary
|
||||
// This makes entire os freeze in release lol
|
||||
#if CONFIGURATION != RELEASE
|
||||
print("Thread bombing allocator... ");
|
||||
Thread* threads[100];
|
||||
|
|
Reference in a new issue