Compare commits

..

10 Commits

Author SHA1 Message Date
Krzosa Karol
c5cd43a594 Change file naming scheme 2022-08-05 23:42:30 +02:00
Krzosa Karol
ad5e9e867f Change file naming scheme 2022-08-05 23:40:44 +02:00
Krzosa Karol
178d5a756c Change file naming scheme 2022-08-05 23:40:02 +02:00
Krzosa Karol
fba01c6573 Change file naming scheme 2022-08-05 23:39:40 +02:00
Krzosa Karol
bb3723802a Fix include paths 2022-07-27 12:47:22 +02:00
Krzosa Karol
a4a1f290a8 Trying to fix github language statistics 2022-07-27 12:46:20 +02:00
Krzosa Karol
c67dd4754c Misc changes 2022-07-27 12:42:58 +02:00
Krzosa Karol
e6e9c6d10d Misc changes 2022-07-27 12:32:42 +02:00
Krzosa Karol
a9920bf142 Add base library 2022-07-27 12:30:56 +02:00
Krzosa Karol
00b030fd9f Update README 2022-07-27 12:27:31 +02:00
18 changed files with 7432 additions and 13 deletions

View File

@@ -1,6 +1,8 @@
# Realtime Software Renderer # Realtime Software Renderer
Optimized realtime software renderer. Renders Sponza Palace at 30FPS(on Ryzen 5800U), it was optimized using SIMD instructions and multithreading.
![screenshot1](assets/Screenshot1.png) ![screenshot1](assets/Screenshot1.png)
![screenshot2](assets/Screenshot2.png) ![screenshot2](assets/Screenshot2.png)
@@ -20,7 +22,7 @@ The inner loop of the rasterization is fully vectorized using AVX, AVX2 and FMA
## Multithreading ## Multithreading
Rendered image is split to tiles, each thread gets one tile to render. To synchronize work between threads a simple work queue is implemented. It only uses atomic operations and semaphores to distribute work. Work queue is implemented in one producer, multiple consumers architecture. Rendered image is split to tiles, each thread gets one tile to render. To synchronize work between threads a simple work queue is implemented. It only uses atomic operations and semaphores to distribute work. Work queue is implemented in one producer, multiple consumers architecture.
## Clipping ## Clipping
@@ -40,6 +42,20 @@ Last clipping stage is performed in the 2D image space. Every triangle has a cor
box. In this box every pixel gets tested to see if it's in the triangle. In this clipping stage box. In this box every pixel gets tested to see if it's in the triangle. In this clipping stage
the box is clipped to the image metrics - 0, 0, width, height. the box is clipped to the image metrics - 0, 0, width, height.
## Source reading guide
* main.cpp contains all the relevent drawing routines, including the optimized triangle rasterizing and other stuff like rendering text bitmaps
* base files act as a standard library
* base.cpp contains used data structures
* os_windows_base.cpp contains platform specific code that base partially depends on
* os_windows_multimedia.cpp deals with creating a window, creating a writable framebuffer etc.
## Building
1. Download Visual Studio and Clang
1. Run build.bat
1. Executable requires a specific Sponza obj + textures and it's not bundled with the repository, it's too big(500mb), repository is only for showcase, if someone actually wants to run this you can PM me but I doubt that anyone would want to run this...
### Things to do: ### Things to do:
- [x] Drawing triangles - [x] Drawing triangles
@@ -79,6 +95,7 @@ the box is clipped to the image metrics - 0, 0, width, height.
- [x] Simple test z clipping - [x] Simple test z clipping
- [x] Maybe should clip a triangle on znear zfar plane? - [x] Maybe should clip a triangle on znear zfar plane?
- [x] Maybe should clip out triangles that are fully z out before draw_triangle - [x] Maybe should clip out triangles that are fully z out before draw_triangle
- [ ] Proper infrustructure for transparent textures - sorting before rendering
- [ ] Effects!!! - [ ] Effects!!!
- [ ] Outlines - [ ] Outlines
- [ ] Lightning - [ ] Lightning

View File

@@ -1,4 +1,4 @@
#include "obj_dump.cpp" #include "assets_obj_dump.cpp"
function void function void
asset_log(Log_Kind kind, String string, char *file, int line){ asset_log(Log_Kind kind, String string, char *file, int line){

View File

@@ -1,9 +1,9 @@
#include "multimedia.cpp" #include "os_windows_multimedia.cpp"
#include "obj.cpp" #include "assets_obj.cpp"
#define STBI_ASSERT assert #define STBI_ASSERT assert
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h" #include "dependencies/stb_image.h"
enum class Obj_Token_Type { enum class Obj_Token_Type {
none, word, number, whitespace, end none, word, number, whitespace, end

1539
base.cpp Normal file

File diff suppressed because it is too large Load Diff

1712
base_math.cpp Normal file

File diff suppressed because it is too large Load Diff

476
base_string.cpp Normal file
View File

@@ -0,0 +1,476 @@
function U8
to_lower_case(U8 a) {
if (a >= 'A' && a <= 'Z')
a += 32;
return a;
}
function U8
to_upper_case(U8 a) {
if (a >= 'a' && a <= 'z')
a -= 32;
return a;
}
function U8
char_to_lower(U8 c){
if(c >= 'A' && c <= 'Z')
c += 32;
return c;
}
function U8
char_to_upper(U8 c){
if(c >= 'a' && c <= 'z')
c -= 32;
return c;
}
function B32
is_whitespace(U8 w) {
bool result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
return result;
}
function B32
is_alphabetic(U8 a) {
if ((a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z')) {
return true;
}
return false;
}
function B32
is_number(U8 a) {
B32 result = a >= '0' && a <= '9';
return result;
}
function B32
is_alphanumeric(U8 a) {
B32 result = is_number(a) || is_alphabetic(a);
return result;
}
function B32
string_compare(String a, String b, B32 ignore_case = false) {
if (a.len != b.len)
return false;
for (S64 i = 0; i < a.len; i++) {
U8 A = a.str[i];
U8 B = b.str[i];
if (ignore_case) {
A = to_lower_case(A);
B = to_lower_case(B);
}
if (A != B)
return false;
}
return true;
}
function B32
operator==(String a, String b){
return string_compare(a,b);
}
function String
string_copy(Allocator *a, String string){
U8 *copy = exp_alloc_array(a, U8, string.len+1);
memory_copy(copy, string.str, string.len);
copy[string.len] = 0;
return String{copy, string.len};
}
function String
string_fmtv(Allocator *a, const char *str, va_list args1) {
va_list args2;
va_copy(args2, args1);
S64 len = stbsp_vsnprintf(0, 0, str, args2);
va_end(args2);
char *result = exp_alloc_array(a, char, len + 1);
stbsp_vsnprintf(result, len + 1, str, args1);
String res = {(U8 *)result, len};
return res;
}
#define STRING_FMT(alloc, str, result) \
va_list args1; \
va_start(args1, str); \
String result = string_fmtv(alloc, str, args1); \
va_end(args1)
function String
string_fmt(Allocator *a, const char *str, ...) {
STRING_FMT(a, str, result);
return result;
}
//-----------------------------------------------------------------------------
// String builder
//-----------------------------------------------------------------------------
struct String_Builder_Block{
String_Builder_Block *next;
S64 cap;
S64 len;
U8 data[0];
};
struct String_Builder{
Allocator *allocator;
String_Builder_Block *first_free;
String_Builder_Block *first;
String_Builder_Block *last;
U64 di;
void reset(){
for(;;){
auto *block = first;
first = first->next;
block->next = first_free;
first_free = block;
if(!first) break;
}
last = 0;
assert(!last && !first);
}
void push_block(SizeU size){
String_Builder_Block *block = 0;
if(first_free){
block = first_free;
first_free = first_free->next;
} else{
block = (String_Builder_Block *)exp_alloc(allocator, sizeof(String_Builder_Block) + size);
}
memory_zero(block, sizeof(String_Builder_Block)+1); // Also clear first byte of character data
block->cap = size;
SLLQueuePush(first, last, block);
}
void init(S64 size = 4096){
assert(allocator);
push_block(size);
}
void append_data(void *data, S64 size){
if(first == 0){
init();
}
S64 remaining_cap = last->cap - last->len;
if(size > remaining_cap){
S64 new_block_size = max(last->cap*2, size*2);
push_block(new_block_size);
}
U8 *write_address = last->data + last->len;
last->len += size;
memory_copy(write_address, data, size);
}
void addf(const char *str, ...){
if(first == 0){
init();
}
va_list args, args2;
va_start(args, str);
retry:{
String_Builder_Block *block = last;
S64 block_size = block->cap - block->len;
char *write_address = (char *)block->data + block->len;
va_copy(args2, args);
int written = stbsp_vsnprintf(write_address, block_size, str, args2);
va_end(args2);
if(written > (block_size-1)){
S64 new_block_size = max(4096, (written+1)*2);
push_block(new_block_size);
goto retry;
}
block->len += written;
}
va_end(args);
di++;
}
};
function String_Builder
string_builder_make(Allocator *a, S64 first_block_size = 4096){
String_Builder sb = {a};
sb.init(first_block_size);
return sb;
}
enum String_Builder_Flag{
String_Builder_Flag_None = 0,
String_Builder_Flag_AddSize = 0,
};
function String
string_flatten(Allocator *a, String_Builder *b, String_Builder_Flag flags = String_Builder_Flag_None){
// @Note(Krzosa): Compute size to allocate
S64 size = 1;
if(is_flag_set(flags, String_Builder_Flag_AddSize)) size += sizeof(SizeU);
For_List(b->first){
size += it->len;
}
String result = {};
result.str = (U8 *)exp_alloc(a, size);
if(is_flag_set(flags, String_Builder_Flag_AddSize)) {
memory_copy(result.str + result.len, &size, sizeof(S64));
result.len += sizeof(S64);
}
// @Note(Krzosa): Copy the content of each block into the string
For_List(b->first){
memory_copy(result.str + result.len, it->data, it->len);
result.len += it->len;
}
result.str[result.len] = 0;
return result;
}
function void
test_string_builder(){
Scratch scratch;
String_Builder sb = string_builder_make(scratch, 4);
sb.addf("Thing, %d", 242252);
String f = string_flatten(scratch, &sb);
assert(string_compare(f, "Thing, 242252"_s));
sb.addf("-%f %f %f", 23.0, 42.29, 2925.2);
f = string_flatten(scratch, &sb);
sb.reset();
}
//-----------------------------------------------------------------------------
// String ops
//-----------------------------------------------------------------------------
function void
string_path_normalize(String s) {
for (S64 i = 0; i < s.len; i++) {
if (s.str[i] == '\\')
s.str[i] = '/';
}
}
function String
string_make(char *str, S64 len) {
String result;
result.str = (U8 *)str;
result.len = len;
return result;
}
function String
string_make(U8 *str, S64 len) {
return string_make((char*)str, len);
}
function String
string_chop(String string, S64 len) {
len = clamp_top(len, string.len);
String result = string_make(string.str, string.len - len);
return result;
}
function String
string_skip(String string, S64 len) {
len = clamp_top(len, string.len);
S64 remain = string.len - len;
String result = string_make(string.str + len, remain);
return result;
}
function String
string_get_postfix(String string, S64 len) {
len = clamp_top(len, string.len);
S64 remain_len = string.len - len;
String result = string_make(string.str + remain_len, len);
return result;
}
function String
string_get_prefix(String string, S64 len) {
len = clamp_top(len, string.len);
String result = string_make(string.str, len);
return result;
}
function String
string_slice(String string, S64 first_index, S64 one_past_last_index) {
assert_msg(first_index < one_past_last_index, "string_slice, first_index is bigger then one_past_last_index");
assert_msg(string.len > 0, "Slicing string of length 0! Might be an error!");
String result = string;
if (string.len > 0) {
if (one_past_last_index > first_index) {
first_index = clamp_top(first_index, string.len - 1);
one_past_last_index = clamp_top(one_past_last_index, string.len);
result.str += first_index;
result.len = one_past_last_index - first_index;
}
else {
result.len = 0;
}
}
return result;
}
function String
string_trim(String string) {
if (string.len == 0) return string;
S64 whitespace_begin = 0;
for (; whitespace_begin < string.len; whitespace_begin++) {
if (!is_whitespace(string.str[whitespace_begin])) {
break;
}
}
S64 whitespace_end = string.len;
for (; whitespace_end != whitespace_begin; whitespace_end--) {
if (!is_whitespace(string.str[whitespace_end - 1])) {
break;
}
}
if (whitespace_begin == whitespace_end) {
string.len = 0;
}
else {
string = string_slice(string, whitespace_begin, whitespace_end);
}
return string;
}
function String
string_trim_end(String string) {
S64 whitespace_end = string.len;
for (; whitespace_end != 0; whitespace_end--) {
if (!is_whitespace(string.str[whitespace_end - 1])) {
break;
}
}
String result = string_get_prefix(string, whitespace_end);
return result;
}
function String
string_to_lower_case(Allocator *arena, String s) {
String copy = string_copy(arena, s);
for (U64 i = 0; i < copy.len; i++) {
copy.str[i] = to_lower_case(copy.str[i]);
}
return copy;
}
function String
string_to_upper_case(Allocator *arena, String s) {
String copy = string_copy(arena, s);
for (U64 i = 0; i < copy.len; i++) {
copy.str[i] = to_upper_case(copy.str[i]);
}
return copy;
}
FLAG32(MatchFlag){
MatchFlag_None=0,
MatchFlag_FindLast=1,
MatchFlag_IgnoreCase=2,
};
function B32
string_find(String string, String find, MatchFlag flags, S64 *index_out) {
B32 result = false;
if (flags & MatchFlag_FindLast) {
for (S64 i = string.len; i != 0; i--) {
S64 index = i - 1;
String substring = string_slice(string, index, index + find.len);
if (string_compare(substring, find, flags & MatchFlag_IgnoreCase)) {
if (index_out)
*index_out = index;
result = true;
break;
}
}
}
else {
for (S64 i = 0; i < string.len; i++) {
String substring = string_slice(string, i, i + find.len);
if (string_compare(substring, find, flags & MatchFlag_IgnoreCase)) {
if (index_out)
*index_out = i;
result = true;
break;
}
}
}
return result;
}
function String
string_chop_last_slash(String s) {
String result = s;
string_find(s, "/"_s, MatchFlag_FindLast, &result.len);
return result;
}
function String
string_chop_last_period(String s) {
String result = s;
string_find(s, "."_s, MatchFlag_FindLast, &result.len);
return result;
}
function String
string_skip_to_last_slash(String s) {
S64 pos;
String result = s;
if (string_find(s, "/"_s, MatchFlag_FindLast, &pos)) {
result = string_skip(result, pos + 1);
}
return result;
}
function String
string_skip_to_last_period(String s) {
S64 pos;
String result = s;
if (string_find(s, "."_s, MatchFlag_FindLast, &pos)) {
result = string_skip(result, pos + 1);
}
return result;
}
function S64
string_len(char *string){
S64 len = 0;
while(*string++!=0)len++;
return len;
}
function String
string_from_cstring(char *string){
String result;
result.str = (U8 *)string;
result.len = string_len(string);
return result;
}

379
base_unicode.cpp Normal file
View File

@@ -0,0 +1,379 @@
global U32 question_mark32 = '?';
global U16 question_mark16 = 0x003f;
global U8 question_mark8 = '?';
struct String32{
U32 *str;
S64 len;
};
struct UTF32_Result{
U32 out_str;
S64 advance;
B32 error;
};
function UTF32_Result
utf8_to_utf32(U8 *c, S64 max_advance) {
UTF32_Result result = {};
if ((c[0] & 0b10000000) == 0) { // Check if leftmost zero of first byte is unset
if(max_advance >= 1){
result.out_str = c[0];
result.advance = 1;
}
else result.error = 1;
}
else if ((c[0] & 0b11100000) == 0b11000000) {
if ((c[1] & 0b11000000) == 0b10000000) { // Continuation byte required
if(max_advance >= 2){
result.out_str = (U32)(c[0] & 0b00011111) << 6u | (c[1] & 0b00111111);
result.advance = 2;
}
else result.error = 2;
}
else result.error = 2;
}
else if ((c[0] & 0b11110000) == 0b11100000) {
if ((c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000) { // Two continuation bytes required
if(max_advance >= 3){
result.out_str = (U32)(c[0] & 0b00001111) << 12u | (U32)(c[1] & 0b00111111) << 6u | (c[2] & 0b00111111);
result.advance = 3;
}
else result.error = 3;
}
else result.error = 3;
}
else if ((c[0] & 0b11111000) == 0b11110000) {
if ((c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000 && (c[3] & 0b11000000) == 0b10000000) { // Three continuation bytes required
if(max_advance >= 4){
result.out_str = (U32)(c[0] & 0b00001111) << 18u | (U32)(c[1] & 0b00111111) << 12u | (U32)(c[2] & 0b00111111) << 6u | (U32)(c[3] & 0b00111111);
result.advance = 4;
}
else result.error = 4;
}
else result.error = 4;
}
else result.error = 4;
return result;
}
struct String16{
U16 *str;
S64 len;
};
struct UTF16_Result{
U16 out_str[2];
S32 len;
B32 error;
};
function UTF16_Result
utf32_to_utf16(U32 codepoint){
UTF16_Result result = {};
if (codepoint < 0x10000) {
result.out_str[0] = (U16)codepoint;
result.out_str[1] = 0;
result.len = 1;
}
else if (codepoint <= 0x10FFFF) {
U32 code = (codepoint - 0x10000);
result.out_str[0] = (U16)(0xD800 | (code >> 10));
result.out_str[1] = (U16)(0xDC00 | (code & 0x3FF));
result.len = 2;
}
else{
result.error = 1;
}
return result;
}
struct UTF8_Result{
U8 out_str[4];
S32 len;
B32 error;
};
function UTF8_Result
utf32_to_utf8(U32 codepoint) {
UTF8_Result result = {};
if (codepoint <= 0x7F) {
result.len = 1;
result.out_str[0] = (U8)codepoint;
}
else if (codepoint <= 0x7FF) {
result.len= 2;
result.out_str[0] = 0b11000000 | (0b00011111 & (codepoint >> 6));
result.out_str[1] = 0b10000000 | (0b00111111 & codepoint);
}
else if (codepoint <= 0xFFFF) { // 16 bit word
result.len= 3;
result.out_str[0] = 0b11100000 | (0b00001111 & (codepoint >> 12)); // 4 bits
result.out_str[1] = 0b10000000 | (0b00111111 & (codepoint >> 6)); // 6 bits
result.out_str[2] = 0b10000000 | (0b00111111 & codepoint); // 6 bits
}
else if (codepoint <= 0x10FFFF) { // 21 bit word
result.len= 4;
result.out_str[0] = 0b11110000 | (0b00000111 & (codepoint >> 18)); // 3 bits
result.out_str[1] = 0b10000000 | (0b00111111 & (codepoint >> 12)); // 6 bits
result.out_str[2] = 0b10000000 | (0b00111111 & (codepoint >> 6)); // 6 bits
result.out_str[3] = 0b10000000 | (0b00111111 & codepoint); // 6 bits
}
else{
result.error = true;
}
return result;
}
function UTF32_Result
utf16_to_utf32(U16 *c, S32 max_advance) {
UTF32_Result result = {};
if(max_advance >= 1){
result.advance = 1;
result.out_str = c[0];
if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF) {
if(max_advance >= 2){
result.out_str = 0x10000;
result.out_str += (U32)(c[0] & 0x03FF) << 10u | (c[1] & 0x03FF);
result.advance = 2;
}
else result.error = 2;
}
}
else result.error = 1;
return result;
}
#define unicode_error(question_mark) \
{ \
result.str[result.len++] = question_mark; \
break; \
}
function String32
string16_to_string32(Allocator *allocator, String16 string){
String32 result = {exp_alloc_array(allocator, U32, string.len+1)};
for(S64 i = 0; i < string.len;){
UTF32_Result decode = utf16_to_utf32(string.str + i, string.len - i);
if(!decode.error){
i += decode.advance;
result.str[result.len++] = decode.out_str;
}
else unicode_error(question_mark32);
}
result.str[result.len] = 0;
return result;
}
function String32
string8_to_string32(Allocator *allocator, String string){
String32 result = {exp_alloc_array(allocator, U32, string.len+1)};
for(S64 i = 0; i < string.len;){
UTF32_Result decode = utf8_to_utf32(string.str + i, string.len - i);
if(!decode.error){
i += decode.advance;
result.str[result.len++] = decode.out_str;
}
else unicode_error(question_mark32);
}
result.str[result.len] = 0;
return result;
}
function String16
string8_to_string16(Allocator *allocator, String in){
String16 result = {exp_alloc_array(allocator, U16, (in.len*2)+1)}; // @Note(Krzosa): Should be more then enough space
for(S64 i = 0; i < in.len;){
UTF32_Result decode = utf8_to_utf32(in.str + i, in.len - i);
if(!decode.error){
i += decode.advance;
UTF16_Result encode = utf32_to_utf16(decode.out_str);
if(!encode.error){
for(S32 j = 0; j < encode.len; j++){
result.str[result.len++] = encode.out_str[j];
}
}
else unicode_error(question_mark16);
}
else unicode_error(question_mark16);
}
result.str[result.len] = 0;
return result;
}
function String
string16_to_string8(Allocator *allocator, String16 in){
String result = {exp_alloc_array(allocator, U8, in.len*4+1)};
for(S64 i = 0; i < in.len;){
UTF32_Result decode = utf16_to_utf32(in.str + i, in.len - i);
if(!decode.error){
i += decode.advance;
UTF8_Result encode = utf32_to_utf8(decode.out_str);
if(!encode.error){
for(S32 j = 0; j < encode.len; j++)
result.str[result.len++] = encode.out_str[j];
}
else unicode_error(question_mark8);
}
else unicode_error(question_mark8);
}
result.str[result.len] = 0;
return result;
}
function B32
string_compare(String16 a, String16 b){
if(a.len != b.len) return false;
for(S64 i = 0; i < a.len; i++){
if(a.str[i] != b.str[i]) return false;
}
return true;
}
function B32
string_compare(String32 a, String32 b){
if(a.len != b.len) return false;
for(S64 i = 0; i < a.len; i++){
if(a.str[i] != b.str[i]) return false;
}
return true;
}
function S64
widechar_len(wchar_t *string){
S64 len = 0;
while(*string++!=0)len++;
return len;
}
function String16
string16_from_widechar(wchar_t *string){
String16 result;
result.str = (U16 *)string;
result.len = widechar_len(string);
return result;
}
function String
string16_copy(Allocator *a, String string){
U8 *copy = exp_alloc_array(a, U8, string.len+1);
memory_copy(copy, string.str, string.len);
copy[string.len] = 0;
return String{copy, string.len};
}
function void
test_unicode(){
assert(utf8_to_utf32((U8 *)"A", 1).out_str == 'A');
assert(utf8_to_utf32((U8 *)"ć", 2).out_str == 0x107);
assert(utf8_to_utf32((U8 *)"ó", 2).out_str == 0x000000f3);
Scratch scratch;
String32 result = string8_to_string32(scratch, "Thing"_s);
assert(result.len == 5);
assert(result.str[0] == 'T');
assert(result.str[4] == 'g');
result = string8_to_string32(scratch, "óźćłŁQ42-=?"_s);
{
U16 u16_code[] = {0x0054, 0x0068, 0x0069, 0x006e, 0x0067, 0x0020, 0x0069, 0x0073};
String16 thing_is16 = {u16_code, buff_cap(u16_code)};
String string = "Thing is"_s;
String16 thing_is_convert = string8_to_string16(scratch, string);
assert(string_compare(thing_is16, thing_is_convert));
String32 a = string16_to_string32(scratch, thing_is16);
String32 b = string16_to_string32(scratch, thing_is_convert);
String32 c = string8_to_string32 (scratch, string);
assert(string_compare(a, b) && string_compare(b,c));
}
{
U16 code[] = {0x015a, 0x0104, 0x00f3, 0x015b, 0x017a, 0x0107, 0x0144, 0x0143, 0x0119, 0x00f3};
String16 code_str = {code, buff_cap(code)};
String string = "ŚĄóśźćńŃęó"_s;
String16 convert = string8_to_string16(scratch, string);
assert(string_compare(convert, code_str));
String32 a = string16_to_string32(scratch, code_str);
String32 b = string16_to_string32(scratch, convert);
String32 c = string8_to_string32 (scratch, string);
assert(string_compare(a, b) && string_compare(b,c));
}
{
String str = " ഃ അ ആ ഇ ഈ ഉ ഊ ഋ ഌ എ ഏ ഐ ഒ ഓ ഔ ക ഖ ഗ ഘ ങ ച ഛ ജ ഝ ഞ ട ഡ ഢ ണ ത ഥ ദ ധ ന പ ഫ ബ ഭ മ യ ര റ ല ള ഴ വ ശ ഷ സ ഹ ാ ി ീ ു ൂ ൃ െ േ ൈ ൊ ോ ൌ ് ൗ ൠ ൡ ൧ ൨ ൩ ൪ ൫ ൬ ൮ ൯ "_s;
U16 arr[] = {0x0020, 0x0020, 0x0020, 0x0020, 0x0d02, 0x0020, 0x0d03, 0x0020, 0x0d05, 0x0020, 0x0d06, 0x0020, 0x0d07, 0x0020, 0x0d08, 0x0020, 0x0d09, 0x0020, 0x0d0a, 0x0020, 0x0d0b, 0x0020, 0x0d0c, 0x0020, 0x0d0e, 0x0020, 0x0d0f, 0x0020, 0x0d10, 0x0020, 0x0d12, 0x0020, 0x0d13, 0x0020, 0x0d14, 0x0020, 0x0d15, 0x0020, 0x0d16, 0x0020, 0x0d17, 0x0020, 0x0d18, 0x0020, 0x0d19, 0x0020, 0x0d1a, 0x0020, 0x0d1b, 0x0020, 0x0d1c, 0x0020, 0x0d1d, 0x0020, 0x0d1e, 0x0020, 0x0d1f, 0x0020, 0x0d20, 0x0020, 0x0d21, 0x0020, 0x0d22, 0x0020, 0x0d23, 0x0020, 0x0d24, 0x0020, 0x0d25, 0x0020, 0x0d26, 0x0020, 0x0d27, 0x0020, 0x0d28, 0x0020, 0x0d2a, 0x0020, 0x0d2b, 0x0020, 0x0d2c, 0x0020, 0x0d2d, 0x0020, 0x0d2e, 0x0020, 0x0d2f, 0x0020, 0x0d30, 0x0020, 0x0d31, 0x0020, 0x0d32, 0x0020, 0x0d33, 0x0020, 0x0d34, 0x0020, 0x0d35, 0x0020, 0x0d36, 0x0020, 0x0d37, 0x0020, 0x0d38, 0x0020, 0x0d39, 0x0020, 0x0d3e, 0x0020, 0x0d3f, 0x0020, 0x0d40, 0x0020, 0x0d41, 0x0020, 0x0d42, 0x0020, 0x0d43, 0x0020, 0x0d46, 0x0020, 0x0d47, 0x0020, 0x0d48, 0x0020, 0x0d4a, 0x0020, 0x0d4b, 0x0020, 0x0d4c, 0x0020, 0x0d4d, 0x0020, 0x0d57, 0x0020, 0x0d60, 0x0020, 0x0d61, 0x0020, 0x0d66, 0x0020, 0x0d67, 0x0020, 0x0d68, 0x0020, 0x0d69, 0x0020, 0x0d6a, 0x0020, 0x0d6b, 0x0020, 0x0d6c, 0x0020, 0x0d6d, 0x0020, 0x0d6e, 0x0020, 0x0d6f, 0x0020};
String16 a = {arr, buff_cap(arr)};
String16 b = string8_to_string16(scratch, str);
assert(string_compare(a,b));
String32 c = string16_to_string32(scratch, a);
String32 d = string16_to_string32(scratch, b);
assert(string_compare(c,d));
String e = string16_to_string8(scratch, a);
String f = string16_to_string8(scratch, b);
assert(string_compare(e,f));
}
{
String str = " 豈 更 車 賈 滑 串 句 龜 龜 契 金 喇 奈 懶 癩 羅 蘿 螺 裸 邏 樂 洛 烙 珞 落 酪 駱 亂 卵 欄 爛 蘭 鸞 嵐 濫 藍 襤 拉 臘 蠟 廊 朗 浪 狼 郎 來 冷 勞 擄 櫓 爐 盧 老 蘆 虜 路 露 魯 鷺 碌 祿 綠 菉 錄 鹿 論 壟 弄 籠 聾 牢 磊 賂 雷 壘 屢 樓 淚 漏 累 縷 陋 勒 肋 凜 凌 稜 綾 菱 陵 讀 拏 樂 諾 丹 寧 怒 率 異 北 磻 便 復 不 泌 數 索 參 塞 省 葉 說 殺 辰 沈 拾 若 掠 略 亮 兩 凉 梁 糧 良 諒 量 勵 ..."_s;
U16 arr[] = {0x0020, 0x0020, 0x0020, 0x0020, 0xf900, 0x0020, 0xf901, 0x0020, 0xf902, 0x0020, 0xf903, 0x0020, 0xf904, 0x0020, 0xf905, 0x0020, 0xf906, 0x0020, 0xf907, 0x0020, 0xf908, 0x0020, 0xf909, 0x0020, 0xf90a, 0x0020, 0xf90b, 0x0020, 0xf90c, 0x0020, 0xf90d, 0x0020, 0xf90e, 0x0020, 0xf90f, 0x0020, 0xf910, 0x0020, 0xf911, 0x0020, 0xf912, 0x0020, 0xf913, 0x0020, 0xf914, 0x0020, 0xf915, 0x0020, 0xf916, 0x0020, 0xf917, 0x0020, 0xf918, 0x0020, 0xf919, 0x0020, 0xf91a, 0x0020, 0xf91b, 0x0020, 0xf91c, 0x0020, 0xf91d, 0x0020, 0xf91e, 0x0020, 0xf91f, 0x0020, 0xf920, 0x0020, 0xf921, 0x0020, 0xf922, 0x0020, 0xf923, 0x0020, 0xf924, 0x0020, 0xf925, 0x0020, 0xf926, 0x0020, 0xf927, 0x0020, 0xf928, 0x0020, 0xf929, 0x0020, 0xf92a, 0x0020, 0xf92b, 0x0020, 0xf92c, 0x0020, 0xf92d, 0x0020, 0xf92e, 0x0020, 0xf92f, 0x0020, 0xf930, 0x0020, 0xf931, 0x0020, 0xf932, 0x0020, 0xf933, 0x0020, 0xf934, 0x0020, 0xf935, 0x0020, 0xf936, 0x0020, 0xf937, 0x0020, 0xf938, 0x0020, 0xf939, 0x0020, 0xf93a, 0x0020, 0xf93b, 0x0020, 0xf93c, 0x0020, 0xf93d, 0x0020, 0xf93e, 0x0020, 0xf93f, 0x0020, 0xf940, 0x0020, 0xf941, 0x0020, 0xf942, 0x0020, 0xf943, 0x0020, 0xf944, 0x0020, 0xf945, 0x0020, 0xf946, 0x0020, 0xf947, 0x0020, 0xf948, 0x0020, 0xf949, 0x0020, 0xf94a, 0x0020, 0xf94b, 0x0020, 0xf94c, 0x0020, 0xf94d, 0x0020, 0xf94e, 0x0020, 0xf94f, 0x0020, 0xf950, 0x0020, 0xf951, 0x0020, 0xf952, 0x0020, 0xf953, 0x0020, 0xf954, 0x0020, 0xf955, 0x0020, 0xf956, 0x0020, 0xf957, 0x0020, 0xf958, 0x0020, 0xf959, 0x0020, 0xf95a, 0x0020, 0xf95b, 0x0020, 0xf95c, 0x0020, 0xf95d, 0x0020, 0xf95e, 0x0020, 0xf95f, 0x0020, 0xf960, 0x0020, 0xf961, 0x0020, 0xf962, 0x0020, 0xf963, 0x0020, 0xf964, 0x0020, 0xf965, 0x0020, 0xf966, 0x0020, 0xf967, 0x0020, 0xf968, 0x0020, 0xf969, 0x0020, 0xf96a, 0x0020, 0xf96b, 0x0020, 0xf96c, 0x0020, 0xf96d, 0x0020, 0xf96e, 0x0020, 0xf96f, 0x0020, 0xf970, 0x0020, 0xf971, 0x0020, 0xf972, 0x0020, 0xf973, 0x0020, 0xf974, 0x0020, 0xf975, 0x0020, 0xf976, 0x0020, 0xf977, 0x0020, 0xf978, 0x0020, 0xf979, 0x0020, 0xf97a, 0x0020, 0xf97b, 0x0020, 0xf97c, 0x0020, 0xf97d, 0x0020, 0xf97e, 0x0020, 0xf97f, 0x0020, 0x002e, 0x002e, 0x002e};
String16 a = {arr, buff_cap(arr)};
String16 b = string8_to_string16(scratch, str);
assert(string_compare(a,b));
String32 c = string16_to_string32(scratch, a);
String32 d = string16_to_string32(scratch, b);
assert(string_compare(c,d));
String e = string16_to_string8(scratch, a);
String f = string16_to_string8(scratch, b);
assert(string_compare(e,f));
}
{
String str = " _ 。 「 」 、 ・ ヲ ァ ィ ゥ ェ ォ ャ ュ ョ ッ ー ア イ ウ エ オ カ キ ク ケ コ サ シ ス セ ソ タ チ ツ ... "_s;
U16 arr[] = {0x0020, 0x0020, 0x0020, 0x0020, 0xff01, 0x0020, 0xff02, 0x0020, 0xff03, 0x0020, 0xff04, 0x0020, 0xff05, 0x0020, 0xff06, 0x0020, 0xff07, 0x0020, 0xff08, 0x0020, 0xff09, 0x0020, 0xff0a, 0x0020, 0xff0b, 0x0020, 0xff0c, 0x0020, 0xff0d, 0x0020, 0xff0e, 0x0020, 0xff0f, 0x0020, 0xff10, 0x0020, 0xff11, 0x0020, 0xff12, 0x0020, 0xff13, 0x0020, 0xff14, 0x0020, 0xff15, 0x0020, 0xff16, 0x0020, 0xff17, 0x0020, 0xff18, 0x0020, 0xff19, 0x0020, 0xff1a, 0x0020, 0xff1b, 0x0020, 0xff1c, 0x0020, 0xff1d, 0x0020, 0xff1e, 0x0020, 0xff1f, 0x0020, 0xff20, 0x0020, 0xff21, 0x0020, 0xff22, 0x0020, 0xff23, 0x0020, 0xff24, 0x0020, 0xff25, 0x0020, 0xff26, 0x0020, 0xff27, 0x0020, 0xff28, 0x0020, 0xff29, 0x0020, 0xff2a, 0x0020, 0xff2b, 0x0020, 0xff2c, 0x0020, 0xff2d, 0x0020, 0xff2e, 0x0020, 0xff2f, 0x0020, 0xff30, 0x0020, 0xff31, 0x0020, 0xff32, 0x0020, 0xff33, 0x0020, 0xff34, 0x0020, 0xff35, 0x0020, 0xff36, 0x0020, 0xff37, 0x0020, 0xff38, 0x0020, 0xff39, 0x0020, 0xff3a, 0x0020, 0xff3b, 0x0020, 0xff3c, 0x0020, 0xff3d, 0x0020, 0xff3e, 0x0020, 0xff3f, 0x0020, 0xff40, 0x0020, 0xff41, 0x0020, 0xff42, 0x0020, 0xff43, 0x0020, 0xff44, 0x0020, 0xff45, 0x0020, 0xff46, 0x0020, 0xff47, 0x0020, 0xff48, 0x0020, 0xff49, 0x0020, 0xff4a, 0x0020, 0xff4b, 0x0020, 0xff4c, 0x0020, 0xff4d, 0x0020, 0xff4e, 0x0020, 0xff4f, 0x0020, 0xff50, 0x0020, 0xff51, 0x0020, 0xff52, 0x0020, 0xff53, 0x0020, 0xff54, 0x0020, 0xff55, 0x0020, 0xff56, 0x0020, 0xff57, 0x0020, 0xff58, 0x0020, 0xff59, 0x0020, 0xff5a, 0x0020, 0xff5b, 0x0020, 0xff5c, 0x0020, 0xff5d, 0x0020, 0xff5e, 0x0020, 0xff61, 0x0020, 0xff62, 0x0020, 0xff63, 0x0020, 0xff64, 0x0020, 0xff65, 0x0020, 0xff66, 0x0020, 0xff67, 0x0020, 0xff68, 0x0020, 0xff69, 0x0020, 0xff6a, 0x0020, 0xff6b, 0x0020, 0xff6c, 0x0020, 0xff6d, 0x0020, 0xff6e, 0x0020, 0xff6f, 0x0020, 0xff70, 0x0020, 0xff71, 0x0020, 0xff72, 0x0020, 0xff73, 0x0020, 0xff74, 0x0020, 0xff75, 0x0020, 0xff76, 0x0020, 0xff77, 0x0020, 0xff78, 0x0020, 0xff79, 0x0020, 0xff7a, 0x0020, 0xff7b, 0x0020, 0xff7c, 0x0020, 0xff7d, 0x0020, 0xff7e, 0x0020, 0xff7f, 0x0020, 0xff80, 0x0020, 0xff81, 0x0020, 0xff82, 0x0020, 0x002e, 0x002e, 0x002e, 0x0020};
String16 a = {arr, buff_cap(arr)};
String16 b = string8_to_string16(scratch, str);
assert(string_compare(a,b));
String32 c = string16_to_string32(scratch, a);
String32 d = string16_to_string32(scratch, b);
assert(string_compare(c,d));
String e = string16_to_string8(scratch, a);
String f = string16_to_string8(scratch, b);
assert(string_compare(e,f));
}
{ // With surrogate pairs
U8 arr8[] = {0xf0, 0x90, 0x90, 0x90, 0xf0, 0x90, 0x90, 0x91};
String str = {arr8, buff_cap(arr8)};
U16 arr[] = {0xd801, 0xdc10, 0xd801, 0xdc11};
String16 a = {arr, buff_cap(arr)};
String16 b = string8_to_string16(scratch, str);
assert(string_compare(a,b));
String32 c = string16_to_string32(scratch, a);
String32 d = string16_to_string32(scratch, b);
assert(string_compare(c,d));
String e = string16_to_string8(scratch, a);
String f = string16_to_string8(scratch, b);
assert(string_compare(e,f));
}
}

View File

@@ -1,5 +1,5 @@
@echo off @echo off
pushd %~dp0 pushd %~dp0
clang main.cpp -O2 -mfma -mavx2 -Wall -Wno-unused-function -Wno-missing-braces -fno-exceptions -fdiagnostics-absolute-paths -Wno-deprecated-declarations -I".." -g -o main.exe -Wl,user32.lib clang sf_main.cpp -O2 -mfma -mavx2 -Wall -Wno-unused-function -Wno-missing-braces -fno-exceptions -fdiagnostics-absolute-paths -Wno-deprecated-declarations -g -o main.exe -Wl,user32.lib
popd popd

1921
dependencies/stb_sprintf.h vendored Normal file

File diff suppressed because it is too large Load Diff

249
os_windows_base.cpp Normal file
View File

@@ -0,0 +1,249 @@
//-----------------------------------------------------------------------------
// Memory
//-----------------------------------------------------------------------------
const SizeU os_page_size = 4096;
function OS_Memory
os_reserve(SizeU size){
OS_Memory result = {};
SizeU adjusted_size = align_up(size, os_page_size);
result.data = (U8*)VirtualAlloc(0, adjusted_size, MEM_RESERVE, PAGE_READWRITE);
assert_msg(result.data, "Failed to reserve virtual memory");
result.reserve = adjusted_size;
return result;
}
function B32
os_commit(OS_Memory *m, SizeU size){
SizeU commit = align_up(size, os_page_size);
SizeU total_commit = m->commit + commit;
total_commit = clamp_top(total_commit, m->reserve);
SizeU adjusted_commit = total_commit - m->commit;
if(adjusted_commit != 0){
void *result = VirtualAlloc((U8*)m->data + m->commit, adjusted_commit, MEM_COMMIT, PAGE_READWRITE);
assert_msg(result, "Failed to commit more memory");
m->commit += adjusted_commit;
return true;
}
return false;
}
function void
os_release(OS_Memory *m){
BOOL result = VirtualFree(m->data, 0, MEM_RELEASE);
assert_msg(result != 0, "Failed to release OS_Memory");
if(result){
m->data = 0;
m->commit = 0;
m->reserve = 0;
}
}
function B32
os_decommit_pos(OS_Memory *m, SizeU pos){
SizeU aligned = align_down(pos, os_page_size);
SizeU adjusted_pos = clamp_top(aligned, m->commit);
SizeU size_to_decommit = m->commit - adjusted_pos;
if(size_to_decommit){
U8 *base_address = m->data + adjusted_pos;
BOOL result = VirtualFree(base_address, size_to_decommit, MEM_DECOMMIT);
if(result){
m->commit -= size_to_decommit;
return true;
}
}
return false;
}
function void
test_os_memory(){
assert(align_down(4096, 4096) == 4096);
assert(align_down(4095, 4096) == 0);
OS_Memory memory = os_reserve(9000);
assert(memory.reserve == 4096*3 && memory.data && memory.commit == 0);
os_commit(&memory, 100);
assert(memory.commit == 4096);
os_commit(&memory, 100);
assert(memory.commit == 4096*2);
os_commit(&memory, 9000);
assert(memory.commit == 4096*3);
os_commit(&memory, 9000);
assert(memory.commit == 4096*3);
os_decommit_pos(&memory, 4096);
assert(memory.commit == 4096);
os_decommit_pos(&memory, 4096);
assert(memory.commit == 4096);
os_decommit_pos(&memory, 0);
assert(memory.commit == 0);
os_release(&memory);
assert(memory.data == 0);
}
//-----------------------------------------------------------------------------
// Time
//-----------------------------------------------------------------------------
global S64 Global_counts_per_second;
api F64 os_time() {
if (Global_counts_per_second == 0) {
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
Global_counts_per_second = freq.QuadPart;
}
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
F64 result = (F64)time.QuadPart / (F64)Global_counts_per_second;
return result;
}
//-----------------------------------------------------------------------------
// Filesystem
//-----------------------------------------------------------------------------
function B32
os_write_file(String filename, String filecontent){
FILE *f = fopen((const char *)filename.str, "w");
if(f){
fwrite(filecontent.str, 1, filecontent.len, f);
fclose(f);
return true;
}
return false;
}
function String
os_read_file(Allocator *a, String name){
String result = {0};
FILE *f = fopen((char *)name.str, "rb");
if(f){
fseek(f, 0, SEEK_END);
result.len = ftell(f);
fseek(f, 0, SEEK_SET);
result.str = (U8 *)exp_alloc(a, result.len + 1);
fread(result.str, result.len, 1, f);
fclose(f);
result.str[result.len] = 0;
}
return result;
}
function String
os_get_working_dir(Allocator *a){
wchar_t buffer[2048];
DWORD written = GetCurrentDirectoryW(2048, buffer);
assert(written != 0);
String16 string16 = string16_from_widechar(buffer);
String result = string16_to_string8(a, string16);
string_path_normalize(result);
return result;
}
function String
os_get_exe_dir(Allocator *a){
wchar_t buffer[2048];
DWORD written = GetModuleFileNameW(0, buffer, 2048);
assert(written != 0);
String16 string16 = string16_from_widechar(buffer);
String result = string16_to_string8(a, string16);
string_path_normalize(result);
result = string_chop_last_slash(result);
if(string16.len > result.len) result.str[result.len] = 0;
string_path_normalize(result);
return result;
}
function String
os_get_absolute_path(Allocator *a, String path){
Scratch scratch(a);
String16 path16 = string8_to_string16(scratch, path);
wchar_t *buffer = exp_alloc_array(scratch, wchar_t, 2048);
DWORD written = GetFullPathNameW((wchar_t *)path16.str, 2048, buffer, 0);
if(written == 0) return {};
String16 absolute16 = string16_from_widechar(buffer);
String absolute = string16_to_string8(a, absolute16);
string_path_normalize(absolute);
return absolute;
}
function B32
os_does_file_exist(String path){
Scratch scratch;
String16 path16 = string8_to_string16(scratch, path);
DWORD attribs = GetFileAttributesW((wchar_t *)path16.str);
B32 result = attribs == INVALID_FILE_ATTRIBUTES ? false : true;
return result;
}
const U32 LIST_NO_FLAGS = 0;
const U32 LIST_RECURSE_INTO_DIRS = 1;
struct OS_File_Info{
String relative_path;
String absolute_path;
B32 is_directory;
};
function Array<OS_File_Info>
os_list_dir(Allocator *a, String dir, U32 flags = LIST_NO_FLAGS){
Scratch scratch(a);
Array<String> dirs_to_read = {scratch};
dirs_to_read.add(dir);
Array<OS_File_Info> result = {a};
for(auto it = dirs_to_read.begin(); it != dirs_to_read.end(); it++){
String modified_path = string_fmt(scratch, "%Q\\*", it);
String16 path16 = string8_to_string16(scratch, modified_path);
WIN32_FIND_DATAW ffd;
HANDLE handle = FindFirstFileW((wchar_t *)path16.str, &ffd);
if(handle == INVALID_HANDLE_VALUE) continue;
do{
//
// Skip '.' and '..'
//
if(ffd.cFileName[0] == '.'){
if(ffd.cFileName[1] == '.'){
if(ffd.cFileName[2] == 0)
continue;
}
if(ffd.cFileName[1] == 0)
continue;
}
String16 filename16 = string16_from_widechar(ffd.cFileName);
String filename = string16_to_string8(scratch, filename16);
String full_file_path = string_fmt(a, "%Q/%Q", dir, filename);
OS_File_Info listing = {full_file_path, os_get_absolute_path(a, full_file_path)};
if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
listing.is_directory = true;
if(flags & LIST_RECURSE_INTO_DIRS){
dirs_to_read.add(full_file_path);
}
}
result.add(listing);
}while(FindNextFileW(handle, &ffd) != 0);
DWORD error = GetLastError();
if(error != ERROR_NO_MORE_FILES){
// Not sure what to do here hmmm
}
FindClose(handle);
}
return result;
}

1128
os_windows_multimedia.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,7 @@
#include "obj_dump.cpp" #include "assets_obj_dump.cpp"
// #include "multimedia.cpp" #include "sf_vec.cpp"
// #include "obj.cpp" #include "sf_work_queue.cpp"
#include "vec.cpp"
#include "work_queue.cpp"
#define PROFILE_SCOPE(x) #define PROFILE_SCOPE(x)
#define MULTITHREADING 1 #define MULTITHREADING 1
@@ -222,7 +220,7 @@ S32 render_triangle_test_case_angle = -1;
U64 filled_pixel_count; U64 filled_pixel_count;
U64 filled_pixel_cycles; U64 filled_pixel_cycles;
U64 triangle_count; U64 triangle_count;
#include "optimization_log.cpp" #include "sf_optimization_log.cpp"
function function
@@ -701,7 +699,7 @@ void draw_mesh(Render *r, String scene_name, Obj_Material *materials, Obj_Mesh *
} }
} }
#include "ui.cpp" #include "sf_ui.cpp"
global F32 speed = 100.f; global F32 speed = 100.f;
global F32 rotation = 0; global F32 rotation = 0;
global Obj *f22; global Obj *f22;

View File

View File