Obj dump offsets textures for some reason, simplify abillity to use obj loader

directly, add timming, add Vec8
This commit is contained in:
Krzosa Karol
2022-07-01 09:17:32 +02:00
parent a7fa817992
commit 513bcabb18
8 changed files with 470 additions and 436 deletions

1
.gitignore vendored
View File

@@ -18,3 +18,4 @@ data.txt
*.bin *.bin
*.4c *.4c
asset.log.txt asset.log.txt
perfclocks.txt

View File

@@ -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);
} }

View 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

View File

@@ -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);

View File

@@ -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
View 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);
}

View File

@@ -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
View 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; }