diff --git a/build.sh b/build.sh index f2d342f..318d2ae 100755 --- a/build.sh +++ b/build.sh @@ -37,7 +37,7 @@ elif [ $target = wasm3 ] ; then elif [ $target = orca ] ; then echo "building orca" - # copies libraries + # copy libraries cp milepost/bin/mtl_renderer.metallib bin/ cp milepost/bin/libmilepost.dylib bin/ cp milepost/bin/libGLESv2.dylib bin/ @@ -51,6 +51,12 @@ elif [ $target = orca ] ; then ./scripts/bindgen.py core ./src ./scripts/bindgen.py gles ./src + ./scripts/bindgen2.py canvas \ + src/canvas_api.json \ + --guest-stubs sdk/graphics.c \ + --guest-include graphics.h \ + --wasm3-bindings ./src/canvas_api_bind_gen.c + # compile orca clang $FLAGS $INCLUDES $LIBS -o bin/orca src/main.c diff --git a/samples/pong/build.sh b/samples/pong/build.sh index 9a8b2e2..225b524 100755 --- a/samples/pong/build.sh +++ b/samples/pong/build.sh @@ -6,8 +6,10 @@ wasmFlags="--target=wasm32 \ -Wl,--no-entry \ -Wl,--export-all \ -Wl,--allow-undefined \ - -I ../../sdk" + -g \ + -D__ORCA__ \ + -I ../../sdk -I ../../milepost/src" -/usr/local/opt/llvm/bin/clang $wasmFlags -o ./module.wasm main.c +/usr/local/opt/llvm/bin/clang $wasmFlags -o ./module.wasm ../../sdk/graphics.c ../../sdk/orca.c main.c -python3 ../../scripts/mkapp.py --orca-dir ../.. --name Pong --icon icon.png module.wasm +#python3 ../../scripts/mkapp.py --orca-dir ../.. --name Pong --icon icon.png module.wasm diff --git a/samples/pong/main.c b/samples/pong/main.c index ca6b9f5..240eebd 100644 --- a/samples/pong/main.c +++ b/samples/pong/main.c @@ -6,16 +6,11 @@ * @revision: * *****************************************************************/ -#include"typedefs.h" -#include"keys.h" -#include"macro_helpers.h" -#include"GLES3/gl32.h" -typedef struct str8 -{ - unsigned long long len; - char* ptr; -} str8; +#include"keys.h" +#include"graphics.h" + +#include"orca.h" #define str8_lit(s) ((str8){.len = sizeof(s)-1, .ptr = (char*)(s)}) @@ -31,69 +26,10 @@ void log_string(str8 string) log_string_flat(string.len, string.ptr); } -unsigned int program; - -const char* vshaderSource = - "#version 300 es\n" - "precision mediump float;" - "layout(location=0) in vec4 vPosition;\n" - "layout(location=1) in vec4 aColor;\n" - "out vec4 vColor;\n" - "uniform mat4 transform;\n" - "void main()\n" - "{\n" - " gl_Position = transform*vPosition;\n" - " vColor = aColor;\n" - "}\n"; - -const char* fshaderSource = - "#version 300 es\n" - "precision mediump float;\n" - "out vec4 fragColor;\n" - "in vec4 vColor;\n" - "void main()\n" - "{\n" - " fragColor = vColor;\n" - "}\n"; - -void compile_shader(GLuint shader, const char* source) -{ - glShaderSource(shader, 1, &source, 0); - glCompileShader(shader); - - GLint success = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - if(success == GL_FALSE) - { - char message[1024]; - int length = 0; - glGetShaderInfoLog(shader, 1024, &length, message); - log_string(str8_lit("gl shader error: \n")); - log_string_flat(length, message); - } -} - -void OnInit(void) -{ - //log_string(str8_lit("init procedure\n")); - - unsigned int vshader = glCreateShader(GL_VERTEX_SHADER); - unsigned int fshader = glCreateShader(GL_FRAGMENT_SHADER); - program = glCreateProgram(); - - compile_shader(vshader, vshaderSource); - compile_shader(fshader, fshaderSource); - - glAttachShader(program, vshader); - glAttachShader(program, fshader); - glLinkProgram(program); - glUseProgram(program); -} - -const vec4 paddleColor = {1, 0, 0, 1}; +const g_color paddleColor = {1, 0, 0, 1}; mp_rect paddle = {200, 40, 200, 40}; -const vec4 ballColor = {1, 1, 0, 1}; +const g_color ballColor = {1, 1, 0, 1}; mp_rect ball = {200, 200, 60, 60}; vec2 velocity = {10, 10}; @@ -104,6 +40,14 @@ float rotationDir = 1; bool leftDown = false; bool rightDown = false; +g_font font; + +void OnInit(void) +{ + font = g_font_create_default(); + //log_string(str8_lit("init procedure\n")); +} + void OnFrameResize(u32 width, u32 height) { log_string(str8_lit("frame resize ")); @@ -113,10 +57,11 @@ void OnFrameResize(u32 width, u32 height) frameSize.x = width; frameSize.y = height; - +/* paddle.x = width/2. - paddle.w/2.; ball.x = width/2. - ball.w/2.; ball.y = height/2. - ball.h/2.; +*/ } void OnMouseDown(int button) @@ -148,82 +93,12 @@ void OnKeyUp(int key) } } -void debug_draw_rotating_triangle() -{ - static float alpha = 0; - f32 aspect = frameSize.x/frameSize.y; - - GLfloat matrix[] = {cosf(alpha)/aspect, sinf(alpha), 0, 0, - -sinf(alpha)/aspect, cosf(alpha), 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1}; - alpha += rotationDir*2*M_PI/120; - - glUniformMatrix4fv(0, 1, false, matrix); - - GLfloat vertices[] = { - -0.866/2, -0.5/2, 0, - 0.866/2, -0.5/2, 0, - 0, 0.5, 0}; - - GLfloat colors[] = { - 1, 0, 0, 1, - 0, 1, 0, 1, - 0, 0, 1, 1}; - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices); - glEnableVertexAttribArray(0); - - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, colors); - glEnableVertexAttribArray(1); - - glDrawArrays(GL_TRIANGLES, 0, 3); -} - -void draw_rect(mp_rect rect, vec4 color) -{ - GLfloat vertices[6*3] = { - rect.x, rect.y, 0, - rect.x, rect.y + rect.h, 0, - rect.x+rect.w, rect.y + rect.h, 0, - rect.x, rect.y, 0, - rect.x+rect.w, rect.y + rect.h, 0, - rect.x+rect.w, rect.y, 0}; - - GLfloat colors[6*4]; - for(int i=0; i<6*4; i+=4) - { - colors[i] = color.x; - colors[i+1] = color.y; - colors[i+2] = color.z; - colors[i+3] = color.w; - } - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices); - glEnableVertexAttribArray(0); - - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, colors); - glEnableVertexAttribArray(1); - - glDrawArrays(GL_TRIANGLES, 0, 6); -} - void OnFrameRefresh(void) { //log_string(str8_lit("frame procedure\n")); - glClearColor(0, 1, 1, 1); - glClear(GL_COLOR_BUFFER_BIT); - f32 aspect = frameSize.x/frameSize.y; - GLfloat matrix[] = {2./frameSize.x, 0, 0, 0, - 0, 2./frameSize.y, 0, 0, - 0, 0, 1, 0, - -1, -1, 0, 1}; - - glUniformMatrix4fv(0, 1, false, matrix); - if(leftDown) { paddle.x -= 10; @@ -267,6 +142,30 @@ void OnFrameRefresh(void) ball.y = frameSize.y/2. - ball.h; } - draw_rect(paddle, paddleColor); - draw_rect(ball, ballColor); + g_set_color_rgba(0, 1, 1, 1); + g_clear(); + + g_mat2x3 transform = {1, 0, 0, + 0, -1, frameSize.y}; + + g_matrix_push(transform); + + g_set_color(paddleColor); + g_rectangle_fill(paddle.x, paddle.y, paddle.w, paddle.h); + + g_set_color(ballColor); + g_circle_fill(ball.x+ball.w/2, ball.y + ball.w/2, ball.w/2.); + + + g_set_font(font); + g_set_font_size(16); + g_set_color_rgba(0, 0, 0, 1); + g_set_text_flip(true); + + str8 str = {.len = 13, .ptr = (char*)"Hello, world!"}; + g_move_to(10, 10); + g_text_outlines(str); + g_fill(); + + g_matrix_pop(); } diff --git a/scripts/bindgen.py b/scripts/bindgen.py index 348e108..a613977 100755 --- a/scripts/bindgen.py +++ b/scripts/bindgen.py @@ -20,7 +20,10 @@ outFile = open(outPath, 'w') stubs = [] links = [] -def gen_stub(name, sig): +def gen_stub(name, sig, native_name): + if native_name == None: + native_name = name + src = 'const void* ' + name + '_stub(IM3Runtime runtime, IM3ImportContext _ctx, uint64_t * _sp, void * _mem)\n' src += '{\n' spIndex = 0 @@ -56,7 +59,7 @@ def gen_stub(name, sig): print('returning pointers is not supported yet\n') break else: - print('unrecognized type ' + c + ' in procedure signature\n') + print('unrecognized type ' + c + ' in procedure return\n') break retCount += 1 else: @@ -83,7 +86,7 @@ def gen_stub(name, sig): argString += ', ' argCount += 1 - src += '\t' + retString + name + '(' + argString + ');\n' + src += '\t' + retString + native_name + '(' + argString + ');\n' src += '\treturn(0);\n' src += '}\n' stubs.append(src) @@ -104,7 +107,8 @@ for line in inFile: if line.isspace(): continue desc = line.split() - gen_stub(desc[0], desc[1]) + + gen_stub(desc[0], desc[1], desc[2] if len(desc) > 2 else None) gen_link(desc[0], desc[1]) linkProc = 'int bindgen_link_' + apiName + '_api(IM3Module module)\n' diff --git a/scripts/mkapp.py b/scripts/mkapp.py index fc6e781..8276434 100644 --- a/scripts/mkapp.py +++ b/scripts/mkapp.py @@ -76,6 +76,7 @@ if args.res_dirs != None: for res in args.res_dirs: shutil.copytree(res, res_dir) +shutil.copy(args.orca_dir + '/resources/OpenSansLatinSubset.ttf', res_dir) #----------------------------------------------------------- #NOTE make icon #----------------------------------------------------------- diff --git a/sdk/macro_helpers.h b/sdk/macro_helpers.h deleted file mode 100644 index a38c0b3..0000000 --- a/sdk/macro_helpers.h +++ /dev/null @@ -1,129 +0,0 @@ -/************************************************************//** -* -* @file: macro_helpers.h -* @author: Martin Fouilleul -* @date: 27/03/2020 -* @revision: -* -*****************************************************************/ -#ifndef __MACRO_HELPERS_H_ -#define __MACRO_HELPERS_H_ - -//NOTE(martin): macro concatenation -#define _cat2_(a, b) a##b -#define _cat3_(a, b, c) a##b##c - - -//NOTE(martin): inline, but still generate code -// (eg. use the inline version inside a library, but still exports the function for client code) -//TODO(martin): this is a compiler-specific attribute, recognized by clang and gcc. See if there's a more portable approach -//#define INLINE_GEN __attribute__((used)) static inline - - -//NOTE(martin): typed and array mallocs -#define malloc_type(type) ((type*)malloc(sizeof(type))) -#define malloc_array(type, count) ((type*)malloc(sizeof(type)*count)) - -//NOTE(martin): 'hygienic' templates, to replace macros and avoid multiple evaluation problems. -#ifdef __cplusplus - //NOTE(martin): in C++ we use templates and decltype/declval - // (overloaded functions would be ambiguous because of the - // overload resolution and conversion/promotion rules) - - #include - - template - inline decltype(std::declval()+std::declval()) minimum_safe(Ta a, Tb b) - { - return(a < b ? a : b); - } - - template - inline decltype(std::declval()+std::declval()) maximum_safe(Ta a, Tb b) - { - return(a > b ? a : b); - } - - template - inline T square_safe(T a) {return(a*a);} - - template - inline T cube_safe(T a) {return(a*a*a);} - -#else // (__cplusplus not defined) - - //NOTE(martin): Type generic arithmetic functions helpers - // this macros helps generate variants of a generic 'template' for all arithmetic types. - // the def parameter must be a macro that take a type, and optional arguments - #define tga_generate_variants(def, ...) \ - def(u8, ##__VA_ARGS__) def(i8, ##__VA_ARGS__ ) def(u16, ##__VA_ARGS__) def(i16, ##__VA_ARGS__) \ - def(u32, ##__VA_ARGS__) def(i32, ##__VA_ARGS__) def(u64, ##__VA_ARGS__) def(i64, ##__VA_ARGS__) \ - def(f32, ##__VA_ARGS__) def(f64, ##__VA_ARGS__) - - // This macro generates the name of a typed variant - #define tga_variant_name(name, type) _cat3_(name, _, type) - - // This macro generates a _Generic association between a type and its variant - #define tga_variant_association(type, name) , type: tga_variant_name(name, type) - - // This macros selects the appropriate variant for a 2 parameters functions - #define tga_select_binary(name, a, b) \ - _Generic((a+b) tga_generate_variants(tga_variant_association, name))(a, b) - - // This macros selects the appropriate variant for a 1 parameters functions - #define tga_select_unary(name, a) \ - _Generic((a) tga_generate_variants(tga_variant_association, name))(a) - - //NOTE(martin): type generic templates - #define minimum_def(type) static inline type tga_variant_name(minimum_safe, type)(type a, type b) {return(a < b ? a : b);} - #define maximum_def(type) static inline type tga_variant_name(maximum_safe, type)(type a, type b) {return(a > b ? a : b);} - #define square_def(type) static inline type tga_variant_name(square_safe, type)(type a) {return(a*a);} - #define cube_def(type) static inline type tga_variant_name(cube_safe, type)(type a) {return(a*a*a);} - - //NOTE(martin): instantiante our templates for all arithmetic types - tga_generate_variants(minimum_def) - tga_generate_variants(maximum_def) - tga_generate_variants(square_def) - tga_generate_variants(cube_def) - - //NOTE(martin): select the correct variant according to the argument types - #define minimum_safe(a, b) tga_select_binary(minimum_safe, a, b) - #define maximum_safe(a, b) tga_select_binary(maximum_safe, a, b) - #define square_safe(a) tga_select_unary(square_safe, a) - #define cube_safe(a) tga_select_unary(cube_safe, a) - -#endif // __cplusplus else branch - - -//NOTE(martin): these macros are calling the safe functions defined above, so they don't evaluate their -// arguments twice - -#define minimum(a, b) minimum_safe(a, b) -#define maximum(a, b) maximum_safe(a, b) - -#define ClampLowBound(a, low) (maximum((a), (low))) -#define ClampHighBound(a, high) (minimum((a), (high))) -#define Clamp(a, low, high) (ClampLowBound(ClampHighBound((a), (high)), (low))) - -#define Square(a) square_safe(a) -#define Cube(a) cube_safe(a) - -#define AlignUpOnPow2(x, a) (((x) + (a) - 1) & ~((a)-1)) -#define AlignDownOnPow2(x, a) ((x) & ~((a)-1)) - -static inline u64 next_pow2_u64(u64 x) -{ - x--; - x |= x>>1; - x |= x>>2; - x |= x>>4; - x |= x>>8; - x |= x>>16; - x |= x>>32; - x++; - return(x); -} - -#define defer_loop(begin, end) begin; for(int __i__=0; __i__<1; __i__++, end) - -#endif //__MACRO_HELPERS_H_ diff --git a/src/main.c b/src/main.c index 4200d32..d9d77f4 100644 --- a/src/main.c +++ b/src/main.c @@ -6,6 +6,7 @@ * *****************************************************************/ #include +#include #include #include @@ -29,7 +30,48 @@ void log_int(int i) printf("%i ", i); } +void mg_matrix_push_flat(float a11, float a12, float a13, + float a21, float a22, float a23) +{ + mg_mat2x3 m = {a11, a12, a13, a21, a22, a23}; + mg_matrix_push(m); +} + +mg_font mg_font_create_default() +{ + //NOTE(martin): create default font + str8 fontPath = mp_app_get_resource_path(mem_scratch(), "../resources/OpenSansLatinSubset.ttf"); + char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath); + + FILE* fontFile = fopen(fontPathCString, "r"); + if(!fontFile) + { + LOG_ERROR("Could not load font file '%s': %s\n", fontPathCString, strerror(errno)); + return(mg_font_nil()); + } + unsigned char* fontData = 0; + fseek(fontFile, 0, SEEK_END); + u32 fontDataSize = ftell(fontFile); + rewind(fontFile); + fontData = (unsigned char*)malloc(fontDataSize); + fread(fontData, 1, fontDataSize, fontFile); + fclose(fontFile); + + unicode_range ranges[5] = {UNICODE_RANGE_BASIC_LATIN, + UNICODE_RANGE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT, + UNICODE_RANGE_LATIN_EXTENDED_A, + UNICODE_RANGE_LATIN_EXTENDED_B, + UNICODE_RANGE_SPECIALS}; + + mg_font font = mg_font_create_from_memory(fontDataSize, fontData, 5, ranges); + + free(fontData); + + return(font); +} + #include"bindgen_core_api.c" +#include"canvas_api_bind.c" #include"bindgen_gles_api.c" #include"manual_gles_api.c" @@ -37,6 +79,7 @@ typedef struct orca_app { mp_window window; mg_surface surface; + mg_surface mtlSurface; mg_canvas canvas; } orca_app; @@ -188,6 +231,7 @@ void* orca_runloop(void* user) //NOTE: bind orca APIs bindgen_link_core_api(module); + bindgen_link_canvas_api(module); bindgen_link_gles_api(module); manual_link_gles_api(module); @@ -319,7 +363,9 @@ void* orca_runloop(void* user) case MP_EVENT_WINDOW_RESIZE: { - //TODO: resize surface! + mp_rect frame = {0, 0, event.frame.rect.w, event.frame.rect.h}; + mg_surface_set_frame(app->surface, frame); + if(eventHandlers[G_EVENT_FRAME_RESIZE]) { u32 width = (u32)event.frame.rect.w; @@ -385,7 +431,7 @@ void* orca_runloop(void* user) } } - mg_surface_prepare(app->surface); +/* mg_surface_prepare(app->surface); glClearColor(1, 0, 1, 1); glClear(GL_COLOR_BUFFER_BIT); @@ -395,6 +441,17 @@ void* orca_runloop(void* user) } mg_surface_present(app->surface); +*/ + + mg_canvas_prepare(app->canvas); + + if(eventHandlers[G_EVENT_FRAME_REFRESH]) + { + m3_Call(eventHandlers[G_EVENT_FRAME_REFRESH], 0, 0); + } + + mg_present(); + //TODO: update and render mem_scratch_clear(); } @@ -427,9 +484,14 @@ int main(int argc, char** argv) mp_window_bring_to_front(window); mp_window_focus(window); + mg_surface mtlSurface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT); + mg_surface_swap_interval(mtlSurface, 1); + mg_canvas canvas = mg_canvas_create(mtlSurface); + orca_app app = {.window = window, - .surface = surface}; -// .canvas = canvas}; + .surface = surface, + .mtlSurface = mtlSurface, + .canvas = canvas}; pthread_t runloopThread; pthread_create(&runloopThread, 0, orca_runloop, &app);