Obj dump offsets textures for some reason, simplify abillity to use obj loader
directly, add timming, add Vec8
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -18,3 +18,4 @@ data.txt
|
|||||||
*.bin
|
*.bin
|
||||||
*.4c
|
*.4c
|
||||||
asset.log.txt
|
asset.log.txt
|
||||||
|
perfclocks.txt
|
||||||
431
assets.cpp
431
assets.cpp
@@ -1,438 +1,12 @@
|
|||||||
#include "multimedia.cpp"
|
#include "obj_dump.cpp"
|
||||||
#include "obj.cpp"
|
|
||||||
|
|
||||||
#define STBI_ASSERT assert
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include "stb_image.h"
|
|
||||||
|
|
||||||
enum class Obj_Token_Type {
|
|
||||||
none, word, number, whitespace, end
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Obj_Token {
|
|
||||||
Obj_Token_Type type;
|
|
||||||
double number;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
char* s;
|
|
||||||
int len;
|
|
||||||
};
|
|
||||||
String s8;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function Bitmap
|
|
||||||
load_image(String path) {
|
|
||||||
Scratch scratch;
|
|
||||||
String file = os_read_file(scratch, path);
|
|
||||||
|
|
||||||
int x, y, n;
|
|
||||||
unsigned char* data = stbi_load_from_memory(file.str, file.len, &x, &y, &n, 4);
|
|
||||||
Bitmap result = { (U32*)data, x, y };
|
|
||||||
if(data) {
|
|
||||||
U32 *p = result.pixels;
|
|
||||||
for (int Y = 0; Y < y; Y++) {
|
|
||||||
for (int X = 0; X < x; X++) {
|
|
||||||
Vec4 color = vec4abgr(*p);
|
|
||||||
color.r *= color.a;
|
|
||||||
color.g *= color.a;
|
|
||||||
color.b *= color.a;
|
|
||||||
*p++ = vec4_to_u32abgr(color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Obj_Token next_token_raw(char** data) {
|
|
||||||
Obj_Token result = {};
|
|
||||||
result.s = *data;
|
|
||||||
*data += 1;
|
|
||||||
|
|
||||||
if (is_alphabetic(*result.s)) {
|
|
||||||
result.type = Obj_Token_Type::word;
|
|
||||||
while (!is_whitespace(**data)) {
|
|
||||||
*data += 1;
|
|
||||||
}
|
|
||||||
result.len = (int)(*data - result.s);
|
|
||||||
}
|
|
||||||
else if (is_number(*result.s) || *result.s == '-') {
|
|
||||||
result.type = Obj_Token_Type::number;
|
|
||||||
while (is_number(**data) || **data == '.' || **data == 'e' || **data == '-') {
|
|
||||||
*data += 1;
|
|
||||||
}
|
|
||||||
result.number = atof(result.s);
|
|
||||||
result.len = (int)(*data - result.s);
|
|
||||||
}
|
|
||||||
else if (*result.s == '#') {
|
|
||||||
while (**data != '\n') *data += 1;
|
|
||||||
result = next_token_raw(data);
|
|
||||||
}
|
|
||||||
else if (is_whitespace(*result.s)) {
|
|
||||||
result.type = Obj_Token_Type::whitespace;
|
|
||||||
while (is_whitespace(**data)) *data += 1;
|
|
||||||
result.len = (int)(*data - result.s);
|
|
||||||
}
|
|
||||||
else if (*result.s == 0) {
|
|
||||||
result.type = Obj_Token_Type::end;
|
|
||||||
}
|
|
||||||
else if (*result.s >= '!') {
|
|
||||||
result.type = (Obj_Token_Type)*result.s;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Obj_Token next_token(char** data) {
|
|
||||||
Obj_Token result;
|
|
||||||
do {
|
|
||||||
result = next_token_raw(data);
|
|
||||||
} while (result.type == Obj_Token_Type::whitespace);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function double expect_number(char** data) {
|
|
||||||
Obj_Token t = next_token(data);
|
|
||||||
assert(t.type == Obj_Token_Type::number); // @Todo: Error handling, error flag
|
|
||||||
return t.number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function void expect_token(char** data, char token) {
|
|
||||||
Obj_Token t = next_token(data);
|
|
||||||
assert(t.type == (Obj_Token_Type)token); // @Todo: Error handling, error flag
|
|
||||||
}
|
|
||||||
|
|
||||||
function void debug_expect_raw(char** data, Obj_Token_Type type) {
|
|
||||||
char* data_temp = *data;
|
|
||||||
Obj_Token t = next_token_raw(&data_temp);
|
|
||||||
assert(t.type == type);
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
|
||||||
parse_mtl(Obj* obj, String path_obj_folder, String mtl_file) {
|
|
||||||
Scratch scratch;
|
|
||||||
char *data = (char *)mtl_file.str;
|
|
||||||
Obj_Material *m = 0;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
Obj_Token token = next_token(&data);
|
|
||||||
if (token.type == Obj_Token_Type::end) break;
|
|
||||||
else if (token.type == Obj_Token_Type::word) {
|
|
||||||
if (string_compare(token.s8, "newmtl"_s)) {
|
|
||||||
token = next_token(&data);
|
|
||||||
m = obj->materials.push_empty_zero();
|
|
||||||
m->name_len = clamp_top(token.len, 64);
|
|
||||||
memory_copy(m->name, token.s8.str, m->name_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "Ns"_s)) {
|
|
||||||
m->shininess = expect_number(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "Ka"_s)) {
|
|
||||||
m->ambient_color.x = expect_number(&data);
|
|
||||||
m->ambient_color.y = expect_number(&data);
|
|
||||||
m->ambient_color.z = expect_number(&data);
|
|
||||||
}
|
|
||||||
else if (string_compare(token.s8, "Kd"_s)) {
|
|
||||||
m->diffuse_color.x = expect_number(&data);
|
|
||||||
m->diffuse_color.y = expect_number(&data);
|
|
||||||
m->diffuse_color.z = expect_number(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "Ks"_s)) {
|
|
||||||
m->specular_color.x = expect_number(&data);
|
|
||||||
m->specular_color.y = expect_number(&data);
|
|
||||||
m->specular_color.z = expect_number(&data);
|
|
||||||
}
|
|
||||||
else if (string_compare(token.s8, "Ni"_s)) {
|
|
||||||
m->optical_density = expect_number(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "d"_s)) {
|
|
||||||
m->non_transparency = expect_number(&data);
|
|
||||||
}
|
|
||||||
else if (string_compare(token.s8, "illum"_s)) {
|
|
||||||
m->illumination_model = (S32)expect_number(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "map_Kd"_s)) {
|
|
||||||
Obj_Token t = next_token(&data);
|
|
||||||
String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8);
|
|
||||||
m->texture_diffuse = load_image(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "map_Ka"_s)) {
|
|
||||||
Obj_Token t = next_token(&data);
|
|
||||||
String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8);
|
|
||||||
m->texture_ambient = load_image(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "map_d"_s)) {
|
|
||||||
Obj_Token t = next_token(&data);
|
|
||||||
String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8);
|
|
||||||
m->texture_dissolve = load_image(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "map_Disp"_s)) {
|
|
||||||
Obj_Token t = next_token(&data);
|
|
||||||
String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8);
|
|
||||||
m->texture_displacement = load_image(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Obj
|
|
||||||
parse(Allocator *allocator, char* data, String path_obj_folder) {
|
|
||||||
Set_Allocator(allocator);
|
|
||||||
Scratch mtl_scratch;
|
|
||||||
Obj result = {};
|
|
||||||
//result.vertices.init(allocator, 160000);
|
|
||||||
//result.texture_coordinates.init(allocator, 160000);
|
|
||||||
//result.normals.init(allocator, 160000);
|
|
||||||
//result.mesh.init(allocator, 64);
|
|
||||||
//result.materials.init(allocator, 64);
|
|
||||||
int smoothing = 0;
|
|
||||||
|
|
||||||
Obj_Mesh *mesh = result.mesh.push_empty_zero();
|
|
||||||
//mesh->indices.init(allocator);
|
|
||||||
int material_id = -1;
|
|
||||||
|
|
||||||
S64 debug_i = 0;
|
|
||||||
for (;;debug_i++){
|
|
||||||
Obj_Token token = next_token(&data);
|
|
||||||
if (token.type == Obj_Token_Type::end) break;
|
|
||||||
else if (token.type == Obj_Token_Type::word) {
|
|
||||||
if (string_compare(token.s8, "v"_s)) {
|
|
||||||
Vec3 *vertex = result.vertices.push_empty_zero();
|
|
||||||
vertex->x = (float)expect_number(&data);
|
|
||||||
vertex->y = (float)expect_number(&data);
|
|
||||||
vertex->z = (float)expect_number(&data);
|
|
||||||
debug_expect_raw(&data, Obj_Token_Type::whitespace);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "vt"_s)) {
|
|
||||||
Vec2 *tex = result.texture_coordinates.push_empty_zero();
|
|
||||||
tex->x = (float)expect_number(&data);
|
|
||||||
tex->y = (float)expect_number(&data);
|
|
||||||
debug_expect_raw(&data, Obj_Token_Type::whitespace);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "vn"_s)) {
|
|
||||||
Vec3 *norm = result.normals.push_empty_zero();
|
|
||||||
norm->x = (float)expect_number(&data);
|
|
||||||
norm->y = (float)expect_number(&data);
|
|
||||||
norm->z = (float)expect_number(&data);
|
|
||||||
debug_expect_raw(&data, Obj_Token_Type::whitespace);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "mtllib"_s)) {
|
|
||||||
Obj_Token t = next_token(&data);
|
|
||||||
String path = string_fmt(mtl_scratch, "%Q/%Q", path_obj_folder, t.s8);
|
|
||||||
String mtl_file = os_read_file(mtl_scratch, path);
|
|
||||||
if(mtl_file.str) {
|
|
||||||
parse_mtl(&result, path_obj_folder, mtl_file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "usemtl"_s)) {
|
|
||||||
Obj_Token t = next_token(&data);
|
|
||||||
assert(t.type == Obj_Token_Type::word);
|
|
||||||
for(U64 i = 0; i < result.materials.len; i++) {
|
|
||||||
Obj_Material *m = result.materials.data + i;
|
|
||||||
if(string_compare({(U8 *)m->name, m->name_len}, t.s8)) {
|
|
||||||
material_id = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "o"_s)) {
|
|
||||||
Obj_Token t = next_token(&data);
|
|
||||||
assert(t.type == Obj_Token_Type::word);
|
|
||||||
if (mesh->indices.len != 0) {
|
|
||||||
mesh = result.mesh.push_empty_zero();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
U64 len = clamp_top(t.len, 64);
|
|
||||||
memory_copy(mesh->name, t.s, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "s"_s)) {
|
|
||||||
Obj_Token t = next_token(&data);
|
|
||||||
if (t.type == Obj_Token_Type::number) {
|
|
||||||
smoothing = (int)t.number;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(t.type == Obj_Token_Type::word);
|
|
||||||
if (string_compare(t.s8, "on"_s)) {
|
|
||||||
smoothing = 1;
|
|
||||||
}
|
|
||||||
else if (string_compare(t.s8, "off"_s)) {
|
|
||||||
smoothing = 0;
|
|
||||||
}
|
|
||||||
else invalid_codepath;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "g"_s)) {
|
|
||||||
Obj_Token t = next_token(&data);
|
|
||||||
assert(t.type == Obj_Token_Type::word);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (string_compare(token.s8, "f"_s)) {
|
|
||||||
Obj_Index *i = mesh->indices.push_empty_zero();
|
|
||||||
i->smoothing_group_id = smoothing;
|
|
||||||
i->material_id = material_id;
|
|
||||||
i->vertex[0] = (int)expect_number(&data);
|
|
||||||
expect_token(&data, '/');
|
|
||||||
i->tex[0] = (int)expect_number(&data);
|
|
||||||
expect_token(&data, '/');
|
|
||||||
i->normal[0] = (int)expect_number(&data);
|
|
||||||
|
|
||||||
i->vertex[1] = (int)expect_number(&data);
|
|
||||||
expect_token(&data, '/');
|
|
||||||
i->tex[1] = (int)expect_number(&data);
|
|
||||||
expect_token(&data, '/');
|
|
||||||
i->normal[1] = (int)expect_number(&data);
|
|
||||||
|
|
||||||
i->vertex[2] = (int)expect_number(&data);
|
|
||||||
expect_token(&data, '/');
|
|
||||||
i->tex[2] = (int)expect_number(&data);
|
|
||||||
expect_token(&data, '/');
|
|
||||||
i->normal[2] = (int)expect_number(&data);
|
|
||||||
//debug_expect_raw(&data, Obj_Token_Type::whitespace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Obj
|
|
||||||
load_obj(Allocator *arena, String file) {
|
|
||||||
Scratch scratch;
|
|
||||||
String data = os_read_file(scratch, file);
|
|
||||||
assert(data.str);
|
|
||||||
|
|
||||||
String path = string_chop_last_slash(file);
|
|
||||||
Obj result = parse(arena, (char *)data.str, path);
|
|
||||||
result.name = file;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T> void
|
|
||||||
dump_array(String_Builder *sb, Array<T> *arr){
|
|
||||||
sb->append_data(arr, sizeof(*arr));
|
|
||||||
sb->append_data(arr->data, sizeof(T)*arr->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
|
||||||
dump_bitmap_image(String_Builder *sb, Bitmap *bm){
|
|
||||||
sb->append_data(bm->pixels, sizeof(U32)*bm->x*bm->y);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function B32
|
|
||||||
_os_write_file(String file, String data, B32 append = false) {
|
|
||||||
B32 result = false;
|
|
||||||
DWORD access = GENERIC_WRITE;
|
|
||||||
DWORD creation_disposition = CREATE_ALWAYS;
|
|
||||||
if (append) {
|
|
||||||
access = FILE_APPEND_DATA;
|
|
||||||
creation_disposition = OPEN_ALWAYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Todo(Krzosa): Unicode
|
|
||||||
HANDLE handle = CreateFileA((const char *)file.str, access, 0, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
||||||
if (handle != INVALID_HANDLE_VALUE) {
|
|
||||||
DWORD bytes_written = 0;
|
|
||||||
// @Todo: can only read 32 byte size files?
|
|
||||||
assert_msg(data.len == (U32)data.len, "Max data size os_write can handle is 32 bytes, data to write is larger then 32 bytes!");
|
|
||||||
B32 error = WriteFile(handle, data.str, (U32)data.len, &bytes_written, NULL);
|
|
||||||
if (error == false) log_error("Failed to write to file: %Q", file);
|
|
||||||
else {
|
|
||||||
if (bytes_written != data.len) log_error("Failed to write to file: %Q, mismatch between length requested to write and length written", file);
|
|
||||||
else result = true;
|
|
||||||
}
|
|
||||||
CloseHandle(handle);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log_error("File not found when trying to write: %Q", file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function B32
|
|
||||||
os_write_file2(String file, String data) {
|
|
||||||
return _os_write_file(file, data, false);
|
|
||||||
}
|
|
||||||
function B32
|
|
||||||
os_append_file(String file, String data) {
|
|
||||||
return _os_write_file(file, data, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function void
|
|
||||||
dump_obj_to_file(Obj *obj, String out_name){
|
|
||||||
obj->vertices.allocator = 0;
|
|
||||||
obj->vertices.cap = obj->vertices.len;
|
|
||||||
|
|
||||||
obj->texture_coordinates.allocator = 0;
|
|
||||||
obj->texture_coordinates.cap = obj->texture_coordinates.len;
|
|
||||||
|
|
||||||
obj->normals.allocator = 0;
|
|
||||||
obj->normals.cap = obj->normals.len;
|
|
||||||
|
|
||||||
obj->mesh.allocator = 0;
|
|
||||||
obj->mesh.cap = obj->mesh.len;
|
|
||||||
|
|
||||||
obj->materials.allocator = 0;
|
|
||||||
obj->materials.cap = obj->materials.len;
|
|
||||||
|
|
||||||
For(obj->mesh){
|
|
||||||
it.indices.allocator = 0;
|
|
||||||
it.indices.cap = it.indices.len;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scratch arena;
|
|
||||||
String_Builder sb = string_builder_make(arena, mib(4));
|
|
||||||
sb.append_data(obj, sizeof(Obj));
|
|
||||||
sb.append_data(obj->name.str, obj->name.len);
|
|
||||||
sb.append_data(obj->vertices.data, obj->vertices.len*sizeof(Vec3));
|
|
||||||
sb.append_data(obj->texture_coordinates.data, obj->texture_coordinates.len*sizeof(Vec2));
|
|
||||||
sb.append_data(obj->normals.data, obj->normals.len*sizeof(Vec3));
|
|
||||||
sb.append_data(obj->mesh.data, obj->mesh.len*sizeof(Obj_Mesh));
|
|
||||||
sb.append_data(obj->materials.data, obj->materials.len*sizeof(Obj_Material));
|
|
||||||
|
|
||||||
For(obj->mesh){
|
|
||||||
sb.append_data(it.indices.data, sizeof(Obj_Index)*it.indices.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
For(obj->materials){
|
|
||||||
sb.append_data(&it, sizeof(Obj_Material));
|
|
||||||
dump_bitmap_image(&sb, &it.texture_ambient);
|
|
||||||
dump_bitmap_image(&sb, &it.texture_diffuse);
|
|
||||||
dump_bitmap_image(&sb, &it.texture_dissolve);
|
|
||||||
dump_bitmap_image(&sb, &it.texture_displacement);
|
|
||||||
}
|
|
||||||
|
|
||||||
String result = string_flatten(arena, &sb);
|
|
||||||
os_write_file2(out_name, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
global FILE *output_file;
|
|
||||||
|
|
||||||
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){
|
||||||
fprintf(output_file, "%.*s", string_expand(string));
|
printf("%.*s", string_expand(string));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv){
|
main(int argc, char **argv){
|
||||||
output_file = fopen("asset.log.txt", "a");
|
|
||||||
thread_ctx.log_proc = asset_log;
|
thread_ctx.log_proc = asset_log;
|
||||||
|
|
||||||
Obj sponza_obj = load_obj(&os_process_heap, "assets/sponza/sponza.obj"_s);
|
Obj sponza_obj = load_obj(&os_process_heap, "assets/sponza/sponza.obj"_s);
|
||||||
@@ -453,5 +27,4 @@ main(int argc, char **argv){
|
|||||||
}
|
}
|
||||||
|
|
||||||
dump_obj_to_file(&plane_obj, "plane.bin"_s);
|
dump_obj_to_file(&plane_obj, "plane.bin"_s);
|
||||||
fclose(output_file);
|
|
||||||
}
|
}
|
||||||
@@ -6,4 +6,4 @@ rem assets.exe
|
|||||||
rem tracy/TracyClient.cpp -DTRACY_ENABLE
|
rem tracy/TracyClient.cpp -DTRACY_ENABLE
|
||||||
|
|
||||||
|
|
||||||
clang main.cpp -O2 -Wall -Wno-unused-function -Wno-missing-braces -fno-exceptions -fdiagnostics-absolute-paths -g -I".." -o main.exe -Wl,user32.lib -Wl,optick\lib\x64\release\OptickCore.lib
|
clang main.cpp -mavx2 -Wall -Wno-unused-function -Wno-missing-braces -fno-exceptions -fdiagnostics-absolute-paths -g -I".." -o main.exe -Wl,user32.lib -Wl,optick\lib\x64\release\OptickCore.lib
|
||||||
18
main.cpp
18
main.cpp
@@ -89,11 +89,11 @@
|
|||||||
#undef assert
|
#undef assert
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include "multimedia.cpp"
|
#include "multimedia.cpp"
|
||||||
#include "profile.cpp"
|
#include "profile.cpp"
|
||||||
#include "obj.cpp"
|
#include "obj.cpp"
|
||||||
|
#include "vec.cpp"
|
||||||
|
|
||||||
|
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
Vec3 pos;
|
Vec3 pos;
|
||||||
@@ -294,6 +294,7 @@ void draw_triangle_nearest(Bitmap* dst, F32 *depth_buffer, Bitmap *src, Vec3 lig
|
|||||||
Vec4 p0, Vec4 p1, Vec4 p2,
|
Vec4 p0, Vec4 p1, Vec4 p2,
|
||||||
Vec2 tex0, Vec2 tex1, Vec2 tex2,
|
Vec2 tex0, Vec2 tex1, Vec2 tex2,
|
||||||
Vec3 norm0, Vec3 norm1, Vec3 norm2) {
|
Vec3 norm0, Vec3 norm1, Vec3 norm2) {
|
||||||
|
if(src->pixels == 0) return;
|
||||||
PROFILE_SCOPE(draw_triangle);
|
PROFILE_SCOPE(draw_triangle);
|
||||||
F32 min_x1 = (F32)(min(p0.x, min(p1.x, p2.x)));
|
F32 min_x1 = (F32)(min(p0.x, min(p1.x, p2.x)));
|
||||||
F32 min_y1 = (F32)(min(p0.y, min(p1.y, p2.y)));
|
F32 min_y1 = (F32)(min(p0.y, min(p1.y, p2.y)));
|
||||||
@@ -429,6 +430,7 @@ void draw_mesh(Render *r, String scene_name, Obj_Material *materials, Obj_Mesh *
|
|||||||
image = &material->texture_ambient;
|
image = &material->texture_ambient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vertex vert[] = {
|
Vertex vert[] = {
|
||||||
{
|
{
|
||||||
vertices[index->vertex[0] - 1],
|
vertices[index->vertex[0] - 1],
|
||||||
@@ -518,13 +520,16 @@ void draw_mesh(Render *r, String scene_name, Obj_Material *materials, Obj_Mesh *
|
|||||||
F32 t = prev_dot / (prev_dot - curr_dot);
|
F32 t = prev_dot / (prev_dot - curr_dot);
|
||||||
in[in_count].pos = vec4(lerp(prev->pos, curr->pos, t), 1);
|
in[in_count].pos = vec4(lerp(prev->pos, curr->pos, t), 1);
|
||||||
in[in_count].tex = lerp(prev->tex, curr->tex, t);
|
in[in_count].tex = lerp(prev->tex, curr->tex, t);
|
||||||
in[in_count++].norm = lerp(prev->norm, curr->norm, t);
|
in[in_count].norm = lerp(prev->norm, curr->norm, t);
|
||||||
|
in_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curr_dot > 0) {
|
if (curr_dot > 0) {
|
||||||
in[in_count].pos = vec4(vert[j].pos, 1);
|
in[in_count].pos = vec4(vert[j].pos, 1);
|
||||||
in[in_count].tex = vert[j].tex;
|
in[in_count].tex = vert[j].tex;
|
||||||
in[in_count++].norm = vert[j].norm;
|
in[in_count++].norm = vert[j].norm;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = curr++;
|
prev = curr++;
|
||||||
prev_dot = curr_dot;
|
prev_dot = curr_dot;
|
||||||
}
|
}
|
||||||
@@ -610,6 +615,8 @@ main(int argc, char **argv) {
|
|||||||
|
|
||||||
f22 = load_obj_dump(os.perm_arena, "plane.bin"_s);
|
f22 = load_obj_dump(os.perm_arena, "plane.bin"_s);
|
||||||
sponza = load_obj_dump(os.perm_arena, "sponza.bin"_s);
|
sponza = load_obj_dump(os.perm_arena, "sponza.bin"_s);
|
||||||
|
// Obj sponza_obj = load_obj(&os_process_heap, "assets/sponza/sponza.obj"_s);
|
||||||
|
// sponza = &sponza_obj;
|
||||||
scene_callback();
|
scene_callback();
|
||||||
|
|
||||||
int screen_x = 1280;
|
int screen_x = 1280;
|
||||||
@@ -654,12 +661,15 @@ main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
if (os.key[Key_R].down) r.camera_pos.y += speed * (F32)os.delta_time;
|
if (os.key[Key_R].down) r.camera_pos.y += speed * (F32)os.delta_time;
|
||||||
if (os.key[Key_F].down) r.camera_pos.y -= speed * (F32)os.delta_time;
|
if (os.key[Key_F].down) r.camera_pos.y -= speed * (F32)os.delta_time;
|
||||||
|
|
||||||
|
// Clear screen and depth buffer
|
||||||
U32* p = r.screen320.pixels;
|
U32* p = r.screen320.pixels;
|
||||||
for (int y = 0; y < r.screen320.y; y++) {
|
for (int y = 0; y < r.screen320.y; y++) {
|
||||||
for (int x = 0; x < r.screen320.x; x++) {
|
for (int x = 0; x < r.screen320.x; x++) {
|
||||||
*p++ = 0x33333333;
|
*p++ = 0x33333333;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
F32* dp = r.depth320;
|
F32* dp = r.depth320;
|
||||||
for (int y = 0; y < r.screen320.y; y++) {
|
for (int y = 0; y < r.screen320.y; y++) {
|
||||||
for (int x = 0; x < r.screen320.x; x++) {
|
for (int x = 0; x < r.screen320.x; x++) {
|
||||||
@@ -667,7 +677,6 @@ main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Mat4 camera_rotation = mat4_rotation_y(r.camera_yaw.x) * mat4_rotation_x(r.camera_yaw.y);
|
Mat4 camera_rotation = mat4_rotation_y(r.camera_yaw.x) * mat4_rotation_x(r.camera_yaw.y);
|
||||||
r.camera_direction = (camera_rotation * vec4(0,0,1,1)).xyz;
|
r.camera_direction = (camera_rotation * vec4(0,0,1,1)).xyz;
|
||||||
Vec3 target = r.camera_pos + r.camera_direction;
|
Vec3 target = r.camera_pos + r.camera_direction;
|
||||||
@@ -696,6 +705,7 @@ main(int argc, char **argv) {
|
|||||||
*ptr++ = r.screen320.pixels[tx + ty * (r.screen320.x)];
|
*ptr++ = r.screen320.pixels[tx + ty * (r.screen320.x)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_end_frame(os.screen, &ui, &font);
|
ui_end_frame(os.screen, &ui, &font);
|
||||||
frame_data = string_fmt(os.frame_arena, "FPS:%f dt:%f frame:%u camera_pos: %f %f %f camera_yaw: %f %f", os.fps, os.delta_time, os.frame,
|
frame_data = string_fmt(os.frame_arena, "FPS:%f dt:%f frame:%u camera_pos: %f %f %f camera_yaw: %f %f", os.fps, os.delta_time, os.frame,
|
||||||
r.camera_pos.x, r.camera_pos.y, r.camera_pos.z, r.camera_yaw.x, r.camera_yaw.y);
|
r.camera_pos.x, r.camera_pos.y, r.camera_pos.z, r.camera_yaw.x, r.camera_yaw.y);
|
||||||
|
|||||||
2
obj.cpp
2
obj.cpp
@@ -64,8 +64,8 @@ load_obj_dump(Allocator *allocator, String filename){
|
|||||||
Stream stream = {string.str, string.str + string.len};
|
Stream stream = {string.str, string.str + string.len};
|
||||||
Obj *obj = stream_read_struct(&stream, Obj);
|
Obj *obj = stream_read_struct(&stream, Obj);
|
||||||
obj->name.str = stream_read_array(&stream, U8, obj->name.len);
|
obj->name.str = stream_read_array(&stream, U8, obj->name.len);
|
||||||
obj->vertices.data = stream_read_array(&stream, Vec3, obj->vertices.len);
|
|
||||||
obj->texture_coordinates.data = stream_read_array(&stream, Vec2, obj->texture_coordinates.len);
|
obj->texture_coordinates.data = stream_read_array(&stream, Vec2, obj->texture_coordinates.len);
|
||||||
|
obj->vertices.data = stream_read_array(&stream, Vec3, obj->vertices.len);
|
||||||
obj->normals.data = stream_read_array(&stream, Vec3, obj->normals.len);
|
obj->normals.data = stream_read_array(&stream, Vec3, obj->normals.len);
|
||||||
obj->mesh.data = stream_read_array(&stream, Obj_Mesh, obj->mesh.len);
|
obj->mesh.data = stream_read_array(&stream, Obj_Mesh, obj->mesh.len);
|
||||||
obj->materials.data = stream_read_array(&stream, Obj_Material, obj->materials.len);
|
obj->materials.data = stream_read_array(&stream, Obj_Material, obj->materials.len);
|
||||||
|
|||||||
432
obj_dump.cpp
Normal file
432
obj_dump.cpp
Normal file
@@ -0,0 +1,432 @@
|
|||||||
|
#include "multimedia.cpp"
|
||||||
|
#include "obj.cpp"
|
||||||
|
|
||||||
|
#define STBI_ASSERT assert
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
enum class Obj_Token_Type {
|
||||||
|
none, word, number, whitespace, end
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Obj_Token {
|
||||||
|
Obj_Token_Type type;
|
||||||
|
double number;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
char* s;
|
||||||
|
int len;
|
||||||
|
};
|
||||||
|
String s8;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function Bitmap
|
||||||
|
load_image(String path) {
|
||||||
|
Scratch scratch;
|
||||||
|
String file = os_read_file(scratch, path);
|
||||||
|
|
||||||
|
int x, y, n;
|
||||||
|
unsigned char* data = stbi_load_from_memory(file.str, file.len, &x, &y, &n, 4);
|
||||||
|
Bitmap result = { (U32*)data, x, y };
|
||||||
|
if(data) {
|
||||||
|
U32 *p = result.pixels;
|
||||||
|
for (int Y = 0; Y < y; Y++) {
|
||||||
|
for (int X = 0; X < x; X++) {
|
||||||
|
Vec4 color = vec4abgr(*p);
|
||||||
|
color.r *= color.a;
|
||||||
|
color.g *= color.a;
|
||||||
|
color.b *= color.a;
|
||||||
|
*p++ = vec4_to_u32abgr(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Obj_Token next_token_raw(char** data) {
|
||||||
|
Obj_Token result = {};
|
||||||
|
result.s = *data;
|
||||||
|
*data += 1;
|
||||||
|
|
||||||
|
if (is_alphabetic(*result.s)) {
|
||||||
|
result.type = Obj_Token_Type::word;
|
||||||
|
while (!is_whitespace(**data)) {
|
||||||
|
*data += 1;
|
||||||
|
}
|
||||||
|
result.len = (int)(*data - result.s);
|
||||||
|
}
|
||||||
|
else if (is_number(*result.s) || *result.s == '-') {
|
||||||
|
result.type = Obj_Token_Type::number;
|
||||||
|
while (is_number(**data) || **data == '.' || **data == 'e' || **data == '-') {
|
||||||
|
*data += 1;
|
||||||
|
}
|
||||||
|
result.number = atof(result.s);
|
||||||
|
result.len = (int)(*data - result.s);
|
||||||
|
}
|
||||||
|
else if (*result.s == '#') {
|
||||||
|
while (**data != '\n') *data += 1;
|
||||||
|
result = next_token_raw(data);
|
||||||
|
}
|
||||||
|
else if (is_whitespace(*result.s)) {
|
||||||
|
result.type = Obj_Token_Type::whitespace;
|
||||||
|
while (is_whitespace(**data)) *data += 1;
|
||||||
|
result.len = (int)(*data - result.s);
|
||||||
|
}
|
||||||
|
else if (*result.s == 0) {
|
||||||
|
result.type = Obj_Token_Type::end;
|
||||||
|
}
|
||||||
|
else if (*result.s >= '!') {
|
||||||
|
result.type = (Obj_Token_Type)*result.s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Obj_Token next_token(char** data) {
|
||||||
|
Obj_Token result;
|
||||||
|
do {
|
||||||
|
result = next_token_raw(data);
|
||||||
|
} while (result.type == Obj_Token_Type::whitespace);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function double expect_number(char** data) {
|
||||||
|
Obj_Token t = next_token(data);
|
||||||
|
assert(t.type == Obj_Token_Type::number); // @Todo: Error handling, error flag
|
||||||
|
return t.number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function void expect_token(char** data, char token) {
|
||||||
|
Obj_Token t = next_token(data);
|
||||||
|
assert(t.type == (Obj_Token_Type)token); // @Todo: Error handling, error flag
|
||||||
|
}
|
||||||
|
|
||||||
|
function B32 match_token(char **data, char token){
|
||||||
|
char *save = *data;
|
||||||
|
Obj_Token t = next_token(&save);
|
||||||
|
if(t.type == (Obj_Token_Type)token){
|
||||||
|
*data = save;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function void debug_expect_raw(char** data, Obj_Token_Type type) {
|
||||||
|
char* data_temp = *data;
|
||||||
|
Obj_Token t = next_token_raw(&data_temp);
|
||||||
|
assert(t.type == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
parse_mtl(Obj* obj, String path_obj_folder, String mtl_file) {
|
||||||
|
Scratch scratch;
|
||||||
|
char *data = (char *)mtl_file.str;
|
||||||
|
Obj_Material *m = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
Obj_Token token = next_token(&data);
|
||||||
|
if (token.type == Obj_Token_Type::end) break;
|
||||||
|
else if (token.type == Obj_Token_Type::word) {
|
||||||
|
if (string_compare(token.s8, "newmtl"_s)) {
|
||||||
|
token = next_token(&data);
|
||||||
|
m = obj->materials.push_empty_zero();
|
||||||
|
m->name_len = clamp_top(token.len, 64);
|
||||||
|
memory_copy(m->name, token.s8.str, m->name_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "Ns"_s)) {
|
||||||
|
m->shininess = expect_number(&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "Ka"_s)) {
|
||||||
|
m->ambient_color.x = expect_number(&data);
|
||||||
|
m->ambient_color.y = expect_number(&data);
|
||||||
|
m->ambient_color.z = expect_number(&data);
|
||||||
|
}
|
||||||
|
else if (string_compare(token.s8, "Kd"_s)) {
|
||||||
|
m->diffuse_color.x = expect_number(&data);
|
||||||
|
m->diffuse_color.y = expect_number(&data);
|
||||||
|
m->diffuse_color.z = expect_number(&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "Ks"_s)) {
|
||||||
|
m->specular_color.x = expect_number(&data);
|
||||||
|
m->specular_color.y = expect_number(&data);
|
||||||
|
m->specular_color.z = expect_number(&data);
|
||||||
|
}
|
||||||
|
else if (string_compare(token.s8, "Ni"_s)) {
|
||||||
|
m->optical_density = expect_number(&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "d"_s)) {
|
||||||
|
m->non_transparency = expect_number(&data);
|
||||||
|
}
|
||||||
|
else if (string_compare(token.s8, "illum"_s)) {
|
||||||
|
m->illumination_model = (S32)expect_number(&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "map_Kd"_s)) {
|
||||||
|
Obj_Token t = next_token(&data);
|
||||||
|
String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8);
|
||||||
|
m->texture_diffuse = load_image(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "map_Ka"_s)) {
|
||||||
|
Obj_Token t = next_token(&data);
|
||||||
|
String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8);
|
||||||
|
m->texture_ambient = load_image(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "map_d"_s)) {
|
||||||
|
Obj_Token t = next_token(&data);
|
||||||
|
String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8);
|
||||||
|
m->texture_dissolve = load_image(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "map_Disp"_s)) {
|
||||||
|
Obj_Token t = next_token(&data);
|
||||||
|
String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8);
|
||||||
|
m->texture_displacement = load_image(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Obj
|
||||||
|
parse(Allocator *allocator, char* data, String path_obj_folder) {
|
||||||
|
Set_Allocator(allocator);
|
||||||
|
Scratch mtl_scratch;
|
||||||
|
Obj result = {};
|
||||||
|
//result.vertices.init(allocator, 160000);
|
||||||
|
//result.texture_coordinates.init(allocator, 160000);
|
||||||
|
//result.normals.init(allocator, 160000);
|
||||||
|
//result.mesh.init(allocator, 64);
|
||||||
|
//result.materials.init(allocator, 64);
|
||||||
|
int smoothing = 0;
|
||||||
|
|
||||||
|
Obj_Mesh *mesh = result.mesh.push_empty_zero();
|
||||||
|
//mesh->indices.init(allocator);
|
||||||
|
int material_id = -1;
|
||||||
|
|
||||||
|
S64 debug_i = 0;
|
||||||
|
for (;;debug_i++){
|
||||||
|
Obj_Token token = next_token(&data);
|
||||||
|
if (token.type == Obj_Token_Type::end) break;
|
||||||
|
else if (token.type == Obj_Token_Type::word) {
|
||||||
|
if (string_compare(token.s8, "v"_s)) {
|
||||||
|
Vec3 *vertex = result.vertices.push_empty_zero();
|
||||||
|
vertex->x = (float)expect_number(&data);
|
||||||
|
vertex->y = (float)expect_number(&data);
|
||||||
|
vertex->z = (float)expect_number(&data);
|
||||||
|
debug_expect_raw(&data, Obj_Token_Type::whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "vt"_s)) {
|
||||||
|
Vec2 *tex = result.texture_coordinates.push_empty_zero();
|
||||||
|
tex->x = (float)expect_number(&data);
|
||||||
|
tex->y = (float)expect_number(&data);
|
||||||
|
debug_expect_raw(&data, Obj_Token_Type::whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "vn"_s)) {
|
||||||
|
Vec3 *norm = result.normals.push_empty_zero();
|
||||||
|
norm->x = (float)expect_number(&data);
|
||||||
|
norm->y = (float)expect_number(&data);
|
||||||
|
norm->z = (float)expect_number(&data);
|
||||||
|
debug_expect_raw(&data, Obj_Token_Type::whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "mtllib"_s)) {
|
||||||
|
Obj_Token t = next_token(&data);
|
||||||
|
String path = string_fmt(mtl_scratch, "%Q/%Q", path_obj_folder, t.s8);
|
||||||
|
String mtl_file = os_read_file(mtl_scratch, path);
|
||||||
|
if(mtl_file.str) {
|
||||||
|
parse_mtl(&result, path_obj_folder, mtl_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "usemtl"_s)) {
|
||||||
|
Obj_Token t = next_token(&data);
|
||||||
|
assert(t.type == Obj_Token_Type::word);
|
||||||
|
for(U64 i = 0; i < result.materials.len; i++) {
|
||||||
|
Obj_Material *m = result.materials.data + i;
|
||||||
|
if(string_compare({(U8 *)m->name, m->name_len}, t.s8)) {
|
||||||
|
material_id = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "o"_s)) {
|
||||||
|
Obj_Token t = next_token(&data);
|
||||||
|
assert(t.type == Obj_Token_Type::word);
|
||||||
|
if (mesh->indices.len != 0) {
|
||||||
|
mesh = result.mesh.push_empty_zero();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
U64 len = clamp_top(t.len, 64);
|
||||||
|
memory_copy(mesh->name, t.s, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "s"_s)) {
|
||||||
|
Obj_Token t = next_token(&data);
|
||||||
|
if (t.type == Obj_Token_Type::number) {
|
||||||
|
smoothing = (int)t.number;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(t.type == Obj_Token_Type::word);
|
||||||
|
if (string_compare(t.s8, "on"_s)) {
|
||||||
|
smoothing = 1;
|
||||||
|
}
|
||||||
|
else if (string_compare(t.s8, "off"_s)) {
|
||||||
|
smoothing = 0;
|
||||||
|
}
|
||||||
|
else invalid_codepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "g"_s)) {
|
||||||
|
Obj_Token t = next_token(&data);
|
||||||
|
assert(t.type == Obj_Token_Type::word);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (string_compare(token.s8, "f"_s)) {
|
||||||
|
Obj_Index *i = mesh->indices.push_empty_zero();
|
||||||
|
i->smoothing_group_id = smoothing;
|
||||||
|
i->material_id = material_id;
|
||||||
|
i->vertex[0] = (int)expect_number(&data);
|
||||||
|
expect_token(&data, '/');
|
||||||
|
i->tex[0] = (int)expect_number(&data);
|
||||||
|
if(match_token(&data, '/')) i->normal[0] = (int)expect_number(&data);
|
||||||
|
|
||||||
|
|
||||||
|
i->vertex[1] = (int)expect_number(&data);
|
||||||
|
expect_token(&data, '/');
|
||||||
|
i->tex[1] = (int)expect_number(&data);
|
||||||
|
if(match_token(&data, '/')) i->normal[1] = (int)expect_number(&data);
|
||||||
|
|
||||||
|
i->vertex[2] = (int)expect_number(&data);
|
||||||
|
expect_token(&data, '/');
|
||||||
|
i->tex[2] = (int)expect_number(&data);
|
||||||
|
if(match_token(&data, '/')) i->normal[2] = (int)expect_number(&data);
|
||||||
|
//debug_expect_raw(&data, Obj_Token_Type::whitespace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Obj
|
||||||
|
load_obj(Allocator *arena, String file) {
|
||||||
|
Scratch scratch;
|
||||||
|
String data = os_read_file(scratch, file);
|
||||||
|
assert(data.str);
|
||||||
|
|
||||||
|
String path = string_chop_last_slash(file);
|
||||||
|
Obj result = parse(arena, (char *)data.str, path);
|
||||||
|
result.name = file;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> void
|
||||||
|
dump_array(String_Builder *sb, Array<T> *arr){
|
||||||
|
sb->append_data(arr, sizeof(*arr));
|
||||||
|
sb->append_data(arr->data, sizeof(T)*arr->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
dump_bitmap_image(String_Builder *sb, Bitmap *bm){
|
||||||
|
sb->append_data(bm->pixels, sizeof(U32)*bm->x*bm->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function B32
|
||||||
|
_os_write_file(String file, String data, B32 append = false) {
|
||||||
|
B32 result = false;
|
||||||
|
DWORD access = GENERIC_WRITE;
|
||||||
|
DWORD creation_disposition = CREATE_ALWAYS;
|
||||||
|
if (append) {
|
||||||
|
access = FILE_APPEND_DATA;
|
||||||
|
creation_disposition = OPEN_ALWAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Todo(Krzosa): Unicode
|
||||||
|
HANDLE handle = CreateFileA((const char *)file.str, access, 0, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
|
DWORD bytes_written = 0;
|
||||||
|
// @Todo: can only read 32 byte size files?
|
||||||
|
assert_msg(data.len == (U32)data.len, "Max data size os_write can handle is 32 bytes, data to write is larger then 32 bytes!");
|
||||||
|
B32 error = WriteFile(handle, data.str, (U32)data.len, &bytes_written, NULL);
|
||||||
|
if (error == false) log_error("Failed to write to file: %Q", file);
|
||||||
|
else {
|
||||||
|
if (bytes_written != data.len) log_error("Failed to write to file: %Q, mismatch between length requested to write and length written", file);
|
||||||
|
else result = true;
|
||||||
|
}
|
||||||
|
CloseHandle(handle);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_error("File not found when trying to write: %Q", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function B32
|
||||||
|
os_write_file2(String file, String data) {
|
||||||
|
return _os_write_file(file, data, false);
|
||||||
|
}
|
||||||
|
function B32
|
||||||
|
os_append_file(String file, String data) {
|
||||||
|
return _os_write_file(file, data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
dump_obj_to_file(Obj *obj, String out_name){
|
||||||
|
obj->vertices.allocator = 0;
|
||||||
|
obj->vertices.cap = obj->vertices.len;
|
||||||
|
|
||||||
|
obj->texture_coordinates.allocator = 0;
|
||||||
|
obj->texture_coordinates.cap = obj->texture_coordinates.len;
|
||||||
|
|
||||||
|
obj->normals.allocator = 0;
|
||||||
|
obj->normals.cap = obj->normals.len;
|
||||||
|
|
||||||
|
obj->mesh.allocator = 0;
|
||||||
|
obj->mesh.cap = obj->mesh.len;
|
||||||
|
|
||||||
|
obj->materials.allocator = 0;
|
||||||
|
obj->materials.cap = obj->materials.len;
|
||||||
|
|
||||||
|
For(obj->mesh){
|
||||||
|
it.indices.allocator = 0;
|
||||||
|
it.indices.cap = it.indices.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scratch arena;
|
||||||
|
String_Builder sb = string_builder_make(arena, mib(4));
|
||||||
|
sb.append_data(obj, sizeof(Obj));
|
||||||
|
sb.append_data(obj->name.str, obj->name.len);
|
||||||
|
sb.append_data(obj->texture_coordinates.data, obj->texture_coordinates.len*sizeof(Vec2));
|
||||||
|
sb.append_data(obj->vertices.data, obj->vertices.len*sizeof(Vec3));
|
||||||
|
sb.append_data(obj->normals.data, obj->normals.len*sizeof(Vec3));
|
||||||
|
sb.append_data(obj->mesh.data, obj->mesh.len*sizeof(Obj_Mesh));
|
||||||
|
sb.append_data(obj->materials.data, obj->materials.len*sizeof(Obj_Material));
|
||||||
|
|
||||||
|
For(obj->mesh){
|
||||||
|
sb.append_data(it.indices.data, sizeof(Obj_Index)*it.indices.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
For(obj->materials){
|
||||||
|
sb.append_data(&it, sizeof(Obj_Material));
|
||||||
|
dump_bitmap_image(&sb, &it.texture_ambient);
|
||||||
|
dump_bitmap_image(&sb, &it.texture_diffuse);
|
||||||
|
dump_bitmap_image(&sb, &it.texture_dissolve);
|
||||||
|
dump_bitmap_image(&sb, &it.texture_displacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
String result = string_flatten(arena, &sb);
|
||||||
|
os_write_file2(out_name, result);
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ enum ProfileScopeName {
|
|||||||
ProfileScopeName_draw_mesh,
|
ProfileScopeName_draw_mesh,
|
||||||
ProfileScopeName_draw_set_of_mesh_indices,
|
ProfileScopeName_draw_set_of_mesh_indices,
|
||||||
ProfileScopeName_main_loop,
|
ProfileScopeName_main_loop,
|
||||||
|
ProfileScopeName_fill_triangle_after_depth_test,
|
||||||
ProfileScopeName_Count,
|
ProfileScopeName_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ const char *profile_scope_names[] = {
|
|||||||
"draw_mesh",
|
"draw_mesh",
|
||||||
"draw_set_of_mesh_indices",
|
"draw_set_of_mesh_indices",
|
||||||
"main_loop",
|
"main_loop",
|
||||||
|
"fill_triangle_after_depth_test",
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProfileState {
|
struct ProfileState {
|
||||||
|
|||||||
16
vec.cpp
Normal file
16
vec.cpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include <intrin.h>
|
||||||
|
|
||||||
|
union Vec8{
|
||||||
|
__m256 simd;
|
||||||
|
F32 e[8];
|
||||||
|
Vec4 v4[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Vec8 vec8(F32 x){return {_mm256_set1_ps(x)}; }
|
||||||
|
Vec8 vec8(F32 a, F32 b, F32 c, F32 d, F32 e, F32 f, F32 g, F32 h){ return {_mm256_set_ps(a,b,c,d,e,f,g,h)}; }
|
||||||
|
Vec8 operator+(Vec8 a, Vec8 b){ return {_mm256_add_ps(a.simd, b.simd)}; }
|
||||||
|
Vec8 operator-(Vec8 a, Vec8 b){ return {_mm256_sub_ps(a.simd, b.simd)}; }
|
||||||
|
Vec8 operator*(Vec8 a, Vec8 b){ return {_mm256_mul_ps(a.simd, b.simd)}; }
|
||||||
|
Vec8 operator/(Vec8 a, Vec8 b){ return {_mm256_div_ps(a.simd, b.simd)}; }
|
||||||
|
Vec8 operator+=(Vec8 &a, Vec8 b){ return a + b; }
|
||||||
Reference in New Issue
Block a user