Signals
This commit is contained in:
92
main.cpp
92
main.cpp
@@ -38,9 +38,15 @@
|
|||||||
/// - [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
|
||||||
/// - [ ] Effects!!!
|
/// - [ ] Effects!!!
|
||||||
|
/// - [ ] Outlines
|
||||||
/// - [ ] Lightning
|
/// - [ ] Lightning
|
||||||
/// - [x] GLOBAL Ilumination
|
/// - [ ] Proper normal interpolation
|
||||||
|
/// * https://hero.handmade.network/episode/code/day101/#105
|
||||||
/// - [ ] Phong
|
/// - [ ] Phong
|
||||||
|
/// - [x] diffuse
|
||||||
|
/// - [x] ambient
|
||||||
|
/// - [ ] specular
|
||||||
|
/// * reflecting vectors
|
||||||
/// - [ ] Use all materials from OBJ
|
/// - [ ] Use all materials from OBJ
|
||||||
/// - [ ] Point light
|
/// - [ ] Point light
|
||||||
/// - [ ] Reading PMX files
|
/// - [ ] Reading PMX files
|
||||||
@@ -62,6 +68,7 @@
|
|||||||
/// - [ ] UI
|
/// - [ ] UI
|
||||||
/// - [x] Labels
|
/// - [x] Labels
|
||||||
/// - [x] Settings variables
|
/// - [x] Settings variables
|
||||||
|
/// - [x] Signals
|
||||||
/// - [ ] Sliders
|
/// - [ ] Sliders
|
||||||
/// - [ ] Groups
|
/// - [ ] Groups
|
||||||
/// - [x] Gamma correct alpha blending for rectangles and bitmaps
|
/// - [x] Gamma correct alpha blending for rectangles and bitmaps
|
||||||
@@ -113,10 +120,10 @@ enum Scene {
|
|||||||
Scene_Count,
|
Scene_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
GLOBAL B32 draw_rects = 0;
|
|
||||||
GLOBAL Scene scene = Scene_Sponza;
|
|
||||||
GLOBAL F32 zfar_value = 100000.f;
|
|
||||||
GLOBAL F32 light_rotation = 0;
|
GLOBAL F32 light_rotation = 0;
|
||||||
|
GLOBAL F32 zfar_value = 100000.f;
|
||||||
|
|
||||||
|
|
||||||
FUNCTION
|
FUNCTION
|
||||||
Vec4 srgb_to_almost_linear(Vec4 a) {
|
Vec4 srgb_to_almost_linear(Vec4 a) {
|
||||||
@@ -380,15 +387,16 @@ void draw_triangle_nearest(Bitmap* dst, F32 *depth_buffer, Bitmap *src, Vec3 lig
|
|||||||
dst_color = { r,g,b,a };
|
dst_color = { r,g,b,a };
|
||||||
}
|
}
|
||||||
|
|
||||||
F32 light = -dot(norm, light_direction);
|
Vec3 light_color = vec3(0.8,0.8,1);
|
||||||
{
|
constexpr F32 ambient_strength = 0.1f; {
|
||||||
light = CLAMP(0.1f, light, 1.f);
|
Vec3 ambient = ambient_strength * light_color;
|
||||||
result_color.r *= light;
|
Vec3 diffuse = CLAMP_BOT(0, -dot(norm, light_direction)) * light_color;
|
||||||
result_color.g *= light;
|
result_color.rgb *= (ambient+diffuse);
|
||||||
result_color.b *= light;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
result_color = premultiplied_alpha(dst_color, result_color);
|
result_color = premultiplied_alpha(dst_color, result_color);
|
||||||
result_color = almost_linear_to_srgb(result_color);
|
result_color = almost_linear_to_srgb(result_color);
|
||||||
U32 color32 = vec4_to_u32abgr(result_color);
|
U32 color32 = vec4_to_u32abgr(result_color);
|
||||||
@@ -408,11 +416,7 @@ void draw_triangle_nearest(Bitmap* dst, F32 *depth_buffer, Bitmap *src, Vec3 lig
|
|||||||
Cy2 -= dx02;
|
Cy2 -= dx02;
|
||||||
destination += dst->x;
|
destination += dst->x;
|
||||||
}
|
}
|
||||||
if (draw_rects) {
|
|
||||||
r_draw_rect(dst, p0.x-4, p0.y-4, 8,8, vec4(1,0,0,1));
|
|
||||||
r_draw_rect(dst, p1.x-4, p1.y-4, 8,8, vec4(0,1,0,1));
|
|
||||||
r_draw_rect(dst, p2.x-4, p2.y-4, 8,8, vec4(0,0,1,1));
|
|
||||||
}
|
|
||||||
if(os.frame > 60) PROFILE_END(draw_triangle);
|
if(os.frame > 60) PROFILE_END(draw_triangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,11 +493,6 @@ void draw_triangle_bilinear(Bitmap* dst, F32 *depth_buffer, Bitmap *src, F32 lig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (draw_rects) {
|
|
||||||
r_draw_rect(dst, p0.x-4, p0.y-4, 8,8, vec4(1,0,0,1));
|
|
||||||
r_draw_rect(dst, p1.x-4, p1.y-4, 8,8, vec4(0,1,0,1));
|
|
||||||
r_draw_rect(dst, p2.x-4, p2.y-4, 8,8, vec4(0,0,1,1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION
|
FUNCTION
|
||||||
@@ -668,6 +667,31 @@ void r_draw_mesh(R_Render *r, S8 scene_name, OBJMaterial *materials, ObjMesh *me
|
|||||||
}
|
}
|
||||||
#include "ui.cpp"
|
#include "ui.cpp"
|
||||||
|
|
||||||
|
F32 speed = 100.f;
|
||||||
|
F32 rotation = 0;
|
||||||
|
Obj f22;
|
||||||
|
Obj sponza;
|
||||||
|
Obj *obj;
|
||||||
|
R_Render r = {};
|
||||||
|
GLOBAL Scene scene = Scene_Sponza;
|
||||||
|
UI_SIGNAL_CALLBACK(scene_callback) {
|
||||||
|
switch(scene) {
|
||||||
|
case Scene_F22: {
|
||||||
|
speed = 1;
|
||||||
|
r.camera_pos = vec3(0,0,-2);
|
||||||
|
obj = &f22;
|
||||||
|
} break;
|
||||||
|
case Scene_Sponza: {
|
||||||
|
speed = 100;
|
||||||
|
r.camera_pos = vec3(0,0,-2);
|
||||||
|
obj = &sponza;
|
||||||
|
} break;
|
||||||
|
case Scene_Count:
|
||||||
|
INVALID_DEFAULT_CASE;
|
||||||
|
}
|
||||||
|
scene = (Scene)(((int)scene + 1) % Scene_Count);
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
os.window_size.x = 320*2;
|
os.window_size.x = 320*2;
|
||||||
os.window_size.y = 180*2;
|
os.window_size.y = 180*2;
|
||||||
@@ -691,16 +715,13 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Obj f22 = load_obj(os.perm_arena, LIT("assets/f22.obj"));
|
f22 = load_obj(os.perm_arena, LIT("assets/f22.obj"));
|
||||||
Obj sponza = load_obj(os.perm_arena, LIT("assets/sponza/sponza.obj"));
|
sponza = load_obj(os.perm_arena, LIT("assets/sponza/sponza.obj"));
|
||||||
Obj *obj = 0;
|
scene_callback();
|
||||||
|
|
||||||
F32 speed = 100.f;
|
|
||||||
F32 rotation = 0;
|
|
||||||
|
|
||||||
int screen_x = 1280/2;
|
int screen_x = 1280/2;
|
||||||
int screen_y = 720/2;
|
int screen_y = 720/2;
|
||||||
R_Render r = {};
|
|
||||||
r.camera_pos = {0,0,-2};
|
r.camera_pos = {0,0,-2};
|
||||||
r.screen320 = {(U32 *)PUSH_SIZE(os.perm_arena, screen_x*screen_y*sizeof(U32)), screen_x, screen_y};
|
r.screen320 = {(U32 *)PUSH_SIZE(os.perm_arena, screen_x*screen_y*sizeof(U32)), screen_x, screen_y};
|
||||||
r.plot = {(U32 *)PUSH_SIZE(os.perm_arena, 1280*720*sizeof(U32)), 1280, 720};
|
r.plot = {(U32 *)PUSH_SIZE(os.perm_arena, 1280*720*sizeof(U32)), 1280, 720};
|
||||||
@@ -728,8 +749,7 @@ int main() {
|
|||||||
|
|
||||||
S8 frame_data = {};
|
S8 frame_data = {};
|
||||||
UISetup setup[] = {
|
UISetup setup[] = {
|
||||||
UI_BOOL(LIT("Draw rectangles:"), &draw_rects),
|
UI_SIGNAL(LIT("Change scene"), scene_callback),
|
||||||
UI_OPTION(LIT("Scene:"), &scene, Scene_Count),
|
|
||||||
UI_IMAGE(&r.plot),
|
UI_IMAGE(&r.plot),
|
||||||
UI_LABEL(&frame_data),
|
UI_LABEL(&frame_data),
|
||||||
};
|
};
|
||||||
@@ -737,18 +757,7 @@ int main() {
|
|||||||
B32 ui_mouse_lock = true;
|
B32 ui_mouse_lock = true;
|
||||||
|
|
||||||
while (os_game_loop()) {
|
while (os_game_loop()) {
|
||||||
switch(scene) {
|
|
||||||
case Scene_F22: {
|
|
||||||
speed = 1;
|
|
||||||
obj = &f22;
|
|
||||||
} break;
|
|
||||||
case Scene_Sponza: {
|
|
||||||
speed = 100;
|
|
||||||
obj = &sponza;
|
|
||||||
} break;
|
|
||||||
case Scene_Count:
|
|
||||||
INVALID_DEFAULT_CASE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ui_mouse_lock == false) {
|
if (ui_mouse_lock == false) {
|
||||||
r.camera_yaw.x += os.delta_mouse_pos.x * 0.01f;
|
r.camera_yaw.x += os.delta_mouse_pos.x * 0.01f;
|
||||||
@@ -757,7 +766,6 @@ int main() {
|
|||||||
if (os.key[Key_Escape].pressed) os_quit();
|
if (os.key[Key_Escape].pressed) os_quit();
|
||||||
if (os.key[Key_O].down) light_rotation += 0.05f;
|
if (os.key[Key_O].down) light_rotation += 0.05f;
|
||||||
if (os.key[Key_P].down) light_rotation -= 0.05f;
|
if (os.key[Key_P].down) light_rotation -= 0.05f;
|
||||||
if (os.key[Key_F1].pressed) draw_rects = !draw_rects;
|
|
||||||
if (os.key[Key_F2].pressed) {
|
if (os.key[Key_F2].pressed) {
|
||||||
ui_mouse_lock = !ui_mouse_lock;
|
ui_mouse_lock = !ui_mouse_lock;
|
||||||
os_show_cursor(!os.cursor_visible);
|
os_show_cursor(!os.cursor_visible);
|
||||||
|
|||||||
138
obj_parser.cpp
138
obj_parser.cpp
@@ -86,13 +86,12 @@ Bitmap load_image(const char* path) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace obj {
|
enum class OBJTokenType {
|
||||||
enum class TokenType {
|
|
||||||
none, word, number, whitespace, end
|
none, word, number, whitespace, end
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Token {
|
struct OBJToken {
|
||||||
TokenType type;
|
OBJTokenType type;
|
||||||
double number;
|
double number;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
@@ -101,22 +100,22 @@ namespace obj {
|
|||||||
};
|
};
|
||||||
S8 s8;
|
S8 s8;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
FUNCTION Token next_token_raw(char** data) {
|
FUNCTION OBJToken next_token_raw(char** data) {
|
||||||
Token result = {};
|
OBJToken result = {};
|
||||||
result.s = *data;
|
result.s = *data;
|
||||||
*data += 1;
|
*data += 1;
|
||||||
|
|
||||||
if (is_alphabetic(*result.s)) {
|
if (is_alphabetic(*result.s)) {
|
||||||
result.type = TokenType::word;
|
result.type = OBJTokenType::word;
|
||||||
while (!is_whitespace(**data)) {
|
while (!is_whitespace(**data)) {
|
||||||
*data += 1;
|
*data += 1;
|
||||||
}
|
}
|
||||||
result.len = (int)(*data - result.s);
|
result.len = (int)(*data - result.s);
|
||||||
}
|
}
|
||||||
else if (is_number(*result.s) || *result.s == '-') {
|
else if (is_number(*result.s) || *result.s == '-') {
|
||||||
result.type = TokenType::number;
|
result.type = OBJTokenType::number;
|
||||||
while (is_number(**data) || **data == '.' || **data == 'e' || **data == '-') {
|
while (is_number(**data) || **data == '.' || **data == 'e' || **data == '-') {
|
||||||
*data += 1;
|
*data += 1;
|
||||||
}
|
}
|
||||||
@@ -128,53 +127,53 @@ namespace obj {
|
|||||||
result = next_token_raw(data);
|
result = next_token_raw(data);
|
||||||
}
|
}
|
||||||
else if (is_whitespace(*result.s)) {
|
else if (is_whitespace(*result.s)) {
|
||||||
result.type = TokenType::whitespace;
|
result.type = OBJTokenType::whitespace;
|
||||||
while (is_whitespace(**data)) *data += 1;
|
while (is_whitespace(**data)) *data += 1;
|
||||||
result.len = (int)(*data - result.s);
|
result.len = (int)(*data - result.s);
|
||||||
}
|
}
|
||||||
else if (*result.s == 0) {
|
else if (*result.s == 0) {
|
||||||
result.type = TokenType::end;
|
result.type = OBJTokenType::end;
|
||||||
}
|
}
|
||||||
else if (*result.s >= '!') {
|
else if (*result.s >= '!') {
|
||||||
result.type = (TokenType)*result.s;
|
result.type = (OBJTokenType)*result.s;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION Token next_token(char** data) {
|
FUNCTION OBJToken next_token(char** data) {
|
||||||
Token result;
|
OBJToken result;
|
||||||
do {
|
do {
|
||||||
result = next_token_raw(data);
|
result = next_token_raw(data);
|
||||||
} while (result.type == TokenType::whitespace);
|
} while (result.type == OBJTokenType::whitespace);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION double expect_number(char** data) {
|
FUNCTION double expect_number(char** data) {
|
||||||
Token t = next_token(data);
|
OBJToken t = next_token(data);
|
||||||
TASSERT(t.type == TokenType::number); // @Todo: Error handling, error flag
|
TASSERT(t.type == OBJTokenType::number); // @Todo: Error handling, error flag
|
||||||
return t.number;
|
return t.number;
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION void expect_token(char** data, char token) {
|
FUNCTION void expect_token(char** data, char token) {
|
||||||
Token t = next_token(data);
|
OBJToken t = next_token(data);
|
||||||
TASSERT(t.type == (TokenType)token); // @Todo: Error handling, error flag
|
TASSERT(t.type == (OBJTokenType)token); // @Todo: Error handling, error flag
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION void debug_expect_raw(char** data, TokenType type) {
|
FUNCTION void debug_expect_raw(char** data, OBJTokenType type) {
|
||||||
char* data_temp = *data;
|
char* data_temp = *data;
|
||||||
Token t = next_token_raw(&data_temp);
|
OBJToken t = next_token_raw(&data_temp);
|
||||||
TASSERT(t.type == type);
|
TASSERT(t.type == type);
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION void parse_mtl(Arena *arena, Obj* obj, S8 path_obj_folder, S8 mtl_file) {
|
FUNCTION void parse_mtl(Arena *arena, Obj* obj, S8 path_obj_folder, S8 mtl_file) {
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
char *data = (char *)mtl_file.str;
|
char *data = (char *)mtl_file.str;
|
||||||
OBJMaterial *m = 0;
|
OBJMaterial *m = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
Token token = next_token(&data);
|
OBJToken token = next_token(&data);
|
||||||
if (token.type == TokenType::end) break;
|
if (token.type == OBJTokenType::end) break;
|
||||||
else if (token.type == TokenType::word) {
|
else if (token.type == OBJTokenType::word) {
|
||||||
if (string_compare(token.s8, LIT("newmtl"))) {
|
if (string_compare(token.s8, LIT("newmtl"))) {
|
||||||
token = next_token(&data);
|
token = next_token(&data);
|
||||||
m = obj->materials.push_empty();
|
m = obj->materials.push_empty();
|
||||||
@@ -210,30 +209,30 @@ namespace obj {
|
|||||||
m->illumination_model = (I32)expect_number(&data);
|
m->illumination_model = (I32)expect_number(&data);
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("map_Kd"))) {
|
else if (string_compare(token.s8, LIT("map_Kd"))) {
|
||||||
Token t = next_token(&data);
|
OBJToken t = next_token(&data);
|
||||||
S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8);
|
S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8);
|
||||||
m->texture_diffuse = load_image((const char *)path.str);
|
m->texture_diffuse = load_image((const char *)path.str);
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("map_Ka"))) {
|
else if (string_compare(token.s8, LIT("map_Ka"))) {
|
||||||
Token t = next_token(&data);
|
OBJToken t = next_token(&data);
|
||||||
S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8);
|
S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8);
|
||||||
m->texture_ambient = load_image((const char *)path.str);
|
m->texture_ambient = load_image((const char *)path.str);
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("map_d"))) {
|
else if (string_compare(token.s8, LIT("map_d"))) {
|
||||||
Token t = next_token(&data);
|
OBJToken t = next_token(&data);
|
||||||
S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8);
|
S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8);
|
||||||
m->texture_dissolve = load_image((const char *)path.str);
|
m->texture_dissolve = load_image((const char *)path.str);
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("map_Disp"))) {
|
else if (string_compare(token.s8, LIT("map_Disp"))) {
|
||||||
Token t = next_token(&data);
|
OBJToken t = next_token(&data);
|
||||||
S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8);
|
S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8);
|
||||||
m->texture_displacment = load_image((const char *)path.str);
|
m->texture_displacment = load_image((const char *)path.str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION Obj parse(Arena *arena, char* data, S8 path_obj_folder) {
|
FUNCTION Obj parse(Arena *arena, char* data, S8 path_obj_folder) {
|
||||||
Scratch mtl_scratch;
|
Scratch mtl_scratch;
|
||||||
Obj result = {};
|
Obj result = {};
|
||||||
int smoothing = 0;
|
int smoothing = 0;
|
||||||
@@ -242,31 +241,31 @@ namespace obj {
|
|||||||
int material_id = -1;
|
int material_id = -1;
|
||||||
|
|
||||||
for (;; ) {
|
for (;; ) {
|
||||||
Token token = next_token(&data);
|
OBJToken token = next_token(&data);
|
||||||
if (token.type == TokenType::end) break;
|
if (token.type == OBJTokenType::end) break;
|
||||||
else if (token.type == TokenType::word) {
|
else if (token.type == OBJTokenType::word) {
|
||||||
if (string_compare(token.s8, LIT("v"))) {
|
if (string_compare(token.s8, LIT("v"))) {
|
||||||
Vec3 *vertex = result.vertices.push_empty();
|
Vec3 *vertex = result.vertices.push_empty();
|
||||||
vertex->x = (float)expect_number(&data);
|
vertex->x = (float)expect_number(&data);
|
||||||
vertex->y = (float)expect_number(&data);
|
vertex->y = (float)expect_number(&data);
|
||||||
vertex->z = (float)expect_number(&data);
|
vertex->z = (float)expect_number(&data);
|
||||||
debug_expect_raw(&data, TokenType::whitespace);
|
debug_expect_raw(&data, OBJTokenType::whitespace);
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("vt"))) {
|
else if (string_compare(token.s8, LIT("vt"))) {
|
||||||
Vec2 *tex = result.texture_coordinates.push_empty();
|
Vec2 *tex = result.texture_coordinates.push_empty();
|
||||||
tex->x = (float)expect_number(&data);
|
tex->x = (float)expect_number(&data);
|
||||||
tex->y = (float)expect_number(&data);
|
tex->y = (float)expect_number(&data);
|
||||||
debug_expect_raw(&data, TokenType::whitespace);
|
debug_expect_raw(&data, OBJTokenType::whitespace);
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("vn"))) {
|
else if (string_compare(token.s8, LIT("vn"))) {
|
||||||
Vec3 *norm = result.normals.push_empty();
|
Vec3 *norm = result.normals.push_empty();
|
||||||
norm->x = (float)expect_number(&data);
|
norm->x = (float)expect_number(&data);
|
||||||
norm->y = (float)expect_number(&data);
|
norm->y = (float)expect_number(&data);
|
||||||
norm->z = (float)expect_number(&data);
|
norm->z = (float)expect_number(&data);
|
||||||
debug_expect_raw(&data, TokenType::whitespace);
|
debug_expect_raw(&data, OBJTokenType::whitespace);
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("mtllib"))) {
|
else if (string_compare(token.s8, LIT("mtllib"))) {
|
||||||
Token t = next_token(&data);
|
OBJToken t = next_token(&data);
|
||||||
S8 path = string_format(mtl_scratch, "%s/%s", path_obj_folder, t.s8);
|
S8 path = string_format(mtl_scratch, "%s/%s", path_obj_folder, t.s8);
|
||||||
Result<S8> mtl_file = os_read_file(mtl_scratch, path);
|
Result<S8> mtl_file = os_read_file(mtl_scratch, path);
|
||||||
if(mtl_file.no_error()) {
|
if(mtl_file.no_error()) {
|
||||||
@@ -275,8 +274,8 @@ namespace obj {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("usemtl"))) {
|
else if (string_compare(token.s8, LIT("usemtl"))) {
|
||||||
Token t = next_token(&data);
|
OBJToken t = next_token(&data);
|
||||||
TASSERT(t.type == TokenType::word);
|
TASSERT(t.type == OBJTokenType::word);
|
||||||
for(U64 i = 0; i < result.materials.len; i++) {
|
for(U64 i = 0; i < result.materials.len; i++) {
|
||||||
OBJMaterial *m = result.materials.e + i;
|
OBJMaterial *m = result.materials.e + i;
|
||||||
if(string_compare(string_make((U8 *)m->name, m->name_len), t.s8)) {
|
if(string_compare(string_make((U8 *)m->name, m->name_len), t.s8)) {
|
||||||
@@ -286,8 +285,8 @@ namespace obj {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("o"))) {
|
else if (string_compare(token.s8, LIT("o"))) {
|
||||||
Token t = next_token(&data);
|
OBJToken t = next_token(&data);
|
||||||
TASSERT(t.type == TokenType::word);
|
TASSERT(t.type == OBJTokenType::word);
|
||||||
if (mesh->indices.len != 0) {
|
if (mesh->indices.len != 0) {
|
||||||
mesh = result.mesh.push_empty();
|
mesh = result.mesh.push_empty();
|
||||||
ZERO_STRUCT(mesh);
|
ZERO_STRUCT(mesh);
|
||||||
@@ -298,12 +297,12 @@ namespace obj {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("s"))) {
|
else if (string_compare(token.s8, LIT("s"))) {
|
||||||
Token t = next_token(&data);
|
OBJToken t = next_token(&data);
|
||||||
if (t.type == TokenType::number) {
|
if (t.type == OBJTokenType::number) {
|
||||||
smoothing = (int)t.number;
|
smoothing = (int)t.number;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TASSERT(t.type == TokenType::word);
|
TASSERT(t.type == OBJTokenType::word);
|
||||||
if (string_compare(t.s8, LIT("on"))) {
|
if (string_compare(t.s8, LIT("on"))) {
|
||||||
smoothing = 1;
|
smoothing = 1;
|
||||||
}
|
}
|
||||||
@@ -315,8 +314,8 @@ namespace obj {
|
|||||||
|
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("g"))) {
|
else if (string_compare(token.s8, LIT("g"))) {
|
||||||
Token t = next_token(&data);
|
OBJToken t = next_token(&data);
|
||||||
TASSERT(t.type == TokenType::word);
|
TASSERT(t.type == OBJTokenType::word);
|
||||||
}
|
}
|
||||||
else if (string_compare(token.s8, LIT("f"))) {
|
else if (string_compare(token.s8, LIT("f"))) {
|
||||||
ObjIndex *i = mesh->indices.push_empty();
|
ObjIndex *i = mesh->indices.push_empty();
|
||||||
@@ -339,34 +338,33 @@ namespace obj {
|
|||||||
i->tex[2] = (int)expect_number(&data);
|
i->tex[2] = (int)expect_number(&data);
|
||||||
expect_token(&data, '/');
|
expect_token(&data, '/');
|
||||||
i->normal[2] = (int)expect_number(&data);
|
i->normal[2] = (int)expect_number(&data);
|
||||||
//debug_expect_raw(&data, TokenType::whitespace);
|
//debug_expect_raw(&data, OBJTokenType::whitespace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION void test_lex() {
|
FUNCTION void test_lex() {
|
||||||
const char* d = "v 0.885739 0.001910 -0.380334";
|
const char* d = "v 0.885739 0.001910 -0.380334";
|
||||||
char* dd = (char *)d;
|
char* dd = (char *)d;
|
||||||
TASSERT(next_token(&dd).type == TokenType::word);
|
TASSERT(next_token(&dd).type == OBJTokenType::word);
|
||||||
Token t = next_token(&dd); TASSERT(t.type == TokenType::number && t.number > 0.8857);
|
OBJToken t = next_token(&dd); TASSERT(t.type == OBJTokenType::number && t.number > 0.8857);
|
||||||
t = next_token(&dd); TASSERT(t.type == TokenType::number && t.number > 0.0019);
|
t = next_token(&dd); TASSERT(t.type == OBJTokenType::number && t.number > 0.0019);
|
||||||
t = next_token(&dd); TASSERT(t.type == TokenType::number && t.number < -0.38);
|
t = next_token(&dd); TASSERT(t.type == OBJTokenType::number && t.number < -0.38);
|
||||||
d = "# Blender v2.79 (sub 0) OBJ File: 'fighters_0.blend'\n"
|
d = "# Blender v2.79 (sub 0) OBJ File: 'fighters_0.blend'\n"
|
||||||
"# www.blender.org\n"
|
"# www.blender.org\n"
|
||||||
"mtllib f-22.mtl\n"
|
"mtllib f-22.mtl\n"
|
||||||
"o F-22\n";
|
"o F-22\n";
|
||||||
dd = (char *)d;
|
dd = (char *)d;
|
||||||
t = next_token(&dd); TASSERT(t.type == TokenType::word && string_compare(t.s8, LIT("mtllib")));
|
t = next_token(&dd); TASSERT(t.type == OBJTokenType::word && string_compare(t.s8, LIT("mtllib")));
|
||||||
t = next_token(&dd); TASSERT(t.type == TokenType::word && string_compare(t.s8, LIT("f-22.mtl")));
|
t = next_token(&dd); TASSERT(t.type == OBJTokenType::word && string_compare(t.s8, LIT("f-22.mtl")));
|
||||||
t = next_token(&dd); TASSERT(t.type == TokenType::word && string_compare(t.s8, LIT("o")));
|
t = next_token(&dd); TASSERT(t.type == OBJTokenType::word && string_compare(t.s8, LIT("o")));
|
||||||
t = next_token(&dd); TASSERT(t.type == TokenType::word && string_compare(t.s8, LIT("F-22")));
|
t = next_token(&dd); TASSERT(t.type == OBJTokenType::word && string_compare(t.s8, LIT("F-22")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
test_lex();
|
test_lex();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION Obj load_obj(Arena *arena, S8 file) {
|
FUNCTION Obj load_obj(Arena *arena, S8 file) {
|
||||||
@@ -374,7 +372,7 @@ FUNCTION Obj load_obj(Arena *arena, S8 file) {
|
|||||||
S8 data = os_read_file(scratch, file).error_is_fatal();
|
S8 data = os_read_file(scratch, file).error_is_fatal();
|
||||||
PUSH_SIZE(scratch, 1);
|
PUSH_SIZE(scratch, 1);
|
||||||
S8 path = string_chop_last_slash(file);
|
S8 path = string_chop_last_slash(file);
|
||||||
Obj result = obj::parse(arena, (char *)data.str, path);
|
Obj result = parse(arena, (char *)data.str, path);
|
||||||
result.name = file;
|
result.name = file;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
33
ui.cpp
33
ui.cpp
@@ -4,9 +4,12 @@ enum UIWidgetKind {
|
|||||||
UIWidgetKind_Image,
|
UIWidgetKind_Image,
|
||||||
UIWidgetKind_Label,
|
UIWidgetKind_Label,
|
||||||
UIWidgetKind_Option,
|
UIWidgetKind_Option,
|
||||||
|
UIWidgetKind_Signal,
|
||||||
UIWidgetKind_Group,
|
UIWidgetKind_Group,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define UI_SIGNAL_CALLBACK(name) void name()
|
||||||
|
typedef UI_SIGNAL_CALLBACK(UISignalCallback);
|
||||||
struct UISetup {
|
struct UISetup {
|
||||||
UIWidgetKind kind;
|
UIWidgetKind kind;
|
||||||
S8 text;
|
S8 text;
|
||||||
@@ -16,6 +19,7 @@ struct UISetup {
|
|||||||
B32 *b32;
|
B32 *b32;
|
||||||
S8 *label;
|
S8 *label;
|
||||||
I32 *option;
|
I32 *option;
|
||||||
|
UISignalCallback *signal_callback;
|
||||||
};
|
};
|
||||||
I32 option_max;
|
I32 option_max;
|
||||||
};
|
};
|
||||||
@@ -23,6 +27,7 @@ struct UISetup {
|
|||||||
#define UI_IMAGE(x) {UIWidgetKind_Image,string_null,(void*)(x)}
|
#define UI_IMAGE(x) {UIWidgetKind_Image,string_null,(void*)(x)}
|
||||||
#define UI_LABEL(x) {UIWidgetKind_Label,string_null,(void*)(x)}
|
#define UI_LABEL(x) {UIWidgetKind_Label,string_null,(void*)(x)}
|
||||||
#define UI_OPTION(text,x,option_max){UIWidgetKind_Option,text,(void*)(x),(option_max)}
|
#define UI_OPTION(text,x,option_max){UIWidgetKind_Option,text,(void*)(x),(option_max)}
|
||||||
|
#define UI_SIGNAL(text,x){UIWidgetKind_Signal,text,(void*)(x)}
|
||||||
|
|
||||||
struct UIWidget {
|
struct UIWidget {
|
||||||
UIWidgetKind kind;
|
UIWidgetKind kind;
|
||||||
@@ -39,6 +44,7 @@ struct UIWidget {
|
|||||||
B32 *b32;
|
B32 *b32;
|
||||||
S8 *label;
|
S8 *label;
|
||||||
I32 *option;
|
I32 *option;
|
||||||
|
UISignalCallback *signal_callback;
|
||||||
} ptr;
|
} ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -96,6 +102,13 @@ FUNCTION UIWidget *ui_push_option(Arena *arena, UIWidget *widget, S8 string, I32
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FUNCTION UIWidget *ui_push_signal(Arena *arena, UIWidget *widget, S8 string, UISignalCallback *callback) {
|
||||||
|
UIWidget *result = ui_push_child(arena, widget, UIWidgetKind_Signal);
|
||||||
|
result->text = string;
|
||||||
|
result->ptr.signal_callback = callback;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
FUNCTION UI ui_make(Arena *arena, UISetup *setup, U64 len) {
|
FUNCTION UI ui_make(Arena *arena, UISetup *setup, U64 len) {
|
||||||
UI result = {};
|
UI result = {};
|
||||||
result.arena = arena_sub(arena, MiB(16));
|
result.arena = arena_sub(arena, MiB(16));
|
||||||
@@ -114,6 +127,9 @@ FUNCTION UI ui_make(Arena *arena, UISetup *setup, U64 len) {
|
|||||||
case UIWidgetKind_Option: {
|
case UIWidgetKind_Option: {
|
||||||
ui_push_option(&result.arena, parent, s->text, s->option, s->option_max);
|
ui_push_option(&result.arena, parent, s->text, s->option, s->option_max);
|
||||||
} break;
|
} break;
|
||||||
|
case UIWidgetKind_Signal: {
|
||||||
|
ui_push_signal(&result.arena, parent, s->text, s->signal_callback);
|
||||||
|
} break;
|
||||||
INVALID_DEFAULT_CASE;
|
INVALID_DEFAULT_CASE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,6 +219,23 @@ FUNCTION void ui_end_frame(Bitmap *dst, UI *ui, Font *font) {
|
|||||||
rect = r_draw_string(dst, font, string, pos);
|
rect = r_draw_string(dst, font, string, pos);
|
||||||
pos.y -= rect.height - font->height;
|
pos.y -= rect.height - font->height;
|
||||||
} break;
|
} break;
|
||||||
|
case UIWidgetKind_Signal: {
|
||||||
|
pos.y -= font->height;
|
||||||
|
Vec4 color = vec4(0, 0, 0, 1);
|
||||||
|
S8 string = string_format(scratch, "%s", w->text);
|
||||||
|
rect = r_get_string_rect(font, string, pos);
|
||||||
|
B32 clicked = ui_mouse_test(ui, w, rect);
|
||||||
|
if (clicked) {
|
||||||
|
w->ptr.signal_callback();
|
||||||
|
}
|
||||||
|
if (ui->hot == w) {
|
||||||
|
color = vec4(0.4f, 0.4f, 0.4f, 1.f);
|
||||||
|
}
|
||||||
|
rect.y = rect.y-font->line_advance / 5;
|
||||||
|
r_draw_rect(dst, rect.x, rect.y, rect.width, rect.height, color);
|
||||||
|
rect = r_draw_string(dst, font, string, pos);
|
||||||
|
pos.y -= rect.height - font->height;
|
||||||
|
} break;
|
||||||
INVALID_DEFAULT_CASE;
|
INVALID_DEFAULT_CASE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user