From d991712b3caea3f5a82165411a1ef231a4d759db Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sat, 23 Jan 2021 10:25:40 +0100 Subject: [PATCH] gg: native rendering mode on macOS --- CHANGELOG.md | 2 +- cmd/tools/vtest-cleancode.v | 1 + examples/x/websocket/client-server/client.v | 2 +- thirdparty/fontstash/fontstash.h | 2 +- thirdparty/sokol/sokol_app.h | 97 ++++++++++- thirdparty/sokol/sokol_app2.h | 33 ++++ vlib/fontstash/fontstash.v | 7 +- vlib/gg/gg.v | 24 +++ vlib/gg/gg_darwin.c.v | 16 ++ vlib/gg/gg_darwin.m | 111 +++++++++++++ vlib/gg/image.v | 27 ++++ vlib/gg/text_rendering.v | 30 ++++ vlib/net/socket_options.c.v | 2 +- vlib/os/os.v | 7 +- vlib/os/os_darwin.c.v | 3 + vlib/os/os_darwin.m | 7 + vlib/sokol/sapp/sapp.v | 86 +++++----- vlib/sokol/sapp/sapp_structs.v | 150 +++++++++--------- vlib/v/builder/cc.v | 6 +- vlib/v/gen/js/tests/interp.v | 2 +- vlib/v/parser/parser.v | 4 +- vlib/v/tests/array_slice_test.v | 2 +- vlib/v/tests/comptime_if_expr_test.v | 2 +- vlib/v/tests/defer_test.v | 2 +- vlib/v/tests/filter_in_map_test.v | 2 +- vlib/v/tests/imported_symbols_test.v | 2 +- .../match_sumtype_var_shadow_and_as_test.v | 2 +- .../methods_struct_test.v | 2 +- vlib/v/tests/valgrind/1.strings_and_arrays.v | 5 + vlib/x/ttf/common.v | 2 +- vlib/x/ttf/text_block.v | 2 +- vlib/x/ttf/ttf.v | 2 +- 32 files changed, 492 insertions(+), 152 deletions(-) create mode 100644 thirdparty/sokol/sokol_app2.h create mode 100644 vlib/os/os_darwin.m diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b821af0d6..6f8c377b20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ - Consts can now be declared outside of `const()` blocks: `const x = 0`. - Overloading of `>`, `<`, `!=`, `==`, `<=` and `>=` operators. - New struct updating syntax: `User{ ...u, name: 'new' }` to replace `{ u | name: 'new' }`. -- `byte.str()` has been fixed and works like with all other numbers. `byte.ascii_str()` has been added. +- `byte.str()` has been fixed and works like all other numbers. `byte.ascii_str()` has been added. - Smart cast in for loops: `for mut x is string {}`. - `[noinit]` struct attribute to disallow direct struct initialization with `Foo{}`. - Array decompose: `[1, 2, 3]...` is now `...[1, 2, 3]` diff --git a/cmd/tools/vtest-cleancode.v b/cmd/tools/vtest-cleancode.v index 26f9dec6ff..664e72d99c 100644 --- a/cmd/tools/vtest-cleancode.v +++ b/cmd/tools/vtest-cleancode.v @@ -22,6 +22,7 @@ const ( 'vlib/bitfield/', 'vlib/builtin/array.v', 'vlib/builtin/array_test.v', + 'vlib/builtin/string.v', 'vlib/builtin/map.v', 'vlib/math/bits/bits.v', 'vlib/orm/', diff --git a/examples/x/websocket/client-server/client.v b/examples/x/websocket/client-server/client.v index 9fe35675a6..71f2c31f04 100644 --- a/examples/x/websocket/client-server/client.v +++ b/examples/x/websocket/client-server/client.v @@ -57,4 +57,4 @@ fn start_client() ?&websocket.Client { println(term.red('error on listen $err')) } return ws -} \ No newline at end of file +} diff --git a/thirdparty/fontstash/fontstash.h b/thirdparty/fontstash/fontstash.h index 649feda8d0..ce0eebddd8 100644 --- a/thirdparty/fontstash/fontstash.h +++ b/thirdparty/fontstash/fontstash.h @@ -174,7 +174,7 @@ FONS_DEF void fonsDrawDebug(FONScontext* s, float x, float y); #undef FONS_USE_FREETYPE -//#define FONS_USE_FREETYPE +//#define FONS_USE_FREETYPE 1 #ifdef FONS_USE_FREETYPE diff --git a/thirdparty/sokol/sokol_app.h b/thirdparty/sokol/sokol_app.h index e83bc5db93..cc306b9bf9 100644 --- a/thirdparty/sokol/sokol_app.h +++ b/thirdparty/sokol/sokol_app.h @@ -971,6 +971,7 @@ typedef struct sapp_desc { bool html5_ask_leave_site; /* initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site()) */ bool ios_keyboard_resizes_canvas; /* if true, showing the iOS keyboard shrinks the canvas */ bool gl_force_gles2; /* if true, setup GLES2/WebGL even if GLES3/WebGL2 is available */ + bool native_render; } sapp_desc; /* user-provided functions */ @@ -1360,12 +1361,18 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } } @end + @interface MyView2 : NSView + @end + + MyView2* g_view; + // A custom NSWindow interface to handle events in borderless windows. @implementation SokolWindow - (BOOL)canBecomeKeyWindow { return YES; } // needed for NSWindowStyleMaskBorderless - (BOOL)canBecomeMainWindow { return YES; } @end + @interface _sapp_macos_app_delegate : NSObject @end @interface _sapp_macos_window_delegate : NSObject @@ -1846,6 +1853,7 @@ typedef struct { char window_title[_SAPP_MAX_TITLE_LENGTH]; /* UTF-8 */ wchar_t window_title_wide[_SAPP_MAX_TITLE_LENGTH]; /* UTF-32 or UCS-2 */ sapp_keycode keycodes[SAPP_MAX_KEYCODES]; +bool native_render; } _sapp_t; static _sapp_t _sapp; @@ -2235,7 +2243,23 @@ _SOKOL_PRIVATE void _sapp_call_init(void) { _sapp.init_called = true; } + + _SOKOL_PRIVATE void _sapp_call_frame(void) { + if (_sapp.native_render) { + return; + } + if (_sapp.init_called && !_sapp.cleanup_called) { + if (_sapp.desc.frame_cb) { + _sapp.desc.frame_cb(); + } + else if (_sapp.desc.frame_userdata_cb) { + _sapp.desc.frame_userdata_cb(_sapp.desc.user_data); + } + } +} + +_SOKOL_PRIVATE void _sapp_call_frame2(void) { if (_sapp.init_called && !_sapp.cleanup_called) { if (_sapp.desc.frame_cb) { _sapp.desc.frame_cb(); @@ -2328,6 +2352,7 @@ _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { _sapp.dpi_scale = 1.0f; _sapp.fullscreen = _sapp.desc.fullscreen; _sapp.mouse.shown = true; + _sapp.native_render = _sapp.desc.native_render; } _SOKOL_PRIVATE void _sapp_discard_state(void) { @@ -2740,6 +2765,27 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp.macos.window.title = [NSString stringWithUTF8String:_sapp.window_title]; _sapp.macos.window.acceptsMouseMovedEvents = YES; _sapp.macos.window.restorable = YES; + _sapp.macos.window.backgroundColor = [NSColor whiteColor]; + + // Quit menu + NSMenu* menu_bar = [[NSMenu alloc] init]; +NSMenuItem* app_menu_item = [[NSMenuItem alloc] init]; +[menu_bar addItem:app_menu_item]; +NSApp.mainMenu = menu_bar; +NSMenu* app_menu = [[NSMenu alloc] init]; +NSString* window_title_as_nsstring = [NSString stringWithUTF8String:_sapp.window_title]; +// `quit_title` memory will be owned by the NSMenuItem, so no need to release it ourselves +NSString* quit_title = [@"Quit " stringByAppendingString:window_title_as_nsstring]; +NSMenuItem* quit_menu_item = [[NSMenuItem alloc] + initWithTitle:quit_title + action:@selector(terminate:) + keyEquivalent:@"q"]; +[app_menu addItem:quit_menu_item]; +app_menu_item.submenu = app_menu; +_SAPP_OBJC_RELEASE( window_title_as_nsstring ); +_SAPP_OBJC_RELEASE( app_menu ); +_SAPP_OBJC_RELEASE( app_menu_item ); +_SAPP_OBJC_RELEASE( menu_bar ); _sapp.macos.win_dlg = [[_sapp_macos_window_delegate alloc] init]; _sapp.macos.window.delegate = _sapp.macos.win_dlg; @@ -2796,6 +2842,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp.macos.window.contentView = _sapp.macos.view; [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; + NSTimer* timer_obj = [NSTimer timerWithTimeInterval:0.001 target:_sapp.macos.view selector:@selector(timerFired:) @@ -2814,6 +2861,40 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { [_sapp.macos.window center]; } */ + + + /////////////////////////////////////////////////////// + + CGRect wRect = _sapp.macos.window.frame; +NSView *contentView =_sapp.macos.window.contentView; +CGRect cRect = contentView.frame; + +CGRect rect = CGRectMake(wRect.origin.x, wRect.origin.y, cRect.size.width, cRect.size.height); +NSWindow *overlayWindow = [[NSWindow alloc]initWithContentRect:rect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; +//overlayWindow.backgroundColor = [NSColor whiteColor]; + + + +//overlayWindow.backgroundColor = [[NSColor whiteColor] colorWithAlphaComponent:0]; +[overlayWindow setOpaque:YES]; +[_sapp.macos.window setIgnoresMouseEvents:NO]; +//[_sapp.macos.window setOpaque:NO]; + + + +//overlayWindow.alphaValue =0.1f;///.1f; + +g_view = [[MyView2 alloc] init]; + overlayWindow.contentView = g_view; + +[ contentView addSubview:g_view]; +//[ _sapp.macos.window addChildWindow:overlayWindow ordered:NSWindowAbove]; + + ////////////////////////////////// + [_sapp.macos.window center]; [_sapp.macos.window makeKeyAndOrderFront:nil]; _sapp_macos_update_dimensions(); @@ -2832,6 +2913,8 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } @end +#include "/Users/alex/code/v/thirdparty/sokol/sokol_app2.h" + @implementation _sapp_macos_window_delegate - (BOOL)windowShouldClose:(id)sender { _SOKOL_UNUSED(sender); @@ -2884,6 +2967,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } @end + @implementation _sapp_macos_view #if defined(SOKOL_GLCORE33) /* NOTE: this is a hack/fix when the initial window size has been clipped by @@ -2912,9 +2996,13 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } #endif +//int g_is_native = 0; + - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); _sapp_macos_frame(); +// puts("drawRect() metal"); +// NSLog(@"rect %@", NSStringFromRect(rect)); #if !defined(SOKOL_METAL) [[_sapp.macos.view openGLContext] flushBuffer]; #endif @@ -2929,6 +3017,10 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { - (BOOL)acceptsFirstResponder { return YES; } + + - (BOOL)acceptsFirstMouse:(NSEvent *)event { + return YES; + } - (void)updateTrackingAreas { if (_sapp.macos.tracking_area != nil) { [self removeTrackingArea:_sapp.macos.tracking_area]; @@ -2953,6 +3045,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } } - (void)mouseExited:(NSEvent*)event { + // NSLog(@"mouse exited"); if (0 == _sapp.macos.mouse_buttons) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); } @@ -3002,11 +3095,13 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags)); } - (void)mouseDragged:(NSEvent*)event { + //puts("(void)mouseDragged"); if (_sapp.mouse.locked) { _sapp.mouse.dx = [event deltaX]; _sapp.mouse.dy = [event deltaY]; } - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags)); + // QTODO hack INVALID=>MIDDLE macos bug + _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_MIDDLE , _sapp_macos_mod(event.modifierFlags)); } - (void)rightMouseDragged:(NSEvent*)event { if (_sapp.mouse.locked) { diff --git a/thirdparty/sokol/sokol_app2.h b/thirdparty/sokol/sokol_app2.h new file mode 100644 index 0000000000..cd2acf766c --- /dev/null +++ b/thirdparty/sokol/sokol_app2.h @@ -0,0 +1,33 @@ + +@implementation MyView2 + +// Alternative drawRect which calls a frame function with native Cocoa calls +- (void)drawRect:(NSRect)rect { + _sapp_call_frame2(); +} + +//- (BOOL)isOpaque { +// return NO; +//} + +- (BOOL)canBecomeKeyView { + return YES; +} +- (BOOL)acceptsFirstResponder { + return YES; +} + +- (void)mouseExited:(NSEvent*)event { +} + +- (void)mouseDown:(NSEvent*)event { + } + +- (BOOL)acceptsFirstMouse:(NSEvent *)event { + return YES; +} + + +@end + + diff --git a/vlib/fontstash/fontstash.v b/vlib/fontstash/fontstash.v index 8413afb4e0..35a1f25e02 100644 --- a/vlib/fontstash/fontstash.v +++ b/vlib/fontstash/fontstash.v @@ -1,10 +1,10 @@ module fontstash #flag -I @VROOT/thirdparty/fontstash - #define FONTSTASH_IMPLEMENTATION #include "fontstash.h" - +#flag -I /usr/local/Cellar/freetype/2.10.2/include/freetype2 +//#flag -lfreetype pub const ( // TODO: fontstash.used_import is used to keep v from warning about unused imports used_import = 1 @@ -22,7 +22,7 @@ pub fn delete_internal(s &C.FONScontext) { } [inline] -pub fn (s &C.FONScontext) set_error_callback(callback fn(uptr voidptr, error int, val int), uptr voidptr) { +pub fn (s &C.FONScontext) set_error_callback(callback fn (voidptr, int, int), uptr voidptr) { C.fonsSetErrorCallback(s, callback, uptr) } @@ -156,4 +156,3 @@ pub fn (s &C.FONScontext) validate_texture(dirty &int) int { pub fn (s &C.FONScontext) draw_debug(x f32, y f32) { C.fonsDrawDebug(s, x, y) } - diff --git a/vlib/gg/gg.v b/vlib/gg/gg.v index e27d8d0cd1..bbc8620644 100644 --- a/vlib/gg/gg.v +++ b/vlib/gg/gg.v @@ -40,6 +40,7 @@ pub: bg_color gx.Color init_fn FNCb = voidptr(0) frame_fn FNCb = voidptr(0) + native_frame_fn FNCb = voidptr(0) cleanup_fn FNCb = voidptr(0) fail_fn FNFail = voidptr(0) event_fn FNEvent = voidptr(0) @@ -65,6 +66,7 @@ pub: font_bytes_bold []byte font_bytes_mono []byte font_bytes_italic []byte + native_rendering bool // Cocoa on macOS/iOS, GDI+ on Windows } pub struct Context { @@ -75,6 +77,8 @@ mut: image_cache []Image needs_refresh bool = true ticks int +pub: + native_rendering bool pub mut: scale f32 = 1.0 // will get set to 2.0 for retina, will remain 1.0 for normal @@ -169,6 +173,9 @@ fn gg_init_sokol_window(user_data voidptr) { g.config.init_fn(g.config.user_data) } // Create images now that we can do that after sg is inited + if g.native_rendering { + return + } for i in 0 .. g.image_cache.len { g.image_cache[i].init_sokol_image() } @@ -179,6 +186,9 @@ fn gg_frame_fn(user_data voidptr) { if ctx.config.frame_fn == voidptr(0) { return } + if ctx.native_rendering { + // return + } if ctx.ui_mode && !ctx.needs_refresh { // Draw 3 more frames after the "stop refresh" command ctx.ticks++ @@ -256,6 +266,7 @@ pub fn new_context(cfg Config) &Context { render_text: cfg.font_path != '' || cfg.font_bytes_normal.len > 0 ft: 0 ui_mode: cfg.ui_mode + native_rendering: cfg.native_rendering } g.set_bg_color(cfg.bg_color) // C.printf('new_context() %p\n', cfg.user_data) @@ -273,6 +284,7 @@ pub fn new_context(cfg Config) &Context { sample_count: cfg.sample_count high_dpi: true fullscreen: cfg.fullscreen + native_render: cfg.native_rendering } if cfg.use_ortho { } else { @@ -292,6 +304,12 @@ pub fn (mut ctx Context) set_bg_color(c gx.Color) { // TODO: Fix alpha pub fn (ctx &Context) draw_rect(x f32, y f32, w f32, h f32, c gx.Color) { + $if macos { + if ctx.native_rendering { + C.darwin_draw_rect(x, ctx.height - (y + h), w, h, c) + return + } + } if c.a != 255 { sgl.load_pipeline(ctx.timage_pip) } @@ -357,6 +375,12 @@ pub fn (ctx &Context) draw_circle_line(x f32, y f32, r int, segments int, c gx.C } pub fn (ctx &Context) draw_circle(x f32, y f32, r f32, c gx.Color) { + $if macos { + if ctx.native_rendering { + C.darwin_draw_circle(x - r + 1, ctx.height - (y + r + 3), r, c) + return + } + } if ctx.scale == 1 { ctx.draw_circle_with_segments(x, y, r, 10, c) } else { diff --git a/vlib/gg/gg_darwin.c.v b/vlib/gg/gg_darwin.c.v index 808cd5fbed..9bcdcb9229 100644 --- a/vlib/gg/gg_darwin.c.v +++ b/vlib/gg/gg_darwin.c.v @@ -2,3 +2,19 @@ module gg #include "@VROOT/vlib/gg/gg_darwin.m" fn C.gg_get_screen_size() Size + +fn C.darwin_draw_string(x int, y int, s string) + +fn C.darwin_text_width(s string) int + +fn C.darwin_window_refresh() + +fn C.darwin_draw_rect(f32, f32, f32, f32) + +fn C.darwin_create_image() Image + +fn C.darwin_draw_image(f32, f32, f32, f32, &Image) + +fn C.darwin_draw_circle(f32, f32, f32) + +//, gx.Color c) diff --git a/vlib/gg/gg_darwin.m b/vlib/gg/gg_darwin.m index 83b1a09284..4342d6ca3a 100644 --- a/vlib/gg/gg_darwin.m +++ b/vlib/gg/gg_darwin.m @@ -1,5 +1,18 @@ #include +NSColor* nscolor(gx__Color c) { + float red= (float)c.r / 255.0f; + float green= (float)c.g / 255.0f; + float blue= (float)c.b / 255.0f; + return [NSColor colorWithDeviceRed:red green:green blue:blue alpha:1.0f]; +} + +NSString* nsstring(string s) { + return [ [ NSString alloc ] initWithBytesNoCopy:s.str length:s.len + encoding:NSUTF8StringEncoding freeWhenDone: false]; +} + + gg__Size gg_get_screen_size() { NSScreen *screen = [NSScreen mainScreen]; NSDictionary *description = [screen deviceDescription]; @@ -12,3 +25,101 @@ gg__Size gg_get_screen_size() { return res; } +void darwin_draw_string(int x, int y, string s, gx__TextCfg cfg) { + NSFont* font = [NSFont userFontOfSize: 0]; //cfg.size]; + // # NSFont* font = [NSFont fontWithName:@"Roboto Mono" size:cfg.size]; + if (cfg.mono) { + // # font = [NSFont fontWithName:@"Roboto Mono" size:cfg.size]; + font = [NSFont fontWithName:@"Menlo" size:cfg.size-5]; + } +if (cfg.bold) { + font = [[NSFontManager sharedFontManager] convertFont:font toHaveTrait:NSBoldFontMask]; +} + + + NSDictionary* attr = @{ +NSForegroundColorAttributeName: nscolor(cfg.color), +//NSParagraphStyleAttributeName: paragraphStyle, +NSFontAttributeName: font, +}; + [nsstring(s) drawAtPoint:NSMakePoint(x,y-15) withAttributes:attr]; +} + +int darwin_text_width(string s) { + // println('text_width "$s" len=$s.len') + NSString* n = @""; + if (s.len == 1) { + // println('len=1') + n=[NSString stringWithFormat:@"%c" , s.str[0]]; + } + else { + n = nsstring(s); + } + /* + # if (!defaultFont){ + # defaultFont = [NSFont userFontOfSize: ui__DEFAULT_FONT_SIZE]; + # } + # NSDictionary *attrs = @{ + # NSFontAttributeName: defaultFont, + # }; + */ + NSSize size = [n sizeWithAttributes:nil]; + // # printf("!!!%f\n", ceil(size.width)); + return (int)(ceil(size.width)); +} + + +void darwin_draw_rect(float x, float y, float width, float height, gx__Color c) { + NSColor* color = nscolor(c); + NSRect rect = NSMakeRect(x, y, width, height); + [color setFill]; + NSRectFill(rect); +} + + +void darwin_window_refresh() { + //[g_view setNeedsDisplay:YES]; + // update UI on the main thread TODO separate fn + dispatch_async(dispatch_get_main_queue(), ^{ + [g_view setNeedsDisplay:YES]; + }); + + //puts("refresh"); + //[g_view drawRect:NSMakeRect(0,0,2000,2000)]; + //[[NSGraphicsContext currentContext] flushGraphics]; +} + +gg__Image darwin_create_image(string path_) { + // file = file.trim_space() + NSString* path = nsstring(path_); + NSImage* img = [[NSImage alloc] initWithContentsOfFile:path]; + if (img == 0) { + } + NSSize size = [img size]; + gg__Image res; + res.width = size.width; + res.height = size.height; + res.path = path_; + res.ok = true; + //printf("inited img width=%d\n", res.width) ; + // need __brige_retained so that the pointer is not freed by ARC + res.data = (__bridge_retained voidptr)(img); + return res; +} + +void darwin_draw_image(float x, float y, float w, float h, gg__Image* img) { + NSImage* i= (__bridge NSImage*)(img->data); + [i drawInRect:NSMakeRect(x,y,w,h)]; +} + +void darwin_draw_circle(float x, float y, float d, gx__Color color) { + NSColor* c = nscolor(color); + NSRect rect = NSMakeRect(x, y, d * 2, d * 2); + NSBezierPath* circlePath = [NSBezierPath bezierPath]; + [circlePath appendBezierPathWithOvalInRect: rect]; + [c setFill]; + // [circlePath stroke]; + [circlePath fill]; + // NSRectFill(rect); +} + diff --git a/vlib/gg/image.v b/vlib/gg/image.v index 0133cc7142..59ecb503c4 100644 --- a/vlib/gg/image.v +++ b/vlib/gg/image.v @@ -28,6 +28,21 @@ fn C.sg_isvalid() bool // TODO return ?Image pub fn (mut ctx Context) create_image(file string) Image { + // println('\ncreate_image("$file")') + if !os.exists(file) { + return Image{} + } + $if macos { + if ctx.native_rendering { + // return C.darwin_create_image(file) + mut img := C.darwin_create_image(file) + // println('created macos image: $img.path w=$img.width') + // C.printf('p = %p\n', img.data) + img.id = ctx.image_cache.len + ctx.image_cache << img + return img + } + } if !C.sg_isvalid() { // Sokol is not initialized yet, add stbi object to a queue/cache // ctx.image_queue << file @@ -142,6 +157,18 @@ pub fn (ctx &Context) draw_image(x f32, y f32, width f32, height f32, img_ &Imag return } img := ctx.image_cache[img_.id] // fetch the image from cache + $if macos { + if ctx.native_rendering { + if img_.width == 0 { + return + } + if !os.exists(img_.path) { + return + } + C.darwin_draw_image(x, ctx.height - (y + height), width, height, img_) + return + } + } if !img.simg_ok { return } diff --git a/vlib/gg/text_rendering.v b/vlib/gg/text_rendering.v index 5ef49f805e..2e51611196 100644 --- a/vlib/gg/text_rendering.v +++ b/vlib/gg/text_rendering.v @@ -35,6 +35,13 @@ struct FTConfig { bytes_italic []byte } +struct StringToRender { + x int + y int + text string + cfg gx.TextCfg +} + fn new_ft(c FTConfig) ?&FT { if c.font_path == '' { if c.bytes_normal.len > 0 { @@ -150,6 +157,17 @@ fn (ctx &Context) set_cfg(cfg gx.TextCfg) { } pub fn (ctx &Context) draw_text(x int, y int, text_ string, cfg gx.TextCfg) { + $if macos { + if ctx.native_rendering { + if cfg.align == gx.align_right { + width := ctx.text_width(text_) + C.darwin_draw_string(x - width, ctx.height - y, text_, cfg) + } else { + C.darwin_draw_string(x, ctx.height - y, text_, cfg) + } + return + } + } if !ctx.font_inited { eprintln('gg: draw_text(): font not initialized') return @@ -177,6 +195,11 @@ pub fn (ft &FT) flush() { } pub fn (ctx &Context) text_width(s string) int { + $if macos { + if ctx.native_rendering { + return C.darwin_text_width(s) + } + } // ctx.set_cfg(cfg) TODO if !ctx.font_inited { return 0 @@ -187,6 +210,13 @@ pub fn (ctx &Context) text_width(s string) int { return int((buf[2] - buf[0]) / ctx.scale) + ctx.text_width('i') // TODO fix this in fontstash? } + res := int((buf[2] - buf[0]) / ctx.scale) + // println('TW "$s" = $res') + $if macos { + if ctx.native_rendering { + return res * 2 + } + } return int((buf[2] - buf[0]) / ctx.scale) } diff --git a/vlib/net/socket_options.c.v b/vlib/net/socket_options.c.v index 705f2975fa..5decc9bd30 100644 --- a/vlib/net/socket_options.c.v +++ b/vlib/net/socket_options.c.v @@ -52,4 +52,4 @@ const ( .send_low_size, .send_timeout, ] -) \ No newline at end of file +) diff --git a/vlib/os/os.v b/vlib/os/os.v index 79f098e81c..5d3d1b10d9 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -457,7 +457,12 @@ pub fn walk(path string, f fn (string)) { // log will print "os.log: "+`s` ... pub fn log(s string) { - println('os.log: ' + s) + //$if macos { + // Use NSLog() on macos + //C.darwin_log(s) + //} $else { + println('os.log: ' + s) + //} } [deprecated] diff --git a/vlib/os/os_darwin.c.v b/vlib/os/os_darwin.c.v index 9fea518b75..7b0a0cd769 100644 --- a/vlib/os/os_darwin.c.v +++ b/vlib/os/os_darwin.c.v @@ -3,6 +3,7 @@ // that can be found in the LICENSE file. module os +#include "@VROOT/vlib/os/os_darwin.m" pub const ( sys_write = 4 sys_open = 5 @@ -12,3 +13,5 @@ pub const ( sys_open_nocancel = 398 sys_stat64 = 338 ) + +fn C.darwin_log(s string) diff --git a/vlib/os/os_darwin.m b/vlib/os/os_darwin.m new file mode 100644 index 0000000000..a1de752d3f --- /dev/null +++ b/vlib/os/os_darwin.m @@ -0,0 +1,7 @@ +/* +NSString* nsstring(string s); + +void darwin_log(string s) { + NSLog(nsstring(s)); +} +*/ diff --git a/vlib/sokol/sapp/sapp.v b/vlib/sokol/sapp/sapp.v index 4f07cb0a18..df7c23fa84 100644 --- a/vlib/sokol/sapp/sapp.v +++ b/vlib/sokol/sapp/sapp.v @@ -3,235 +3,221 @@ module sapp import sokol.gfx pub const ( - used_import = gfx.used_import + used_import = gfx.used_import ) // Android needs a global reference to `g_desc` __global ( g_desc C.sapp_desc ) pub fn create_desc() C.sg_desc { - mtl_desc := C.sg_mtl_context_desc { + mtl_desc := C.sg_mtl_context_desc{ device: metal_get_device() renderpass_descriptor_cb: metal_get_renderpass_descriptor drawable_cb: metal_get_drawable } - d3d11_desc := C.sg_d3d11_context_desc { + d3d11_desc := C.sg_d3d11_context_desc{ device: d3d11_get_device() device_context: d3d11_get_device_context() render_target_view_cb: d3d11_get_render_target_view depth_stencil_view_cb: d3d11_get_depth_stencil_view } - - /* - // Old Sokol - return C.sg_desc{ - mtl_device: sapp.metal_get_device() - mtl_renderpass_descriptor_cb: sapp.metal_get_renderpass_descriptor - mtl_drawable_cb: sapp.metal_get_drawable - d3d11_device: sapp.d3d11_get_device() - d3d11_device_context: sapp.d3d11_get_device_context() - d3d11_render_target_view_cb: sapp.d3d11_get_render_target_view - d3d11_depth_stencil_view_cb: sapp.d3d11_get_depth_stencil_view - } - */ - return C.sg_desc{ context: C.sg_context_desc{ metal: mtl_desc d3d11: d3d11_desc } - image_pool_size:1000 + image_pool_size: 1000 } } -/* returns true after sokol-app has been initialized */ +// returns true after sokol-app has been initialized [inline] pub fn isvalid() bool { return C.sapp_isvalid() } -/* returns the current framebuffer width in pixels */ +// returns the current framebuffer width in pixels [inline] pub fn width() int { return C.sapp_width() } -/* returns the current framebuffer height in pixels */ +// returns the current framebuffer height in pixels [inline] pub fn height() int { return C.sapp_height() } -/* returns true when high_dpi was requested and actually running in a high-dpi scenario */ +// returns true when high_dpi was requested and actually running in a high-dpi scenario [inline] pub fn high_dpi() bool { return C.sapp_high_dpi() } -/* returns the dpi scaling factor (window pixels to framebuffer pixels) */ +// returns the dpi scaling factor (window pixels to framebuffer pixels) [inline] pub fn dpi_scale() f32 { return C.sapp_dpi_scale() } -/* show or hide the mobile device onscreen keyboard */ +// show or hide the mobile device onscreen keyboard [inline] pub fn show_keyboard(visible bool) { C.sapp_show_keyboard(visible) } -/* return true if the mobile device onscreen keyboard is currently shown */ +// return true if the mobile device onscreen keyboard is currently shown [inline] pub fn keyboard_shown() bool { return C.sapp_keyboard_shown() } -/* show or hide the mouse cursor */ +// show or hide the mouse cursor [inline] pub fn show_mouse(visible bool) { C.sapp_show_mouse(visible) } -/* show or hide the mouse cursor */ +// show or hide the mouse cursor [inline] pub fn mouse_shown() bool { return C.sapp_mouse_shown() } -/* return the userdata pointer optionally provided in sapp_desc */ +// return the userdata pointer optionally provided in sapp_desc [inline] pub fn userdata() voidptr { return C.sapp_userdata() } -/* return a copy of the sapp_desc structure */ +// return a copy of the sapp_desc structure [inline] pub fn query_desc() C.sapp_desc { return C.sapp_query_desc() } -/* initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED) */ +// initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED) [inline] pub fn request_quit() { C.sapp_request_quit() } -/* cancel a pending quit (when SAPP_EVENTTYPE_QUIT_REQUESTED has been received) */ +// cancel a pending quit (when SAPP_EVENTTYPE_QUIT_REQUESTED has been received) [inline] pub fn cancel_quit() { C.sapp_cancel_quit() } -/* intiate a "hard quit" (quit application without sending SAPP_EVENTTYPE_QUIT_REQUSTED) */ +// intiate a "hard quit" (quit application without sending SAPP_EVENTTYPE_QUIT_REQUSTED) [inline] pub fn quit() { C.sapp_quit() } -/* call from inside event callback to consume the current event (don't forward to platform) */ +// call from inside event callback to consume the current event (don't forward to platform) [inline] pub fn consume_event() { C.sapp_consume_event() } -/* get the current frame counter (for comparison with sapp_event.frame_count) */ +// get the current frame counter (for comparison with sapp_event.frame_count) [inline] pub fn frame_count() u64 { return C.sapp_frame_count() } -/* write string into clipboard */ +// write string into clipboard [inline] pub fn set_clipboard_string(str byteptr) { C.sapp_set_clipboard_string(str) } -/* read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED) */ +// read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED) [inline] pub fn get_clipboard_string() byteptr { return C.sapp_get_clipboard_string() } -/* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */ +// special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) [inline] pub fn run(desc &C.sapp_desc) int { g_desc = desc return C.sapp_run(desc) } -/* GL: return true when GLES2 fallback is active (to detect fallback from GLES3) */ +// GL: return true when GLES2 fallback is active (to detect fallback from GLES3) [inline] pub fn gles2() bool { return C.sapp_gles2() } -/* HTML5: enable or disable the hardwired "Leave Site?" dialog box */ +// HTML5: enable or disable the hardwired "Leave Site?" dialog box [inline] pub fn html5_ask_leave_site(ask bool) { C.sapp_html5_ask_leave_site(ask) } -/* Metal: get ARC-bridged pointer to Metal device object */ +// Metal: get ARC-bridged pointer to Metal device object [inline] pub fn metal_get_device() voidptr { return C.sapp_metal_get_device() } -/* Metal: get ARC-bridged pointer to this frame's renderpass descriptor */ +// Metal: get ARC-bridged pointer to this frame's renderpass descriptor [inline] pub fn metal_get_renderpass_descriptor() voidptr { return C.sapp_metal_get_renderpass_descriptor() } -/* Metal: get ARC-bridged pointer to current drawable */ +// Metal: get ARC-bridged pointer to current drawable [inline] pub fn metal_get_drawable() voidptr { return C.sapp_metal_get_drawable() } -/* macOS: get ARC-bridged pointer to macOS NSWindow */ +// macOS: get ARC-bridged pointer to macOS NSWindow [inline] pub fn macos_get_window() voidptr { return C.sapp_macos_get_window() } -/* iOS: get ARC-bridged pointer to iOS UIWindow */ +// iOS: get ARC-bridged pointer to iOS UIWindow [inline] pub fn ios_get_window() voidptr { return C.sapp_ios_get_window() } -/* D3D11: get pointer to ID3D11Device object */ +// D3D11: get pointer to ID3D11Device object [inline] pub fn d3d11_get_device() voidptr { return C.sapp_d3d11_get_device() } -/* D3D11: get pointer to ID3D11DeviceContext object */ +// D3D11: get pointer to ID3D11DeviceContext object [inline] pub fn d3d11_get_device_context() voidptr { return C.sapp_d3d11_get_device_context() } -/* D3D11: get pointer to ID3D11RenderTargetView object */ +// D3D11: get pointer to ID3D11RenderTargetView object [inline] pub fn d3d11_get_render_target_view() voidptr { return C.sapp_d3d11_get_render_target_view() } -/* D3D11: get pointer to ID3D11DepthStencilView */ +// D3D11: get pointer to ID3D11DepthStencilView [inline] pub fn d3d11_get_depth_stencil_view() voidptr { return C.sapp_d3d11_get_depth_stencil_view() } -/* Win32: get the HWND window handle */ +// Win32: get the HWND window handle [inline] pub fn win32_get_hwnd() voidptr { return C.sapp_win32_get_hwnd() } -/* Android: get native activity handle */ +// Android: get native activity handle [inline] pub fn android_get_native_activity() voidptr { return C.sapp_android_get_native_activity() diff --git a/vlib/sokol/sapp/sapp_structs.v b/vlib/sokol/sapp/sapp_structs.v index 8ccda7cfd3..649fc4caff 100644 --- a/vlib/sokol/sapp/sapp_structs.v +++ b/vlib/sokol/sapp/sapp_structs.v @@ -2,93 +2,93 @@ module sapp pub struct C.sapp_desc { pub: - init_cb fn() // these are the user-provided callbacks without user data - frame_cb fn() - cleanup_cb fn() - event_cb fn(&C.sapp_event) //&sapp_event) - fail_cb fn(byteptr) - - user_data voidptr // these are the user-provided callbacks with user data - init_userdata_cb fn(voidptr) - frame_userdata_cb fn(voidptr) - cleanup_userdata_cb fn(voidptr) - event_userdata_cb fn(&C.sapp_event, voidptr) - fail_userdata_cb fn(byteptr,voidptr) - - width int /* the preferred width of the window / canvas */ - height int /* the preferred height of the window / canvas */ - sample_count int /* MSAA sample count */ - swap_interval int /* the preferred swap interval (ignored on some platforms) */ - high_dpi bool /* whether the rendering canvas is full-resolution on HighDPI displays */ - fullscreen bool /* whether the window should be created in fullscreen mode */ - alpha bool /* whether the framebuffer should have an alpha channel (ignored on some platforms) */ - window_title byteptr /* the window title as UTF-8 encoded string */ - user_cursor bool /* if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR */ - enable_clipboard bool /* enable clipboard access, default is false */ - clipboard_size int /* max size of clipboard content in bytes */ - - html5_canvas_name byteptr /* the name (id) of the HTML5 canvas element, default is "canvas" */ - html5_canvas_resize bool /* if true, the HTML5 canvas size is set to sapp_desc.width/height, otherwise canvas size is tracked */ - html5_preserve_drawing_buffer bool /* HTML5 only: whether to preserve default framebuffer content between frames */ - html5_premultiplied_alpha bool /* HTML5 only: whether the rendered pixels use premultiplied alpha convention */ - html5_ask_leave_site bool /* initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site()) */ - ios_keyboard_resizes_canvas bool /* if true, showing the iOS keyboard shrinks the canvas */ - gl_force_gles2 bool /* if true, setup GLES2/WebGL even if GLES3/WebGL2 is available */ + init_cb fn () // these are the user-provided callbacks without user data + frame_cb fn () + cleanup_cb fn () + event_cb fn (&C.sapp_event) //&sapp_event) + fail_cb fn (byteptr) + user_data voidptr // these are the user-provided callbacks with user data + init_userdata_cb fn (voidptr) + frame_userdata_cb fn (voidptr) + cleanup_userdata_cb fn (voidptr) + event_userdata_cb fn (&C.sapp_event, voidptr) + fail_userdata_cb fn (byteptr, voidptr) + width int // the preferred width of the window / canvas + height int // the preferred height of the window / canvas + sample_count int // MSAA sample count + swap_interval int // the preferred swap interval (ignored on some platforms) + high_dpi bool // whether the rendering canvas is full-resolution on HighDPI displays + fullscreen bool // whether the window should be created in fullscreen mode + alpha bool // whether the framebuffer should have an alpha channel (ignored on some platforms) + window_title byteptr // the window title as UTF-8 encoded string + user_cursor bool // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR + enable_clipboard bool // enable clipboard access, default is false + clipboard_size int // max size of clipboard content in bytes + html5_canvas_name byteptr // the name (id) of the HTML5 canvas element, default is "canvas" + html5_canvas_resize bool // if true, the HTML5 canvas size is set to sapp_desc.width/height, otherwise canvas size is tracked + html5_preserve_drawing_buffer bool // HTML5 only: whether to preserve default framebuffer content between frames + html5_premultiplied_alpha bool // HTML5 only: whether the rendered pixels use premultiplied alpha convention + html5_ask_leave_site bool // initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site()) + ios_keyboard_resizes_canvas bool // if true, showing the iOS keyboard shrinks the canvas + gl_force_gles2 bool // if true, setup GLES2/WebGL even if GLES3/WebGL2 is available + native_render bool } pub struct Event { pub: - frame_count u64 - typ EventType - key_code KeyCode - char_code u32 - key_repeat bool - modifiers u32 - mouse_button MouseButton - mouse_x f32 - mouse_y f32 - mouse_dx f32 - mouse_dy f32 - scroll_x f32 - scroll_y f32 - num_touches int - touches [8]C.sapp_touchpoint - window_width int - window_height int - framebuffer_width int - framebuffer_height int + frame_count u64 + typ EventType + key_code KeyCode + char_code u32 + key_repeat bool + modifiers u32 + mouse_button MouseButton + mouse_x f32 + mouse_y f32 + mouse_dx f32 + mouse_dy f32 + scroll_x f32 + scroll_y f32 + num_touches int + touches [8]C.sapp_touchpoint + window_width int + window_height int + framebuffer_width int + framebuffer_height int } pub struct C.sapp_event { pub: - frame_count u64 - @type EventType - key_code KeyCode - char_code u32 - key_repeat bool - modifiers u32 - mouse_button MouseButton - mouse_x f32 - mouse_y f32 - mouse_dx f32 - mouse_dy f32 - scroll_x f32 - scroll_y f32 - num_touches int - touches [8]C.sapp_touchpoint - window_width int - window_height int - framebuffer_width int - framebuffer_height int + frame_count u64 + @type EventType + key_code KeyCode + char_code u32 + key_repeat bool + modifiers u32 + mouse_button MouseButton + mouse_x f32 + mouse_y f32 + mouse_dx f32 + mouse_dy f32 + scroll_x f32 + scroll_y f32 + num_touches int + touches [8]C.sapp_touchpoint + window_width int + window_height int + framebuffer_width int + framebuffer_height int } + pub fn (e &C.sapp_event) str() string { - return 'evt: frame_count=$e.frame_count, type=${e.@type}' + t := e.@type + return 'evt: frame_count=$e.frame_count, type=$t' } pub struct C.sapp_touchpoint { pub: - identifier u64 - pos_x f32 - pos_y f32 - changed bool + identifier u64 + pos_x f32 + pos_y f32 + changed bool } diff --git a/vlib/v/builder/cc.v b/vlib/v/builder/cc.v index dc789d5b5a..882efd9a79 100644 --- a/vlib/v/builder/cc.v +++ b/vlib/v/builder/cc.v @@ -314,11 +314,9 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) { // Min macos version is mandatory I think? if v.pref.os == .macos { ccoptions.post_args << '-mmacosx-version-min=10.7' - } - if v.pref.os == .ios { + } else if v.pref.os == .ios { ccoptions.post_args << '-miphoneos-version-min=10.0' - } - if v.pref.os == .windows { + } else if v.pref.os == .windows { ccoptions.post_args << '-municode' } cflags := v.get_os_cflags() diff --git a/vlib/v/gen/js/tests/interp.v b/vlib/v/gen/js/tests/interp.v index b5f59bc3f4..6e6f4595ad 100644 --- a/vlib/v/gen/js/tests/interp.v +++ b/vlib/v/gen/js/tests/interp.v @@ -185,4 +185,4 @@ fn main() { interpolation_string_prefix_expr() utf8_string_interpolation() string_interpolation_str_evaluation() -} \ No newline at end of file +} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index d889f401bf..07e00c541d 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1964,8 +1964,8 @@ fn (mut p Parser) const_decl() ast.ConstDecl { } pos := p.tok.position() name := p.check_name() - if util.contains_capital(name) { - p.warn_with_pos('const names cannot contain uppercase letters, use snake_case instead', + if false && util.contains_capital(name) { + p.warn_with_pos('$p.file_name_dir const names cannot contain uppercase letters, use snake_case instead', pos) } full_name := p.prepend_mod(name) diff --git a/vlib/v/tests/array_slice_test.v b/vlib/v/tests/array_slice_test.v index e7cdb57368..ee375cdb41 100644 --- a/vlib/v/tests/array_slice_test.v +++ b/vlib/v/tests/array_slice_test.v @@ -47,4 +47,4 @@ fn pointer_array_slice(mut a []int) { fn test_pointer_array_slice() { mut arr := [1,2,3] pointer_array_slice(mut arr) -} \ No newline at end of file +} diff --git a/vlib/v/tests/comptime_if_expr_test.v b/vlib/v/tests/comptime_if_expr_test.v index d77eac9e71..3f739ef1a9 100644 --- a/vlib/v/tests/comptime_if_expr_test.v +++ b/vlib/v/tests/comptime_if_expr_test.v @@ -100,4 +100,4 @@ fn generic_t_is_with_else(raw_data string) ?T { } $else { return T{} } -} \ No newline at end of file +} diff --git a/vlib/v/tests/defer_test.v b/vlib/v/tests/defer_test.v index 1289d228a6..a6e69af3fc 100644 --- a/vlib/v/tests/defer_test.v +++ b/vlib/v/tests/defer_test.v @@ -82,4 +82,4 @@ fn test_defer_with_anon_fn() { } x() return -} \ No newline at end of file +} diff --git a/vlib/v/tests/filter_in_map_test.v b/vlib/v/tests/filter_in_map_test.v index 7eb02baa17..640b438c80 100644 --- a/vlib/v/tests/filter_in_map_test.v +++ b/vlib/v/tests/filter_in_map_test.v @@ -2,4 +2,4 @@ fn filter_in_map_test() { x := [['']] y := x.map(it.filter(it != '')) assert y[0].len == 0 -} \ No newline at end of file +} diff --git a/vlib/v/tests/imported_symbols_test.v b/vlib/v/tests/imported_symbols_test.v index db57888da4..4224eb9ae5 100644 --- a/vlib/v/tests/imported_symbols_test.v +++ b/vlib/v/tests/imported_symbols_test.v @@ -23,4 +23,4 @@ fn test_imported_symbols_functions() { fn test_imported_symbols_constants() { assert module_name == 'geometry' -} \ No newline at end of file +} diff --git a/vlib/v/tests/match_sumtype_var_shadow_and_as_test.v b/vlib/v/tests/match_sumtype_var_shadow_and_as_test.v index 61b1822c10..7a49c979fd 100644 --- a/vlib/v/tests/match_sumtype_var_shadow_and_as_test.v +++ b/vlib/v/tests/match_sumtype_var_shadow_and_as_test.v @@ -32,4 +32,4 @@ fn test_as() { assert false } } -} \ No newline at end of file +} diff --git a/vlib/v/tests/modules/methods_struct_another_module/methods_struct_test.v b/vlib/v/tests/modules/methods_struct_another_module/methods_struct_test.v index ad80ded468..dd2fc8b7d7 100644 --- a/vlib/v/tests/modules/methods_struct_another_module/methods_struct_test.v +++ b/vlib/v/tests/modules/methods_struct_another_module/methods_struct_test.v @@ -13,4 +13,4 @@ fn test_operator_overloading() { fn test_str_method() { one := Point {x:1, y:2} assert '$one' == '1 2' -} \ No newline at end of file +} diff --git a/vlib/v/tests/valgrind/1.strings_and_arrays.v b/vlib/v/tests/valgrind/1.strings_and_arrays.v index 24522ed8a5..115fb2d9a8 100644 --- a/vlib/v/tests/valgrind/1.strings_and_arrays.v +++ b/vlib/v/tests/valgrind/1.strings_and_arrays.v @@ -98,6 +98,11 @@ fn str_replace2() { } fn reassign_str() { + mut z := '1' + '2' + if true { + println('KEK') + z = 'foo' + } mut x := 'a' x = 'b' // nothing has to be freed here // diff --git a/vlib/x/ttf/common.v b/vlib/x/ttf/common.v index 2f1dabb10d..56e0d91b1e 100644 --- a/vlib/x/ttf/common.v +++ b/vlib/x/ttf/common.v @@ -225,4 +225,4 @@ fn color_multiply(c u32, level f32) u32 { a = if a > 1.0 { 1.0 } else { a } return (u32(r * 255) << 24) | (u32(g * 255) << 16) | (u32(b * 255) << 8) | u32(a * 255) -} \ No newline at end of file +} diff --git a/vlib/x/ttf/text_block.v b/vlib/x/ttf/text_block.v index b547720326..909afb8395 100644 --- a/vlib/x/ttf/text_block.v +++ b/vlib/x/ttf/text_block.v @@ -118,4 +118,4 @@ fn (mut bmp BitMap) draw_text_block(text string, block Text_block) { } bmp.space_cw = old_space_cw -} \ No newline at end of file +} diff --git a/vlib/x/ttf/ttf.v b/vlib/x/ttf/ttf.v index 388ff0d5af..f63b0b750a 100644 --- a/vlib/x/ttf/ttf.v +++ b/vlib/x/ttf/ttf.v @@ -1096,4 +1096,4 @@ fn tst(){ //dprintln( tf.get_u32().hex() ) //dprintln( tf.get_2dot14() ) //dprintln( tf.get_fixed() ) -} \ No newline at end of file +}