Custom shaders
This commit is contained in:
parent
05c9811f38
commit
2aba15b429
22 changed files with 696 additions and 2873 deletions
18
README.md
18
README.md
|
@ -19,16 +19,14 @@ Ooga booga, often referred to as a *game engine* for simplicity, is more so desi
|
|||
|
||||
Ooga booga is designed to keep things simple, and let you solve video game problems the simplest way possible.
|
||||
|
||||
Performing SIMPLE and TRIVIAL tasks should be ... SIMPLE.
|
||||
If you want to draw a rectangle, there should be a single procedure to draw a rectangle.
|
||||
If you want to play an audio clip, there should be a single procedure to play an audio clip.
|
||||
Etc.
|
||||
This is something OS & Graphics API's tend to be fascinatingly terrible at even for the most trivial of tasks.
|
||||
Thankfully, this is a main problem which oogabooga seeks to solve with a thin-as-possible layer of abstraction over the
|
||||
If you need to do something more complicated, you should be able to focus on that problem alone.
|
||||
We aim to give you tools at a low enough level where there are no constraints to how you can go about solving the problems which arise for your game.
|
||||
If you wonder what any of the oogabooga procedures do, you can search for that symbol, go to the definition, and see & digest the exact implementation.
|
||||
Almost all implementations are code written by us with this in mind (with the exception of 3 nothings stb headers).
|
||||
What we mean by simple, is twofold:
|
||||
|
||||
1. Simple to use
|
||||
Performing SIMPLE and TRIVIAL tasks should be ... SIMPLE. If you want to draw a rectangle, there should be a single procedure to draw a rectangle. If you want to play an audio clip, there should be a single procedure to play an audio clip. Etc. This is something OS & Graphics API's tend to be fascinatingly terrible at even for the most trivial of tasks, and that is a big chunk of what we set out to solve.
|
||||
|
||||
2. Simple implementations
|
||||
When you need to do something more complicated, you need to understand the library you're working with. For some reason, it seems like it's a standard for libraries today to obscure the implementation details as much as possible spread out in layers and layers of procedure calls and abstractions. This is terrible.
|
||||
In Oogabooga, there is none of that. We WANT you to delve into our implementations and see exactly what we do. We do not hide ANYTHING from you. We do not impose RESTRICTIONS on how you solve problems. If you need to know what a procedure does, you search for the symbol and look at the implementation code. That's it.
|
||||
|
||||
|
||||
### The "Build System"
|
||||
|
|
21
TODO
21
TODO
|
@ -1,7 +1,10 @@
|
|||
|
||||
- Audio
|
||||
- Avoid playing identical audio at the same time
|
||||
- Custom audio mixing
|
||||
- Allow audio programming
|
||||
- Inject mixer proc per player
|
||||
- Inject a mixer proc before and after filling output buffer
|
||||
- Better spacialization
|
||||
- Fix vorbis >FILE< streaming (#StbVorbisFileStream)
|
||||
- Handle audio sources which had their format defaulted to update when default device changes
|
||||
For streamed audio sources this should be easy enough, because the conversion happens from raw format to source format as we stream it.
|
||||
|
@ -17,17 +20,33 @@
|
|||
- End of clip also causes noise if audio clip does not end smoothly
|
||||
- Setting audio source to a format which differs from audio output format in both channels and bit_width at the same time will produce pure loud noise.
|
||||
- 24-Bit audio conversion doesn't really work
|
||||
- Converting 24-bit audio files doesn't really work
|
||||
|
||||
- General bugs & issues
|
||||
- Release freeze in run_tests
|
||||
- Window width&height is zero when minimized (and we make a 0x0 swap chain)
|
||||
- Window positioning & sizing is fucky wucky
|
||||
|
||||
- Renderer
|
||||
- Custom shaders (just do hlsl for now, later we transpile)
|
||||
- Still compile a default that's set by default and we can set with set_shader_for_basic_2d
|
||||
// with screen space coords too (i.e, Vector2 instead of Matrix4)
|
||||
void draw_outline_rect_xform(Matrix4 xform, Vector2 size, float thickness, Vector4 color); // maybe have draw_rect_xform just be an outline and have another one for draw_filled_rect_xform or something
|
||||
void draw_rounded_rect_xform(Matrix4 xform, Vector2 size, float rounding, Vector4 color);
|
||||
void draw_circle_xform(Matrix4 xform, float radius, int segments, Vector4 color);
|
||||
void draw_line_xform(Matrix4 from, Matrix4 to, float thickness, Vector4 color);
|
||||
|
||||
// purely for screen space coords (scissor rect shit)
|
||||
void push_clip_rect(Vector2 position, Vector2 size);
|
||||
void pop_clip_rect();
|
||||
|
||||
- Fonts
|
||||
- Atlases are way too big, render atlases with size depending on font_height (say, 128 codepoints per atlas)
|
||||
|
||||
- OS
|
||||
Window::bool is_minimized
|
||||
don't set window.width & window.height to 0
|
||||
|
||||
- Needs testing:
|
||||
- Audio format channel conversions
|
||||
- sample rate downsampling
|
||||
|
|
4
build.c
4
build.c
|
@ -4,6 +4,7 @@
|
|||
// Build config stuff
|
||||
|
||||
#define OOGABOOGA_DEV 1
|
||||
//#define RUN_TESTS 1
|
||||
|
||||
#define INITIAL_PROGRAM_MEMORY_SIZE MB(5)
|
||||
|
||||
|
@ -39,9 +40,10 @@ typedef struct Context_Extra {
|
|||
|
||||
// #include "oogabooga/examples/text_rendering.c"
|
||||
// #include "oogabooga/examples/custom_logger.c"
|
||||
#include "oogabooga/examples/renderer_stress_test.c"
|
||||
// #include "oogabooga/examples/renderer_stress_test.c"
|
||||
// #include "oogabooga/examples/tile_game.c"
|
||||
// #include "oogabooga/examples/audio_test.c"
|
||||
#include "oogabooga/examples/custom_shader.c"
|
||||
|
||||
// This is where you swap in your own project!
|
||||
// #include "entry_yourepicgamename.c"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## v0.01.001 - Spacial audio,
|
||||
## v0.01.001 - Spacial audio, custom shading
|
||||
- Audio
|
||||
- Implemented spacial audio playback
|
||||
Simply set player->position (it's in ndc space (-1 to 1), see audio_test.c)
|
||||
|
@ -8,10 +8,19 @@
|
|||
play_one_audio_clip_at_position(path, pos)
|
||||
- Implemented volume control with player->volume
|
||||
- Renderer
|
||||
- Implemented custom shading
|
||||
- Recompile shader with your extension to the pixel stage with
|
||||
shader_recompile_with_extension(source, cbuffer_size)
|
||||
- pass a buffer to the shader constant buffer at b0 with
|
||||
draw_frame.cbuffer = &my_cbuffer_data
|
||||
- Made an example for custom shading (oogabooga/examples/custom_shading.c)
|
||||
- Embed default shader into codebase & always compile
|
||||
- Added draw_line(p0, p1, width, color)
|
||||
- Implemented culling of quads out of view
|
||||
- Fixed culling bug where big rectangles that overlapped the screen but had all corners outside the screen would get culled.
|
||||
|
||||
- Misc
|
||||
- Improved text measure and added a better explanation for it in font.c.
|
||||
- Added some useful Vector procedures:
|
||||
vx_length()
|
||||
vx_normalize()
|
||||
|
@ -19,6 +28,8 @@
|
|||
vx_dot()
|
||||
vx_abs()
|
||||
vx_cross()
|
||||
- added os_get_file_size_from_Path()
|
||||
- Some simple restructuring of existing code
|
||||
|
||||
## v0.01.000 - AUDIO!
|
||||
- Added audio sources
|
||||
|
|
|
@ -1496,7 +1496,6 @@ void apply_audio_spacialization(void* frames, Audio_Format format, u64 number_of
|
|||
if (format.channels == 2) {
|
||||
|
||||
// time delay and phase shift for vertical position
|
||||
float32 time_delay = (up_down_pan - 0.5f) * 0.0005f; // 0.5ms delay range
|
||||
float32 phase_shift = (up_down_pan - 0.5f) * 0.5f; // 0.5 radians phase shift range
|
||||
|
||||
// Stereo
|
||||
|
|
|
@ -18,9 +18,11 @@ void dump_stack_trace();
|
|||
|
||||
#define DEFER(start, end) for(int _i_ = ((start), 0); _i_ == 0; _i_ += 1, (end))
|
||||
|
||||
#define RAW_STRING(...) (#__VA_ARGS__)
|
||||
|
||||
#if CONFIGURATION == RELEASE
|
||||
#undef assert
|
||||
#define assert(...) (void)0;
|
||||
#define assert(x, ...) (void)(x)
|
||||
#endif
|
||||
|
||||
#define panic(...) { print(__VA_ARGS__); crash(); }
|
||||
|
|
|
@ -34,7 +34,7 @@ typedef struct Cpu_Capabilities {
|
|||
__debugbreak();
|
||||
volatile int *a = 0;
|
||||
*a = 5;
|
||||
a = (int*)0xDEADBEEF;
|
||||
a = (volatile int*)0xDEADBEEF;
|
||||
*a = 5;
|
||||
}
|
||||
#include <intrin.h>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,202 +0,0 @@
|
|||
|
||||
struct VS_INPUT
|
||||
{
|
||||
float4 position : POSITION;
|
||||
float2 uv : TEXCOORD;
|
||||
float4 color : COLOR;
|
||||
int texture_index : TEXTURE_INDEX;
|
||||
uint type : TYPE;
|
||||
uint sampler_index : SAMPLER_INDEX;
|
||||
};
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 position : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR;
|
||||
int texture_index: TEXTURE_INDEX;
|
||||
int type: TYPE;
|
||||
int sampler_index: SAMPLER_INDEX;
|
||||
};
|
||||
|
||||
PS_INPUT vs_main(VS_INPUT input)
|
||||
{
|
||||
PS_INPUT output;
|
||||
output.position = input.position;
|
||||
output.uv = input.uv;
|
||||
output.color = input.color;
|
||||
output.texture_index = input.texture_index;
|
||||
output.type = input.type;
|
||||
output.sampler_index = input.sampler_index;
|
||||
return output;
|
||||
}
|
||||
|
||||
// #Magicvalue
|
||||
Texture2D textures[32] : register(t0);
|
||||
SamplerState image_sampler_0 : register(s0);
|
||||
SamplerState image_sampler_1 : register(s1);
|
||||
SamplerState image_sampler_2 : register(s2);
|
||||
SamplerState image_sampler_3 : register(s3);
|
||||
|
||||
float4 sample_texture(int texture_index, int sampler_index, float2 uv) {
|
||||
// I love hlsl
|
||||
if (sampler_index == 0) {
|
||||
if (texture_index == 0) return textures[0].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 1) return textures[1].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 2) return textures[2].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 3) return textures[3].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 4) return textures[4].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 5) return textures[5].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 6) return textures[6].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 7) return textures[7].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 8) return textures[8].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 9) return textures[9].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 10) return textures[10].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 11) return textures[11].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 12) return textures[12].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 13) return textures[13].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 14) return textures[14].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 15) return textures[15].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 16) return textures[16].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 17) return textures[17].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 18) return textures[18].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 19) return textures[19].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 20) return textures[20].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 21) return textures[21].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 22) return textures[22].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 23) return textures[23].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 24) return textures[24].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 25) return textures[25].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 26) return textures[26].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 27) return textures[27].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 28) return textures[28].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 29) return textures[29].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 30) return textures[30].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 31) return textures[31].Sample(image_sampler_0, uv);
|
||||
} else if (sampler_index == 1) {
|
||||
if (texture_index == 0) return textures[0].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 1) return textures[1].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 2) return textures[2].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 3) return textures[3].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 4) return textures[4].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 5) return textures[5].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 6) return textures[6].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 7) return textures[7].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 8) return textures[8].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 9) return textures[9].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 10) return textures[10].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 11) return textures[11].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 12) return textures[12].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 13) return textures[13].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 14) return textures[14].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 15) return textures[15].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 16) return textures[16].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 17) return textures[17].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 18) return textures[18].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 19) return textures[19].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 20) return textures[20].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 21) return textures[21].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 22) return textures[22].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 23) return textures[23].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 24) return textures[24].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 25) return textures[25].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 26) return textures[26].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 27) return textures[27].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 28) return textures[28].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 29) return textures[29].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 30) return textures[30].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 31) return textures[31].Sample(image_sampler_1, uv);
|
||||
} else if (sampler_index == 2) {
|
||||
if (texture_index == 0) return textures[0].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 1) return textures[1].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 2) return textures[2].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 3) return textures[3].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 4) return textures[4].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 5) return textures[5].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 6) return textures[6].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 7) return textures[7].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 8) return textures[8].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 9) return textures[9].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 10) return textures[10].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 11) return textures[11].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 12) return textures[12].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 13) return textures[13].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 14) return textures[14].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 15) return textures[15].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 16) return textures[16].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 17) return textures[17].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 18) return textures[18].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 19) return textures[19].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 20) return textures[20].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 21) return textures[21].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 22) return textures[22].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 23) return textures[23].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 24) return textures[24].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 25) return textures[25].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 26) return textures[26].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 27) return textures[27].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 28) return textures[28].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 29) return textures[29].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 30) return textures[30].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 31) return textures[31].Sample(image_sampler_2, uv);
|
||||
} else if (sampler_index == 3) {
|
||||
if (texture_index == 0) return textures[0].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 1) return textures[1].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 2) return textures[2].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 3) return textures[3].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 4) return textures[4].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 5) return textures[5].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 6) return textures[6].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 7) return textures[7].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 8) return textures[8].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 9) return textures[9].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 10) return textures[10].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 11) return textures[11].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 12) return textures[12].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 13) return textures[13].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 14) return textures[14].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 15) return textures[15].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 16) return textures[16].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 17) return textures[17].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 18) return textures[18].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 19) return textures[19].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 20) return textures[20].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 21) return textures[21].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 22) return textures[22].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 23) return textures[23].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 24) return textures[24].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 25) return textures[25].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 26) return textures[26].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 27) return textures[27].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 28) return textures[28].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 29) return textures[29].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 30) return textures[30].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 31) return textures[31].Sample(image_sampler_3, uv);
|
||||
}
|
||||
|
||||
return float4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define QUAD_TYPE_REGULAR 0
|
||||
#define QUAD_TYPE_TEXT 1
|
||||
|
||||
float4 ps_main(PS_INPUT input) : SV_TARGET
|
||||
{
|
||||
if (input.type == QUAD_TYPE_REGULAR) {
|
||||
if (input.texture_index >= 0 && input.texture_index < 32 && input.sampler_index >= 0 && input.sampler_index <= 3) {
|
||||
return sample_texture(input.texture_index, input.sampler_index, input.uv)*input.color;
|
||||
} else {
|
||||
return input.color;
|
||||
}
|
||||
} else if (input.type == QUAD_TYPE_TEXT) {
|
||||
if (input.texture_index >= 0 && input.texture_index < 32 && input.sampler_index >= 0 && input.sampler_index <= 3) {
|
||||
float alpha = sample_texture(input.texture_index, input.sampler_index, input.uv).x;
|
||||
return float4(1.0, 1.0, 1.0, alpha)*input.color;
|
||||
} else {
|
||||
return input.color;
|
||||
}
|
||||
}
|
||||
return float4(0.0, 1.0, 0.0, 1.0);
|
||||
}
|
|
@ -78,15 +78,12 @@ typedef struct Draw_Quad {
|
|||
// r, g, b, a
|
||||
Vector4 color;
|
||||
Gfx_Image *image;
|
||||
|
||||
// x1, y1, x2, y2
|
||||
Vector4 uv;
|
||||
u8 type;
|
||||
|
||||
Gfx_Filter_Mode image_min_filter;
|
||||
Gfx_Filter_Mode image_mag_filter;
|
||||
|
||||
s32 z;
|
||||
u8 type;
|
||||
// x1, y1, x2, y2
|
||||
Vector4 uv;
|
||||
|
||||
} Draw_Quad;
|
||||
|
||||
|
@ -102,6 +99,9 @@ typedef struct Draw_Frame {
|
|||
bool enable_z_sorting;
|
||||
s32 z_stack[Z_STACK_MAX];
|
||||
u64 z_count;
|
||||
|
||||
void *cbuffer;
|
||||
|
||||
} Draw_Frame;
|
||||
// This frame is passed to the platform layer and rendered in os_update.
|
||||
// Resets every frame.
|
||||
|
@ -135,10 +135,10 @@ Draw_Quad *draw_quad_projected(Draw_Quad quad, Matrix4 world_to_clip) {
|
|||
quad.bottom_right = m4_transform(world_to_clip, v4(v2_expand(quad.bottom_right), 0, 1)).xy;
|
||||
|
||||
bool should_cull =
|
||||
(quad.bottom_left.x < -1 || quad.bottom_left.x > 1 || quad.bottom_left.y < -1 || quad.bottom_left.y > 1)
|
||||
&& (quad.top_left.x < -1 || quad.top_left.x > 1 || quad.top_left.y < -1 || quad.top_left.y > 1)
|
||||
&& (quad.top_right.x < -1 || quad.top_right.x > 1 || quad.top_right.y < -1 || quad.top_right.y > 1)
|
||||
&& (quad.bottom_right.x < -1 || quad.bottom_right.x > 1 || quad.bottom_right.y < -1 || quad.bottom_right.y > 1);
|
||||
(quad.bottom_left.x < -1 && quad.top_left.x < -1 && quad.top_right.x < -1 && quad.bottom_right.x < -1) ||
|
||||
(quad.bottom_left.x > 1 && quad.top_left.x > 1 && quad.top_right.x > 1 && quad.bottom_right.x > 1) ||
|
||||
(quad.bottom_left.y < -1 && quad.top_left.y < -1 && quad.top_right.y < -1 && quad.bottom_right.y < -1) ||
|
||||
(quad.bottom_left.y > 1 && quad.top_left.y > 1 && quad.top_right.y > 1 && quad.bottom_right.y > 1);
|
||||
|
||||
if (should_cull) {
|
||||
return &_nil_quad;
|
||||
|
|
|
@ -105,7 +105,7 @@ int entry(int argc, char **argv) {
|
|||
if (button(STR("Song vol down"), rect.xy, rect.zw, false)) {
|
||||
song_player->volume -= 0.05;
|
||||
}
|
||||
song_player->volume = clamp(song_player->volume, 0, 5);
|
||||
song_player->volume = clamp(song_player->volume, 0, 20);
|
||||
rect.x += rect.z + FONT_HEIGHT;
|
||||
draw_text(font, tprint("Song volume: %d%%", (s64)round(song_player->volume*100)), FONT_HEIGHT, v2_sub(rect.xy, v2(2, -2)), v2(1, 1), COLOR_BLACK);
|
||||
draw_text(font, tprint("Song volume: %d%%", (s64)round(song_player->volume*100)), FONT_HEIGHT, rect.xy, v2(1, 1), COLOR_WHITE);
|
||||
|
|
72
oogabooga/examples/custom_shader.c
Normal file
72
oogabooga/examples/custom_shader.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
|
||||
// BEWARE std140 packing:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
|
||||
typedef struct My_Cbuffer {
|
||||
Vector2 mouse_pos_screen;
|
||||
Vector2 window_size;
|
||||
} My_Cbuffer;
|
||||
|
||||
int entry(int argc, char **argv) {
|
||||
|
||||
window.title = STR("Custom Shader Example");
|
||||
window.scaled_width = 1280;
|
||||
window.scaled_height = 720;
|
||||
window.x = 200;
|
||||
window.y = 90;
|
||||
window.clear_color = hex_to_rgba(0x6495EDff);
|
||||
|
||||
string source;
|
||||
bool ok = os_read_entire_file("oogabooga/examples/custom_shader.hlsl", &source, get_heap_allocator());
|
||||
assert(ok, "Could not read oogabooga/examples/custom_shader.hlsl");
|
||||
|
||||
// This is slow and needs to recompile the shader. However, it should probably only happen once (or each hot reload)
|
||||
// If it fails, it will return false and return to whatever shader it was before.
|
||||
shader_recompile_with_extension(source, sizeof(My_Cbuffer));
|
||||
|
||||
dealloc_string(get_heap_allocator(), source);
|
||||
|
||||
// This memory needs to stay alive throughout the frame because we pass the pointer to it in draw_frame.cbuffer.
|
||||
// If this memory is invalidated before gfx_update after setting draw_frame.cbuffer, then gfx_update will copy
|
||||
// memory from an invalid address.
|
||||
My_Cbuffer cbuffer;
|
||||
|
||||
float64 last_time = os_get_current_time_in_seconds();
|
||||
while (!window.should_close) {
|
||||
|
||||
float64 now = os_get_current_time_in_seconds();
|
||||
if ((int)now != (int)last_time) {
|
||||
log("%.2f FPS\n%.2fms", 1.0/(now-last_time), (now-last_time)*1000);
|
||||
}
|
||||
last_time = now;
|
||||
|
||||
reset_temporary_storage();
|
||||
|
||||
cbuffer.mouse_pos_screen = v2(input_frame.mouse_x, input_frame.mouse_y);
|
||||
cbuffer.window_size = v2(window.width, window.height);
|
||||
draw_frame.cbuffer = &cbuffer;
|
||||
|
||||
// Just draw a big rect to cover background, so our lighting shader will apply to background
|
||||
draw_rect(v2(-5, -5), v2(10, 10), v4(.4, .4, .4, 1.0));
|
||||
|
||||
Matrix4 rect_xform = m4_scalar(1.0);
|
||||
rect_xform = m4_rotate_z(rect_xform, (f32)now);
|
||||
rect_xform = m4_translate(rect_xform, v3(-.25f, -.25f, 0));
|
||||
draw_rect_xform(rect_xform, v2(.5f, .5f), COLOR_GREEN);
|
||||
|
||||
draw_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED);
|
||||
|
||||
|
||||
// Shader hot reloading
|
||||
if (is_key_just_pressed('R')) {
|
||||
ok = os_read_entire_file("oogabooga/examples/custom_shader.hlsl", &source, get_heap_allocator());
|
||||
assert(ok, "Could not read oogabooga/examples/custom_shader.hlsl");
|
||||
shader_recompile_with_extension(source, sizeof(My_Cbuffer));
|
||||
dealloc_string(get_heap_allocator(), source);
|
||||
}
|
||||
|
||||
os_update();
|
||||
gfx_update();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
23
oogabooga/examples/custom_shader.hlsl
Normal file
23
oogabooga/examples/custom_shader.hlsl
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
// PS_INPUT is defined in the default shader in gfx_impl_d3d11.c at the bottom of the file
|
||||
|
||||
// BEWARE std140 packing:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
|
||||
cbuffer some_cbuffer : register(b0) {
|
||||
float2 mouse_pos_screen; // In pixels
|
||||
float2 window_size;
|
||||
}
|
||||
|
||||
float4 pixel_shader_extension(PS_INPUT input, float4 color) {
|
||||
const float light_distance = 500;
|
||||
|
||||
float2 vertex_pos = input.position_screen.xy; // In pixels
|
||||
vertex_pos.y = window_size.y-vertex_pos.y; // For some reason d3d11 inverts the Y here so we need to revert it
|
||||
|
||||
// Simple linear attenuation based on distance
|
||||
float attenuation = 1.0 - (length(mouse_pos_screen - vertex_pos) / light_distance);
|
||||
|
||||
float4 light = float4(attenuation, attenuation, attenuation, 1.0);
|
||||
|
||||
return color * light;
|
||||
}
|
|
@ -8,7 +8,12 @@ int entry(int argc, char **argv) {
|
|||
window.y = 90;
|
||||
window.clear_color = hex_to_rgba(0x6495EDff);
|
||||
|
||||
float64 last_time = os_get_current_time_in_seconds();
|
||||
while (!window.should_close) {
|
||||
float64 now = os_get_current_time_in_seconds();
|
||||
if ((int)now != (int)last_time) log("%.2f FPS\n%.2fms", 1.0/(now-last_time), (now-last_time)*1000);
|
||||
last_time = now;
|
||||
|
||||
reset_temporary_storage();
|
||||
|
||||
float64 now = os_get_current_time_in_seconds();
|
||||
|
|
|
@ -92,7 +92,7 @@ int entry(int argc, char **argv) {
|
|||
if (is_key_just_pressed('Z')) do_enable_z_sorting = !do_enable_z_sorting;
|
||||
|
||||
seed_for_random = 69;
|
||||
for (u64 i = 0; i < 50000; i++) {
|
||||
for (u64 i = 0; i < 100000; i++) {
|
||||
float32 aspect = (float32)window.width/(float32)window.height;
|
||||
float min_x = -aspect;
|
||||
float max_x = aspect;
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
|
||||
|
||||
#if !OOGABOOGA_DEV
|
||||
|
||||
#include "d3d11_image_shader_bytecode.c"
|
||||
|
||||
#endif
|
||||
|
||||
#define D3D11Release(x) x->lpVtbl->Release(x)
|
||||
|
||||
|
@ -49,17 +44,23 @@ ID3D11SamplerState *d3d11_image_sampler_nl_fl = 0;
|
|||
ID3D11SamplerState *d3d11_image_sampler_np_fl = 0;
|
||||
ID3D11SamplerState *d3d11_image_sampler_nl_fp = 0;
|
||||
|
||||
ID3D11VertexShader *d3d11_image_vertex_shader = 0;
|
||||
ID3D11PixelShader *d3d11_image_pixel_shader = 0;
|
||||
ID3D11VertexShader *d3d11_vertex_shader_for_2d = 0;
|
||||
ID3D11PixelShader *d3d11_fragment_shader_for_2d = 0;
|
||||
ID3D11InputLayout *d3d11_image_vertex_layout = 0;
|
||||
|
||||
ID3D11Buffer *d3d11_quad_vbo = 0;
|
||||
u32 d3d11_quad_vbo_size = 0;
|
||||
void *d3d11_staging_quad_buffer = 0;
|
||||
|
||||
ID3D11Buffer *d3d11_cbuffer = 0;
|
||||
u64 d3d11_cbuffer_size = 0;
|
||||
|
||||
Draw_Quad *sort_quad_buffer = 0;
|
||||
u64 sort_quad_buffer_size = 0;
|
||||
|
||||
// Defined at the bottom of this file
|
||||
extern const char *d3d11_image_shader_source;
|
||||
|
||||
const char* d3d11_stringify_category(D3D11_MESSAGE_CATEGORY category) {
|
||||
switch (category) {
|
||||
case D3D11_MESSAGE_CATEGORY_APPLICATION_DEFINED: return "Application Defined";
|
||||
|
@ -89,6 +90,14 @@ const char* d3d11_stringify_severity(D3D11_MESSAGE_SEVERITY severity) {
|
|||
|
||||
void CALLBACK d3d11_debug_callback(D3D11_MESSAGE_CATEGORY category, D3D11_MESSAGE_SEVERITY severity, D3D11_MESSAGE_ID id, const char* description)
|
||||
{
|
||||
if (id == 391) {
|
||||
// Sigh:
|
||||
/*
|
||||
[WARNING]: D3D11 MESSAGE [Category: State Creation, Severity: Warning, id: 391]: ID3D11Device::CreateInputLayout: The provided input signature expects to read an element with SemanticName/Index: 'SAMPLER_INDEX'/0 and component(s) of the type 'uint32'. However, the matching entry in the Input Layout declaration, element[5], specifies mismatched format: 'R8_SINT'. This is not an error, since behavior is well defined: The element format determines what data conversion algorithm gets applied before it shows up in a shader register. Independently, the shader input signature defines how the shader will interpret the data that has been placed in its input registers, with no change in the bits stored. It is valid for the application to reinterpret data as a different type once it is in the vertex shader, so this warning is issued just in case reinterpretation was not intended by the author.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
string msg = tprint("D3D11 MESSAGE [Category: %cs, Severity: %cs, id: %d]: %cs", d3d11_stringify_category(category), d3d11_stringify_severity(severity), id, description);
|
||||
|
||||
switch (severity) {
|
||||
|
@ -244,6 +253,112 @@ void d3d11_update_swapchain() {
|
|||
win32_check_hr(hr);
|
||||
}
|
||||
|
||||
bool
|
||||
d3d11_compile_shader(string source) {
|
||||
|
||||
source = string_replace_all(source, STR("$INJECT_PIXEL_POST_PROCESS"), STR("float4 pixel_shader_extension(PS_INPUT input, float4 color) { return color; }"), temp);
|
||||
|
||||
// #Leak on recompile
|
||||
|
||||
///
|
||||
// Make default shaders
|
||||
|
||||
// Compile vertex shader
|
||||
ID3DBlob* vs_blob = NULL;
|
||||
ID3DBlob* err_blob = NULL;
|
||||
HRESULT hr = D3DCompile((char*)source.data, source.count, 0, 0, 0, "vs_main", "vs_5_0", 0, 0, &vs_blob, &err_blob);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
log_error("Vertex Shader Compilation Error: %cs\n", (char*)ID3D10Blob_GetBufferPointer(err_blob));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compile pixel shader
|
||||
ID3DBlob* ps_blob = NULL;
|
||||
hr = D3DCompile((char*)source.data, source.count, 0, 0, 0, "ps_main", "ps_5_0", 0, 0, &ps_blob, &err_blob);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
log_error("Fragment Shader Compilation Error: %cs\n", (char*)ID3D10Blob_GetBufferPointer(err_blob));
|
||||
return false;
|
||||
}
|
||||
|
||||
void *vs_buffer = ID3D10Blob_GetBufferPointer(vs_blob);
|
||||
u64 vs_size = ID3D10Blob_GetBufferSize(vs_blob);
|
||||
void *ps_buffer = ID3D10Blob_GetBufferPointer(ps_blob);
|
||||
u64 ps_size = ID3D10Blob_GetBufferSize(ps_blob);
|
||||
|
||||
log_verbose("Shaders compiled");
|
||||
|
||||
|
||||
// Create the shaders
|
||||
hr = ID3D11Device_CreateVertexShader(d3d11_device, vs_buffer, vs_size, NULL, &d3d11_vertex_shader_for_2d);
|
||||
win32_check_hr(hr);
|
||||
|
||||
hr = ID3D11Device_CreatePixelShader(d3d11_device, ps_buffer, ps_size, NULL, &d3d11_fragment_shader_for_2d);
|
||||
win32_check_hr(hr);
|
||||
|
||||
log_verbose("Shaders created");
|
||||
|
||||
|
||||
|
||||
D3D11_INPUT_ELEMENT_DESC layout[6];
|
||||
memset(layout, 0, sizeof(layout));
|
||||
|
||||
layout[0].SemanticName = "POSITION";
|
||||
layout[0].SemanticIndex = 0;
|
||||
layout[0].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
layout[0].InputSlot = 0;
|
||||
layout[0].AlignedByteOffset = offsetof(D3D11_Vertex, position);
|
||||
layout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[0].InstanceDataStepRate = 0;
|
||||
|
||||
layout[1].SemanticName = "TEXCOORD";
|
||||
layout[1].SemanticIndex = 0;
|
||||
layout[1].Format = DXGI_FORMAT_R32G32_FLOAT;
|
||||
layout[1].InputSlot = 0;
|
||||
layout[1].AlignedByteOffset = offsetof(D3D11_Vertex, uv);
|
||||
layout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[1].InstanceDataStepRate = 0;
|
||||
|
||||
layout[2].SemanticName = "COLOR";
|
||||
layout[2].SemanticIndex = 0;
|
||||
layout[2].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
layout[2].InputSlot = 0;
|
||||
layout[2].AlignedByteOffset = offsetof(D3D11_Vertex, color);
|
||||
layout[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[2].InstanceDataStepRate = 0;
|
||||
|
||||
layout[3].SemanticName = "TEXTURE_INDEX";
|
||||
layout[3].SemanticIndex = 0;
|
||||
layout[3].Format = DXGI_FORMAT_R8_SINT;
|
||||
layout[3].InputSlot = 0;
|
||||
layout[3].AlignedByteOffset = offsetof(D3D11_Vertex, texture_index);
|
||||
layout[3].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[3].InstanceDataStepRate = 0;
|
||||
|
||||
layout[4].SemanticName = "TYPE";
|
||||
layout[4].SemanticIndex = 0;
|
||||
layout[4].Format = DXGI_FORMAT_R8_UINT;
|
||||
layout[4].InputSlot = 0;
|
||||
layout[4].AlignedByteOffset = offsetof(D3D11_Vertex, type);
|
||||
layout[4].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[4].InstanceDataStepRate = 0;
|
||||
|
||||
layout[5].SemanticName = "SAMPLER_INDEX";
|
||||
layout[5].SemanticIndex = 0;
|
||||
layout[5].Format = DXGI_FORMAT_R8_SINT;
|
||||
layout[5].InputSlot = 0;
|
||||
layout[5].AlignedByteOffset = offsetof(D3D11_Vertex, sampler);
|
||||
layout[5].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[5].InstanceDataStepRate = 0;
|
||||
|
||||
hr = ID3D11Device_CreateInputLayout(d3d11_device, layout, 6, vs_buffer, vs_size, &d3d11_image_vertex_layout);
|
||||
win32_check_hr(hr);
|
||||
|
||||
D3D11Release(vs_blob);
|
||||
D3D11Release(ps_blob);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void gfx_init() {
|
||||
|
||||
window.enable_vsync = false;
|
||||
|
@ -302,7 +417,7 @@ void gfx_init() {
|
|||
win32_check_hr(hr);
|
||||
|
||||
if (debug_failed) {
|
||||
log_error("We could not init D3D11 with DEBUG flag. This is likely because you have not enabled \"Graphics Tools\" in windows settings. https://github.com/microsoft/DirectX-Graphics-Samples/issues/447#issuecomment-415611443");
|
||||
log_error("We could not init D3D11 with DEBUG flag. To fix this, you can try:\n1. Go to windows settings\n2. Go to System -> Optional features\n3. Add the feature called \"Graphics Tools\"\n4. Restart your computer\n5. Be frustrated that windows is like this.\nhttps://devblogs.microsoft.com/cppblog/visual-studio-2015-and-graphics-tools-for-windows-10/");
|
||||
}
|
||||
|
||||
assert(d3d11_device != 0, "D3D11CreateDevice failed");
|
||||
|
@ -408,136 +523,10 @@ void gfx_init() {
|
|||
win32_check_hr(hr);
|
||||
}
|
||||
|
||||
// We are ooga booga devs so we read the file and compile
|
||||
#if OOGABOOGA_DEV
|
||||
string source = STR(d3d11_image_shader_source);
|
||||
bool ok = d3d11_compile_shader(source);
|
||||
|
||||
string source;
|
||||
bool source_ok = os_read_entire_file("oogabooga/dev/d3d11_image_shader.hlsl", &source, get_heap_allocator()); // #Leak
|
||||
assert(source_ok, "Could not open d3d11_image_shader source");
|
||||
|
||||
// Compile vertex shader
|
||||
ID3DBlob* vs_blob = NULL;
|
||||
ID3DBlob* err_blob = NULL;
|
||||
hr = D3DCompile((char*)source.data, source.count, 0, 0, 0, "vs_main", "vs_5_0", 0, 0, &vs_blob, &err_blob);
|
||||
assert(SUCCEEDED(hr), "Vertex Shader Compilation Error: %cs\n", (char*)ID3D10Blob_GetBufferPointer(err_blob));
|
||||
|
||||
// Compile pixel shader
|
||||
ID3DBlob* ps_blob = NULL;
|
||||
hr = D3DCompile((char*)source.data, source.count, 0, 0, 0, "ps_main", "ps_5_0", 0, 0, &ps_blob, &err_blob);
|
||||
assert(SUCCEEDED(hr), "Vertex Shader Compilation Error: %cs\n", (char*)ID3D10Blob_GetBufferPointer(err_blob));
|
||||
|
||||
void *vs_buffer = ID3D10Blob_GetBufferPointer(vs_blob);
|
||||
u64 vs_size = ID3D10Blob_GetBufferSize(vs_blob);
|
||||
void *ps_buffer = ID3D10Blob_GetBufferPointer(ps_blob);
|
||||
u64 ps_size = ID3D10Blob_GetBufferSize(ps_blob);
|
||||
|
||||
log_verbose("Shaders compiled");
|
||||
|
||||
///
|
||||
// Dump blobs to the .c
|
||||
File blob_file = os_file_open("oogabooga/d3d11_image_shader_bytecode.c", O_WRITE | O_CREATE);
|
||||
os_file_write_string(blob_file, STR("/*\n"));
|
||||
os_file_write_string(blob_file, STR("<<<<<< Bytecode compiled fro HLSL code below: >>>>>>\n\n"));
|
||||
os_file_write_string(blob_file, source);
|
||||
os_file_write_string(blob_file, STR("\n*/\n\n"));
|
||||
|
||||
os_file_write_string(blob_file, STR("const u8 IMAGE_SHADER_VERTEX_BLOB_BYTES[]= {\n"));
|
||||
for (u64 i = 0; i < vs_size; i++) {
|
||||
os_file_write_string(blob_file, tprint("0x%02x", (int)((u8*)vs_buffer)[i]));
|
||||
if (i < vs_size-1) os_file_write_string(blob_file, STR(", "));
|
||||
if (i % 15 == 0 && i != 0) os_file_write_string(blob_file, STR("\n"));
|
||||
}
|
||||
os_file_write_string(blob_file, STR("\n};\n"));
|
||||
|
||||
os_file_write_string(blob_file, STR("const u8 IMAGE_SHADER_PIXEL_BLOB_BYTES[]= {\n"));
|
||||
for (u64 i = 0; i < ps_size; i++) {
|
||||
os_file_write_string(blob_file, tprint("0x%02x", (int)((u8*)ps_buffer)[i]));
|
||||
if (i < ps_size-1) os_file_write_string(blob_file, STR(", "));
|
||||
if (i % 15 == 0 && i != 0) os_file_write_string(blob_file, STR("\n"));
|
||||
}
|
||||
os_file_write_string(blob_file, STR("\n};\n"));
|
||||
os_file_close(blob_file);
|
||||
|
||||
|
||||
#else
|
||||
|
||||
const void *vs_buffer = IMAGE_SHADER_VERTEX_BLOB_BYTES;
|
||||
u64 vs_size = sizeof(IMAGE_SHADER_VERTEX_BLOB_BYTES);
|
||||
const void *ps_buffer = IMAGE_SHADER_PIXEL_BLOB_BYTES;
|
||||
u64 ps_size = sizeof(IMAGE_SHADER_PIXEL_BLOB_BYTES);
|
||||
|
||||
log_verbose("Cached shaders loaded");
|
||||
#endif
|
||||
|
||||
// Create the shaders
|
||||
hr = ID3D11Device_CreateVertexShader(d3d11_device, vs_buffer, vs_size, NULL, &d3d11_image_vertex_shader);
|
||||
win32_check_hr(hr);
|
||||
|
||||
hr = ID3D11Device_CreatePixelShader(d3d11_device, ps_buffer, ps_size, NULL, &d3d11_image_pixel_shader);
|
||||
win32_check_hr(hr);
|
||||
|
||||
log_verbose("Shaders created");
|
||||
|
||||
|
||||
|
||||
D3D11_INPUT_ELEMENT_DESC layout[6];
|
||||
memset(layout, 0, sizeof(layout));
|
||||
|
||||
layout[0].SemanticName = "POSITION";
|
||||
layout[0].SemanticIndex = 0;
|
||||
layout[0].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
layout[0].InputSlot = 0;
|
||||
layout[0].AlignedByteOffset = offsetof(D3D11_Vertex, position);
|
||||
layout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[0].InstanceDataStepRate = 0;
|
||||
|
||||
layout[1].SemanticName = "TEXCOORD";
|
||||
layout[1].SemanticIndex = 0;
|
||||
layout[1].Format = DXGI_FORMAT_R32G32_FLOAT;
|
||||
layout[1].InputSlot = 0;
|
||||
layout[1].AlignedByteOffset = offsetof(D3D11_Vertex, uv);
|
||||
layout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[1].InstanceDataStepRate = 0;
|
||||
|
||||
layout[2].SemanticName = "COLOR";
|
||||
layout[2].SemanticIndex = 0;
|
||||
layout[2].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
layout[2].InputSlot = 0;
|
||||
layout[2].AlignedByteOffset = offsetof(D3D11_Vertex, color);
|
||||
layout[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[2].InstanceDataStepRate = 0;
|
||||
|
||||
layout[3].SemanticName = "TEXTURE_INDEX";
|
||||
layout[3].SemanticIndex = 0;
|
||||
layout[3].Format = DXGI_FORMAT_R8_SINT;
|
||||
layout[3].InputSlot = 0;
|
||||
layout[3].AlignedByteOffset = offsetof(D3D11_Vertex, texture_index);
|
||||
layout[3].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[3].InstanceDataStepRate = 0;
|
||||
|
||||
layout[4].SemanticName = "TYPE";
|
||||
layout[4].SemanticIndex = 0;
|
||||
layout[4].Format = DXGI_FORMAT_R8_UINT;
|
||||
layout[4].InputSlot = 0;
|
||||
layout[4].AlignedByteOffset = offsetof(D3D11_Vertex, type);
|
||||
layout[4].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[4].InstanceDataStepRate = 0;
|
||||
|
||||
layout[5].SemanticName = "SAMPLER_INDEX";
|
||||
layout[5].SemanticIndex = 0;
|
||||
layout[5].Format = DXGI_FORMAT_R8_SINT;
|
||||
layout[5].InputSlot = 0;
|
||||
layout[5].AlignedByteOffset = offsetof(D3D11_Vertex, sampler);
|
||||
layout[5].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
layout[5].InstanceDataStepRate = 0;
|
||||
|
||||
hr = ID3D11Device_CreateInputLayout(d3d11_device, layout, 6, vs_buffer, vs_size, &d3d11_image_vertex_layout);
|
||||
win32_check_hr(hr);
|
||||
|
||||
#if OOGABOOGA_DEV
|
||||
D3D11Release(vs_blob);
|
||||
D3D11Release(ps_blob);
|
||||
#endif
|
||||
assert(ok, "Failed compiling default shader");
|
||||
|
||||
log_info("D3D11 init done");
|
||||
|
||||
|
@ -560,8 +549,17 @@ void d3d11_draw_call(int number_of_rendered_quads, ID3D11ShaderResourceView **te
|
|||
ID3D11DeviceContext_IASetVertexBuffers(d3d11_context, 0, 1, &d3d11_quad_vbo, &stride, &offset);
|
||||
ID3D11DeviceContext_IASetPrimitiveTopology(d3d11_context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
ID3D11DeviceContext_VSSetShader(d3d11_context, d3d11_image_vertex_shader, NULL, 0);
|
||||
ID3D11DeviceContext_PSSetShader(d3d11_context, d3d11_image_pixel_shader, NULL, 0);
|
||||
ID3D11DeviceContext_VSSetShader(d3d11_context, d3d11_vertex_shader_for_2d, NULL, 0);
|
||||
ID3D11DeviceContext_PSSetShader(d3d11_context, d3d11_fragment_shader_for_2d, NULL, 0);
|
||||
|
||||
if (draw_frame.cbuffer && d3d11_cbuffer && d3d11_cbuffer_size) {
|
||||
D3D11_MAPPED_SUBRESOURCE cbuffer_mapping;
|
||||
ID3D11DeviceContext_Map(d3d11_context, (ID3D11Resource*)d3d11_cbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbuffer_mapping);
|
||||
memcpy(cbuffer_mapping.pData, draw_frame.cbuffer, d3d11_cbuffer_size);
|
||||
ID3D11DeviceContext_Unmap(d3d11_context, (ID3D11Resource*)d3d11_cbuffer, 0);
|
||||
|
||||
ID3D11DeviceContext_PSSetConstantBuffers(d3d11_context, 0, 1, &d3d11_cbuffer);
|
||||
}
|
||||
|
||||
ID3D11DeviceContext_PSSetSamplers(d3d11_context, 0, 1, &d3d11_image_sampler_np_fp);
|
||||
ID3D11DeviceContext_PSSetSamplers(d3d11_context, 1, 1, &d3d11_image_sampler_nl_fl);
|
||||
|
@ -895,3 +893,242 @@ void gfx_deinit_image(Gfx_Image *image) {
|
|||
panic("Unhandled D3D11 resource deletion");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
shader_recompile_with_extension(string ext_source, u64 cbuffer_size) {
|
||||
|
||||
|
||||
string source = string_replace_all(STR(d3d11_image_shader_source), STR("$INJECT_PIXEL_POST_PROCESS"), ext_source, temp);
|
||||
|
||||
if (!d3d11_compile_shader(source)) return false;
|
||||
|
||||
u64 aligned_cbuffer_size = (max(cbuffer_size, 16) + 16) & ~(15);
|
||||
|
||||
if (d3d11_cbuffer) {
|
||||
D3D11Release(d3d11_cbuffer);
|
||||
}
|
||||
D3D11_BUFFER_DESC desc = ZERO(D3D11_BUFFER_DESC);
|
||||
desc.ByteWidth = aligned_cbuffer_size;
|
||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
HRESULT hr = ID3D11Device_CreateBuffer(d3d11_device, &desc, null, &d3d11_cbuffer);
|
||||
win32_check_hr(hr);
|
||||
|
||||
d3d11_cbuffer_size = cbuffer_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *d3d11_image_shader_source = RAW_STRING(
|
||||
|
||||
struct VS_INPUT
|
||||
{
|
||||
float4 position : POSITION;
|
||||
float2 uv : TEXCOORD;
|
||||
float4 color : COLOR;
|
||||
int texture_index : TEXTURE_INDEX;
|
||||
uint type : TYPE;
|
||||
uint sampler_index : SAMPLER_INDEX;
|
||||
};
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 position_screen : SV_POSITION;
|
||||
float4 position : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR;
|
||||
int texture_index: TEXTURE_INDEX;
|
||||
int type: TYPE;
|
||||
int sampler_index: SAMPLER_INDEX;
|
||||
};
|
||||
|
||||
PS_INPUT vs_main(VS_INPUT input)
|
||||
{
|
||||
PS_INPUT output;
|
||||
output.position_screen = input.position;
|
||||
output.position = input.position;
|
||||
output.uv = input.uv;
|
||||
output.color = input.color;
|
||||
output.texture_index = input.texture_index;
|
||||
output.type = input.type;
|
||||
output.sampler_index = input.sampler_index;
|
||||
return output;
|
||||
}
|
||||
|
||||
// #Magicvalue
|
||||
Texture2D textures[32] : register(t0);
|
||||
SamplerState image_sampler_0 : register(s0);
|
||||
SamplerState image_sampler_1 : register(s1);
|
||||
SamplerState image_sampler_2 : register(s2);
|
||||
SamplerState image_sampler_3 : register(s3);
|
||||
|
||||
float4 sample_texture(int texture_index, int sampler_index, float2 uv) {
|
||||
// I love hlsl
|
||||
if (sampler_index == 0) {
|
||||
if (texture_index == 0) return textures[0].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 1) return textures[1].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 2) return textures[2].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 3) return textures[3].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 4) return textures[4].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 5) return textures[5].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 6) return textures[6].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 7) return textures[7].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 8) return textures[8].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 9) return textures[9].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 10) return textures[10].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 11) return textures[11].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 12) return textures[12].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 13) return textures[13].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 14) return textures[14].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 15) return textures[15].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 16) return textures[16].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 17) return textures[17].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 18) return textures[18].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 19) return textures[19].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 20) return textures[20].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 21) return textures[21].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 22) return textures[22].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 23) return textures[23].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 24) return textures[24].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 25) return textures[25].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 26) return textures[26].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 27) return textures[27].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 28) return textures[28].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 29) return textures[29].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 30) return textures[30].Sample(image_sampler_0, uv);
|
||||
else if (texture_index == 31) return textures[31].Sample(image_sampler_0, uv);
|
||||
} else if (sampler_index == 1) {
|
||||
if (texture_index == 0) return textures[0].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 1) return textures[1].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 2) return textures[2].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 3) return textures[3].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 4) return textures[4].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 5) return textures[5].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 6) return textures[6].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 7) return textures[7].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 8) return textures[8].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 9) return textures[9].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 10) return textures[10].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 11) return textures[11].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 12) return textures[12].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 13) return textures[13].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 14) return textures[14].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 15) return textures[15].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 16) return textures[16].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 17) return textures[17].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 18) return textures[18].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 19) return textures[19].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 20) return textures[20].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 21) return textures[21].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 22) return textures[22].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 23) return textures[23].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 24) return textures[24].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 25) return textures[25].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 26) return textures[26].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 27) return textures[27].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 28) return textures[28].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 29) return textures[29].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 30) return textures[30].Sample(image_sampler_1, uv);
|
||||
else if (texture_index == 31) return textures[31].Sample(image_sampler_1, uv);
|
||||
} else if (sampler_index == 2) {
|
||||
if (texture_index == 0) return textures[0].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 1) return textures[1].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 2) return textures[2].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 3) return textures[3].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 4) return textures[4].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 5) return textures[5].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 6) return textures[6].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 7) return textures[7].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 8) return textures[8].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 9) return textures[9].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 10) return textures[10].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 11) return textures[11].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 12) return textures[12].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 13) return textures[13].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 14) return textures[14].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 15) return textures[15].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 16) return textures[16].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 17) return textures[17].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 18) return textures[18].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 19) return textures[19].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 20) return textures[20].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 21) return textures[21].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 22) return textures[22].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 23) return textures[23].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 24) return textures[24].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 25) return textures[25].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 26) return textures[26].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 27) return textures[27].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 28) return textures[28].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 29) return textures[29].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 30) return textures[30].Sample(image_sampler_2, uv);
|
||||
else if (texture_index == 31) return textures[31].Sample(image_sampler_2, uv);
|
||||
} else if (sampler_index == 3) {
|
||||
if (texture_index == 0) return textures[0].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 1) return textures[1].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 2) return textures[2].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 3) return textures[3].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 4) return textures[4].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 5) return textures[5].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 6) return textures[6].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 7) return textures[7].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 8) return textures[8].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 9) return textures[9].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 10) return textures[10].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 11) return textures[11].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 12) return textures[12].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 13) return textures[13].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 14) return textures[14].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 15) return textures[15].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 16) return textures[16].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 17) return textures[17].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 18) return textures[18].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 19) return textures[19].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 20) return textures[20].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 21) return textures[21].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 22) return textures[22].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 23) return textures[23].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 24) return textures[24].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 25) return textures[25].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 26) return textures[26].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 27) return textures[27].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 28) return textures[28].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 29) return textures[29].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 30) return textures[30].Sample(image_sampler_3, uv);
|
||||
else if (texture_index == 31) return textures[31].Sample(image_sampler_3, uv);
|
||||
}
|
||||
|
||||
return float4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
|
||||
\n
|
||||
|
||||
$INJECT_PIXEL_POST_PROCESS
|
||||
|
||||
\n
|
||||
\043define QUAD_TYPE_REGULAR 0\n
|
||||
\043define QUAD_TYPE_TEXT 1\n
|
||||
float4 ps_main(PS_INPUT input) : SV_TARGET
|
||||
{
|
||||
if (input.type == QUAD_TYPE_REGULAR) {
|
||||
if (input.texture_index >= 0 && input.texture_index < 32 && input.sampler_index >= 0 && input.sampler_index <= 3) {
|
||||
return pixel_shader_extension(input, sample_texture(input.texture_index, input.sampler_index, input.uv)*input.color);
|
||||
} else {
|
||||
return pixel_shader_extension(input, input.color);
|
||||
}
|
||||
} else if (input.type == QUAD_TYPE_TEXT) {
|
||||
if (input.texture_index >= 0 && input.texture_index < 32 && input.sampler_index >= 0 && input.sampler_index <= 3) {
|
||||
float alpha = sample_texture(input.texture_index, input.sampler_index, input.uv).x;
|
||||
return pixel_shader_extension(input, float4(1.0, 1.0, 1.0, alpha)*input.color);
|
||||
} else {
|
||||
return pixel_shader_extension(input, input.color);
|
||||
}
|
||||
}
|
||||
|
||||
return float4(0.0, 1.0, 0.0, 1.0);
|
||||
}
|
||||
);
|
|
@ -30,17 +30,27 @@ typedef struct Gfx_Image {
|
|||
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);
|
||||
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);
|
||||
|
||||
// Implemented per renderer
|
||||
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);
|
||||
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);
|
||||
|
||||
bool
|
||||
shader_recompile_with_extension(string ext_source, u64 cbuffer_size);
|
||||
|
||||
// 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 *
|
||||
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);
|
||||
|
@ -56,7 +66,8 @@ Gfx_Image *make_image(u32 width, u32 height, u32 channels, void *initial_data, A
|
|||
return image;
|
||||
}
|
||||
|
||||
Gfx_Image *load_image_from_disk(string path, Allocator allocator) {
|
||||
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;
|
||||
|
@ -92,7 +103,8 @@ Gfx_Image *load_image_from_disk(string path, Allocator allocator) {
|
|||
return image;
|
||||
}
|
||||
|
||||
void delete_image(Gfx_Image *image) {
|
||||
void
|
||||
delete_image(Gfx_Image *image) {
|
||||
// Free the image data allocated by stb_image
|
||||
image->width = 0;
|
||||
image->height = 0;
|
||||
|
|
|
@ -336,6 +336,9 @@ bool os_grow_program_memory(u64 new_size) {
|
|||
|
||||
memset(program_memory, 0xBA, program_memory_size);
|
||||
} else {
|
||||
// #Cleanup this mess
|
||||
// Allocation size doesn't actually need to be aligned to granularity, page size is enough.
|
||||
// Doesn't matter that much tho, but this is just a bit unfortunate to look at.
|
||||
void* tail = (u8*)program_memory + program_memory_size;
|
||||
u64 m = ((u64)program_memory_size % os.granularity);
|
||||
assert(m == 0, "program_memory_size is not aligned to granularity!");
|
||||
|
@ -780,6 +783,18 @@ os_file_get_size(File f) {
|
|||
return result;
|
||||
}
|
||||
|
||||
s64
|
||||
os_file_get_size_from_path(string path) {
|
||||
File f = os_file_open(path, O_READ);
|
||||
if (f == OS_INVALID_FILE) return -1;
|
||||
|
||||
s64 size = os_file_get_size(f);
|
||||
|
||||
os_file_close(f);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
s64 os_file_get_pos(File f) {
|
||||
LARGE_INTEGER pos = {0};
|
||||
LARGE_INTEGER new_pos;
|
||||
|
|
|
@ -155,6 +155,7 @@ bool os_file_set_pos(File f, s64 pos_in_bytes);
|
|||
s64 os_file_get_pos(File f);
|
||||
|
||||
s64 os_file_get_size(File f);
|
||||
s64 os_file_get_size_from_path(string path);
|
||||
|
||||
bool os_write_entire_file_handle(File f, string data);
|
||||
bool os_write_entire_file_s(string path, string data);
|
||||
|
@ -291,8 +292,8 @@ typedef struct Os_Window {
|
|||
string title;
|
||||
union { s32 width; s32 pixel_width; };
|
||||
union { s32 height; s32 pixel_height; };
|
||||
s32 scaled_width;
|
||||
s32 scaled_height;
|
||||
s32 scaled_width; // DPI scaled!
|
||||
s32 scaled_height; // DPI scaled!
|
||||
s32 x;
|
||||
s32 y;
|
||||
Vector4 clear_color;
|
||||
|
|
|
@ -17,7 +17,8 @@ const string null_string = {0, 0};
|
|||
#define fixed_string STR
|
||||
#define STR(s) ((string){ length_of_null_terminated_string((const char*)s), (u8*)s })
|
||||
|
||||
inline u64 length_of_null_terminated_string(const char* cstring) {
|
||||
inline u64
|
||||
length_of_null_terminated_string(const char* cstring) {
|
||||
u64 len = 0;
|
||||
while (*cstring != 0) {
|
||||
len += 1;
|
||||
|
@ -26,22 +27,26 @@ inline u64 length_of_null_terminated_string(const char* cstring) {
|
|||
return len;
|
||||
}
|
||||
|
||||
string alloc_string(Allocator allocator, u64 count) {
|
||||
string
|
||||
alloc_string(Allocator allocator, u64 count) {
|
||||
string s;
|
||||
s.count = count;
|
||||
s.data = cast(u8*)alloc(allocator, count);
|
||||
return s;
|
||||
}
|
||||
void dealloc_string(Allocator allocator, string s) {
|
||||
void
|
||||
dealloc_string(Allocator allocator, string s) {
|
||||
assert(s.count > 0 && s.data, "You tried to deallocate an empty string. That's doesn't make sense.");
|
||||
dealloc(allocator, s.data);
|
||||
}
|
||||
string talloc_string(u64 count) {
|
||||
string
|
||||
talloc_string(u64 count) {
|
||||
string s = alloc_string(temp, count);
|
||||
return s;
|
||||
}
|
||||
|
||||
string string_concat(const string left, const string right, Allocator allocator) {
|
||||
string
|
||||
string_concat(const string left, const string right, Allocator allocator) {
|
||||
|
||||
if (right.count + left.count == 0) return null_string;
|
||||
if (left.count == 0) return right;
|
||||
|
@ -54,18 +59,21 @@ string string_concat(const string left, const string right, Allocator allocator)
|
|||
memcpy(result.data+left.count, right.data, right.count);
|
||||
return result;
|
||||
}
|
||||
char *convert_to_null_terminated_string(const string s, Allocator allocator) {
|
||||
char *
|
||||
convert_to_null_terminated_string(const string s, Allocator allocator) {
|
||||
char *cstring = cast(char*)alloc(allocator, s.count+1);
|
||||
memcpy(cstring, s.data, s.count);
|
||||
cstring[s.count] = 0;
|
||||
return cstring;
|
||||
}
|
||||
|
||||
char *temp_convert_to_null_terminated_string(const string s) {
|
||||
char *
|
||||
temp_convert_to_null_terminated_string(const string s) {
|
||||
char *c = convert_to_null_terminated_string(s, temp);
|
||||
return c;
|
||||
}
|
||||
bool strings_match(string a, string b) {
|
||||
bool
|
||||
strings_match(string a, string b) {
|
||||
if (a.count != b.count) return false;
|
||||
|
||||
// Count match, pointer match: they are the same
|
||||
|
@ -74,7 +82,8 @@ bool strings_match(string a, string b) {
|
|||
return memcmp(a.data, b.data, a.count) == 0;
|
||||
}
|
||||
|
||||
string string_view(string s, u64 start_index, u64 count) {
|
||||
string
|
||||
string_view(string s, u64 start_index, u64 count) {
|
||||
assert(start_index < s.count, "array_view start_index % out of range for string count %", start_index, s.count);
|
||||
assert(count > 0, "array_view count must be more than 0");
|
||||
assert(start_index + count <= s.count, "array_view start_index + count is out of range");
|
||||
|
@ -87,7 +96,8 @@ string string_view(string s, u64 start_index, u64 count) {
|
|||
}
|
||||
|
||||
// Returns first index from left where "sub" matches in "s". Returns -1 if no match is found.
|
||||
s64 string_find_from_left(string s, string sub) {
|
||||
s64
|
||||
string_find_from_left(string s, string sub) {
|
||||
for (s64 i = 0; i <= s.count-sub.count; i++) {
|
||||
if (strings_match(string_view(s, i, sub.count), sub)) {
|
||||
return i;
|
||||
|
@ -98,7 +108,8 @@ s64 string_find_from_left(string s, string sub) {
|
|||
}
|
||||
|
||||
// Returns first index from right where "sub" matches in "s" Returns -1 if no match is found.
|
||||
s64 string_find_from_right(string s, string sub) {
|
||||
s64
|
||||
string_find_from_right(string s, string sub) {
|
||||
for (s64 i = s.count-sub.count; i >= 0 ; i--) {
|
||||
if (strings_match(string_view(s, i, sub.count), sub)) {
|
||||
return i;
|
||||
|
@ -108,10 +119,93 @@ s64 string_find_from_right(string s, string sub) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool string_starts_with(string s, string sub) {
|
||||
bool
|
||||
string_starts_with(string s, string sub) {
|
||||
if (s.count < sub.count) return false;
|
||||
|
||||
s.count = sub.count;
|
||||
|
||||
return strings_match(s, sub);
|
||||
}
|
||||
|
||||
string
|
||||
string_copy(string s, Allocator allocator) {
|
||||
string c = alloc_string(allocator, s.count);
|
||||
memcpy(c.data, s.data, s.count);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
typedef struct String_Builder {
|
||||
union {
|
||||
struct {u64 count;u8 *buffer;};
|
||||
string result;
|
||||
};
|
||||
u64 buffer_capacity;
|
||||
Allocator allocator;
|
||||
} String_Builder;
|
||||
|
||||
|
||||
void
|
||||
string_builder_reserve(String_Builder *b, u64 required_capacity) {
|
||||
if (b->buffer_capacity >= required_capacity) return;
|
||||
|
||||
u64 new_capacity = max(b->buffer_capacity*2, (u64)(required_capacity*1.5));
|
||||
u8 *new_buffer = alloc(b->allocator, new_capacity);
|
||||
if (b->buffer) {
|
||||
memcpy(new_buffer, b->buffer, b->count);
|
||||
dealloc(b->allocator, b->buffer);
|
||||
}
|
||||
b->buffer = new_buffer;
|
||||
b->buffer_capacity = new_capacity;
|
||||
}
|
||||
void
|
||||
string_builder_init_reserve(String_Builder *b, u64 reserved_capacity, Allocator allocator) {
|
||||
reserved_capacity = max(reserved_capacity, 128);
|
||||
b->allocator = allocator;
|
||||
b->buffer_capacity = 0;
|
||||
b->buffer = 0;
|
||||
string_builder_reserve(b, reserved_capacity);
|
||||
b->count = 0;
|
||||
}
|
||||
void
|
||||
string_builder_init(String_Builder *b, Allocator allocator) {
|
||||
string_builder_init_reserve(b, 128, allocator);
|
||||
}
|
||||
void
|
||||
string_builder_append(String_Builder *b, string s) {
|
||||
assert(b->allocator.proc, "String_Builder is missing allocator");
|
||||
string_builder_reserve(b, b->count+s.count);
|
||||
|
||||
memcpy(b->buffer+b->count, s.data, s.count);
|
||||
b->count += s.count;
|
||||
}
|
||||
string
|
||||
string_builder_get_string(String_Builder b) {
|
||||
return b.result;
|
||||
}
|
||||
|
||||
|
||||
string
|
||||
string_replace_all(string s, string old, string new, Allocator allocator) {
|
||||
|
||||
if (!s.data || !s.count) return string_copy(null_string, allocator);
|
||||
|
||||
String_Builder builder;
|
||||
string_builder_init_reserve(&builder, s.count, allocator);
|
||||
|
||||
while (s.count > 0) {
|
||||
if (s.count >= old.count && strings_match(string_view(s, 0, old.count), old)) {
|
||||
if (new.count != 0) string_builder_append(&builder, new);
|
||||
s.data += old.count;
|
||||
s.count -= old.count;
|
||||
} else {
|
||||
string_builder_append(&builder, string_view(s, 0, 1));
|
||||
s.data += 1;
|
||||
s.count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return string_builder_get_string(builder);
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ string tprintf(const char *fmt, ...) {
|
|||
return s;
|
||||
}
|
||||
|
||||
// print for 'string' and printf for 'char*'
|
||||
// prints for 'string' and printf for 'char*'
|
||||
|
||||
#define PRINT_BUFFER_SIZE 4096
|
||||
// Avoids all and any allocations but overhead in speed and memory.
|
||||
|
@ -231,47 +231,8 @@ typedef void(*Logger_Proc)(Log_Level level, string s);
|
|||
#define log(...) LOG_BASE(LOG_INFO, __VA_ARGS__)
|
||||
|
||||
|
||||
typedef struct String_Builder {
|
||||
union {
|
||||
struct {u64 count;u8 *buffer;};
|
||||
string result;
|
||||
};
|
||||
u64 buffer_capacity;
|
||||
Allocator allocator;
|
||||
} String_Builder;
|
||||
|
||||
|
||||
void string_builder_reserve(String_Builder *b, u64 required_capacity) {
|
||||
if (b->buffer_capacity >= required_capacity) return;
|
||||
|
||||
u64 new_capacity = max(b->buffer_capacity*2, (u64)(required_capacity*1.5));
|
||||
u8 *new_buffer = alloc(b->allocator, new_capacity);
|
||||
if (b->buffer) {
|
||||
memcpy(new_buffer, b->buffer, b->count);
|
||||
dealloc(b->allocator, b->buffer);
|
||||
}
|
||||
b->buffer = new_buffer;
|
||||
b->buffer_capacity = new_capacity;
|
||||
}
|
||||
void string_builder_init_reserve(String_Builder *b, u64 reserved_capacity, Allocator allocator) {
|
||||
reserved_capacity = max(reserved_capacity, 128);
|
||||
b->allocator = allocator;
|
||||
b->buffer_capacity = 0;
|
||||
b->buffer = 0;
|
||||
string_builder_reserve(b, reserved_capacity);
|
||||
b->count = 0;
|
||||
}
|
||||
void string_builder_init(String_Builder *b, Allocator allocator) {
|
||||
string_builder_init_reserve(b, 128, allocator);
|
||||
}
|
||||
void string_builder_append(String_Builder *b, string s) {
|
||||
assert(b->allocator.proc, "String_Builder is missing allocator");
|
||||
string_builder_reserve(b, b->count+s.count);
|
||||
|
||||
memcpy(b->buffer+b->count, s.data, s.count);
|
||||
b->count += s.count;
|
||||
}
|
||||
|
||||
void string_builder_prints(String_Builder *b, string fmt, ...) {
|
||||
assert(b->allocator.proc, "String_Builder is missing allocator");
|
||||
|
||||
|
@ -315,8 +276,3 @@ void string_builder_printf(String_Builder *b, const char *fmt, ...) {
|
|||
string: string_builder_prints, \
|
||||
default: string_builder_printf \
|
||||
)(__VA_ARGS__)
|
||||
|
||||
string string_builder_get_string(String_Builder *b) {
|
||||
return b->result;
|
||||
}
|
||||
|
||||
|
|
|
@ -395,7 +395,7 @@ void test_strings() {
|
|||
assert(memcmp(builder.buffer, expected_result, builder.count) == 0, "Failed: string_builder_printf");
|
||||
|
||||
// Test string_builder_get_string
|
||||
string result_str = string_builder_get_string(&builder);
|
||||
string result_str = string_builder_get_string(builder);
|
||||
assert(result_str.count == builder.count, "Failed: string_builder_get_string");
|
||||
assert(memcmp(result_str.data, builder.buffer, result_str.count) == 0, "Failed: string_builder_get_string");
|
||||
|
||||
|
@ -405,7 +405,7 @@ void test_strings() {
|
|||
// Test handling of empty builder
|
||||
String_Builder empty_builder;
|
||||
string_builder_init(&empty_builder, heap);
|
||||
result_str = string_builder_get_string(&empty_builder);
|
||||
result_str = string_builder_get_string(empty_builder);
|
||||
assert(result_str.count == 0, "Failed: empty builder handling");
|
||||
dealloc(heap, empty_builder.buffer);
|
||||
|
||||
|
@ -441,6 +441,15 @@ void test_strings() {
|
|||
assert(multi_append_builder.count == strlen(expected_result), "Failed: multiple appends");
|
||||
assert(memcmp(multi_append_builder.buffer, expected_result, multi_append_builder.count) == 0, "Failed: multiple appends");
|
||||
dealloc(heap, multi_append_builder.buffer);
|
||||
|
||||
|
||||
|
||||
string cheese_hello = STR("HeCHEESElloCHEESE, WorCHEESEld!");
|
||||
string hello = string_replace_all(cheese_hello, STR("CHEESE"), STR(""), heap);
|
||||
assert(strings_match(hello, STR("Hello, World!")), "Failed: string_replace");
|
||||
string hello_balls = string_replace_all(hello, STR("Hello"), STR("Greetings"), heap);
|
||||
hello_balls = string_replace_all(hello_balls, STR("World"), STR("Balls"), heap);
|
||||
assert(strings_match(hello_balls, STR("Greetings, Balls!")), "Failed: string_replace");
|
||||
}
|
||||
|
||||
void test_file_io() {
|
||||
|
|
Reference in a new issue