diff --git a/compiler/cheaders.v b/compiler/cheaders.v index b79775bb55..42935dc7c1 100644 --- a/compiler/cheaders.v +++ b/compiler/cheaders.v @@ -13,7 +13,7 @@ CommonCHeaders = ' #define STRUCT_DEFAULT_VALUE {} #define EMPTY_STRUCT_DECLARATION -#define EMPTY_STRUCT_INIT +#define EMPTY_STRUCT_INIT 0 #define OPTION_CAST(x) (x) #ifdef _WIN32 @@ -105,4 +105,4 @@ void init_consts(); ' -) \ No newline at end of file +) diff --git a/compiler/fn.v b/compiler/fn.v index aeccf26728..046172c2fc 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -140,7 +140,7 @@ fn (p mut Parser) fn_decl() { } receiver_typ = p.get_type() T := p.table.find_type(receiver_typ) - if T.is_interface { + if T.cat == .interface_ { p.error('invalid receiver type `$receiver_typ` (`$receiver_typ` is an interface)') } // Don't allow modifying types from a different module diff --git a/compiler/parser.v b/compiler/parser.v index f02063094b..3838accf1b 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -74,6 +74,8 @@ mut: returns bool vroot string is_c_struct_init bool + is_empty_c_struct_init bool + is_c_fn_call bool can_chash bool attr string v_script bool // "V bash", import all os functions into global space @@ -177,7 +179,7 @@ fn (p mut Parser) parse() { } p.fgenln('\n') p.builtin_mod = p.mod == 'builtin' - p.can_chash = p.mod == 'freetype' || p.mod=='ui' // TODO tmp remove + p.can_chash = p.mod=='ui' || p.mod == 'darwin'// TODO tmp remove // Import pass - the first and the smallest pass that only analyzes imports // fully qualify the module name, eg base64 to encoding.base64 fq_mod := p.table.qualify_module(p.mod, p.file_path) @@ -199,7 +201,7 @@ fn (p mut Parser) parse() { // Go through every top level token or throw a compilation error if a non-top level token is met for { switch p.tok { - case Token.key_import: + case .key_import: if p.peek() == .key_const { p.const_decl() } @@ -483,26 +485,27 @@ fn (p mut Parser) interface_method(field_name, receiver string) &Fn { return method } +fn key_to_type_cat(tok Token) TypeCategory { + switch tok { + case Token.key_interface: return TypeCategory.interface_ + case Token.key_struct: return TypeCategory.struct_ + case Token.key_union: return TypeCategory.union_ + //Token.key_ => return .interface_ + } + panic('') +} + // also unions and interfaces fn (p mut Parser) struct_decl() { - // Attribute before type? - mut objc_parent := '' - mut is_objc := false// V can generate Objective C for integration with Cocoa - // [attr] - if p.tok == .lsbr { - p.check(.lsbr) - // `[interface:ParentInterface]` - is_objc = p.tok == .key_interface - p.next() - if is_objc { - p.check(.colon) - objc_parent = p.check_name() - } - p.check(.rsbr) - } + // V can generate Objective C for integration with Cocoa + // `[interface:ParentInterface]` + is_objc := p.attr.starts_with('interface') + objc_parent := if is_objc { p.attr.right(10) } else { '' } + // interface, union, struct is_interface := p.tok == .key_interface is_union := p.tok == .key_union is_struct := p.tok == .key_struct + mut cat := key_to_type_cat(p.tok) p.fgen(p.tok.str() + ' ') // Get type name p.next() @@ -517,6 +520,10 @@ fn (p mut Parser) struct_decl() { if is_c { p.check(.dot) name = p.check_name() + cat = .c_struct + if p.attr == 'typedef' { + cat = .c_typedef + } } if !is_c && !good_type_name(name) { p.error('bad struct name, e.g. use `HttpRequest` instead of `HTTPRequest`') @@ -549,13 +556,14 @@ fn (p mut Parser) struct_decl() { typ.mod = p.mod typ.is_c = is_c typ.is_placeholder = false + typ.cat = cat } else { typ = &Type { name: name mod: p.mod is_c: is_c - is_interface: is_interface + cat: cat } } // Struct `C.Foo` declaration, no body @@ -706,7 +714,7 @@ fn (p mut Parser) enum_decl(_enum_name string) { name: enum_name mod: p.mod parent: 'int' - is_enum: true + cat: TypeCategory.enum_ enum_vals: fields }) p.check(.rcbr) @@ -905,7 +913,8 @@ fn (p mut Parser) get_type() string { } typ += p.lit if !p.is_struct_init { - // Otherwise we get `foo := FooFoo{` because `Foo` was already generated in name_expr() + // Otherwise we get `foo := FooFoo{` because `Foo` was already + // generated in name_expr() p.fgen(p.lit) } // C.Struct import @@ -1120,7 +1129,6 @@ fn (p mut Parser) statement(add_semi bool) string { } // `a := 777` else if p.peek() == .decl_assign { - p.log('var decl') p.var_decl() } else { @@ -1128,7 +1136,7 @@ fn (p mut Parser) statement(add_semi bool) string { if p.lit == 'panic' || p.lit == 'exit' { p.returns = true } - // `a + 3`, `a(7)` or maybe just `a` + // `a + 3`, `a(7)`, or just `a` q = p.bool_expression() } case Token.key_goto: @@ -1220,7 +1228,7 @@ fn ($v.name mut $v.typ) $p.cur_fn.name (...) { is_str := v.typ == 'string' switch tok { case Token.assign: - if !is_map { + if !is_map && !p.is_empty_c_struct_init { p.gen(' = ') } case Token.plus_assign: @@ -1326,13 +1334,18 @@ fn (p mut Parser) var_decl() { }) if !or_else { gen_name := p.table.var_cgen_name(name) - mut nt_gen := p.table.cgen_name_type_pair(gen_name, typ) + '=' + mut nt_gen := p.table.cgen_name_type_pair(gen_name, typ) + // `foo := C.Foo{}` => `Foo foo;` + if !p.is_empty_c_struct_init { + nt_gen += '=' + } if is_static { nt_gen = 'static $nt_gen' } p.cgen.set_placeholder(pos, nt_gen) } p.var_decl_name = '' + p.is_empty_c_struct_init = false } const ( @@ -1383,7 +1396,7 @@ fn (p mut Parser) bterm() string { is_str := typ=='string' && !p.is_sql tok := p.tok // if tok in [ .eq, .gt, .lt, .le, .ge, .ne] { - if tok == .eq || (tok == .assign && p.is_sql) || tok == .gt || tok == .lt || tok == .le || tok == .ge || tok == .ne { + if tok == .eq || tok == .gt || tok == .lt || tok == .le || tok == .ge || tok == .ne { p.fgen(' ${p.tok.str()} ') if is_str { p.gen(',') @@ -1466,7 +1479,7 @@ fn (p mut Parser) name_expr() string { if p.tok == .dot { //println('got enum dot val $p.left_type pass=$p.pass $p.scanner.line_nr left=$p.left_type') T := p.find_type(p.expected_type) - if T.is_enum { + if T.cat == .enum_ { p.check(.dot) val := p.check_name() // Make sure this enum value exists @@ -1552,7 +1565,7 @@ fn (p mut Parser) name_expr() string { // Color.green else if p.peek() == .dot { enum_type := p.table.find_type(name) - if !enum_type.is_enum { + if enum_type.cat != .enum_ { p.error('`$name` is not an enum') } p.next() @@ -1563,19 +1576,8 @@ fn (p mut Parser) name_expr() string { p.next() return enum_type.name } + // struct initialization else if p.peek() == .lcbr { - // go back to name start (mod.name) -/* - p.scanner.pos = hack_pos - p.tok = hack_tok - p.lit = hack_lit -*/ - // TODO hack. If it's a C type, we may need to add struct before declaration: - // a := &C.A{} ==> struct A* a = malloc(sizeof(struct A)); - if is_c_struct_init { - p.is_c_struct_init = true - p.cgen.insert_before('struct /*c struct init*/') - } if ptr { name += '*' // `&User{}` => type `User*` } @@ -1597,12 +1599,15 @@ fn (p mut Parser) name_expr() string { name: name// .replace('c_', '') is_c: true } + p.is_c_fn_call = true p.fn_call(f, 0, '', '') + p.is_c_fn_call = false // Try looking it up. Maybe its defined with "C.fn_name() fn_type", // then we know what type it returns cfn := p.table.find_fn(name) // Not Found? Return 'void*' if cfn.name == '' { + //return 'cvoid' //'void*' return 'void*' } return cfn.typ @@ -1791,7 +1796,7 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string { p.gen_array_str(mut typ) has_method = true } - if !typ.is_c && !has_field && !has_method && !p.first_pass() { + if !typ.is_c && !p.is_c_fn_call && !has_field && !has_method && !p.first_pass() { if typ.name.starts_with('Option_') { opt_type := typ.name.right(7) p.error('unhandled option type: $opt_type?') @@ -1809,7 +1814,7 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string { p.error('type `$typ.name` has no field or method `$field_name`') } mut dot := '.' - if str_typ.contains('*') { + if str_typ.ends_with('*') || str_typ == 'FT_Face' { // TODO fix C ptr typedefs dot = '->' } // field @@ -2113,7 +2118,7 @@ fn (p mut Parser) expression() string { p.check_space(.left_shift) // Get the value we are pushing p.gen(', (') - // Imkey_mut? Can we push? + // Immutable? Can we push? if !p.expr_var.is_mut && !p.pref.translated { p.error('`$p.expr_var.name` is immutable (can\'t <<)') } @@ -2130,7 +2135,7 @@ fn (p mut Parser) expression() string { p.check_types(expr_type, tmp_typ) // Pass tmp var info to the _PUSH macro // Prepend tmp initialisation and push call - // Don't dereference if it's already a key_mut array argument (`fn foo(mut []int)`) + // Don't dereference if it's already a mutable array argument (`fn foo(mut []int)`) push_call := if typ.contains('*'){'_PUSH('} else { '_PUSH(&'} p.cgen.set_placeholder(ph, push_call) p.gen('), $tmp, $tmp_typ)') @@ -2791,18 +2796,32 @@ fn (p mut Parser) array_init() string { fn (p mut Parser) struct_init(typ string, is_c_struct_init bool) string { p.is_struct_init = true + t := p.table.find_type(typ) + // TODO hack. If it's a C type, we may need to add struct before declaration: + // a := &C.A{} ==> struct A* a = malloc(sizeof(struct A)); + if is_c_struct_init { // && t.cat != .c_typedef { + p.is_c_struct_init = true + if t.cat != .c_typedef { + p.cgen.insert_before('struct /*c struct init*/') + } + } p.next() p.scanner.fmt_out.cut(typ.len) ptr := typ.contains('*') // TODO tm struct struct bug if typ == 'tm' { p.cgen.lines[p.cgen.lines.len-1] = '' - p.cgen.lines[p.cgen.lines.len-2] = '' } p.check(.lcbr) - // tmp := p.get_tmp() + // `user := User{foo:bar}` => `User user = (User){ .foo = bar}` if !ptr { if p.is_c_struct_init { + // `face := C.FT_Face{}` => `FT_Face face;` + if p.tok == .rcbr { + p.is_empty_c_struct_init = true + p.check(.rcbr) + return typ + } p.gen('(struct $typ) {') p.is_c_struct_init = false } @@ -2829,7 +2848,6 @@ fn (p mut Parser) struct_init(typ string, is_c_struct_init bool) string { mut inited_fields := []string peek := p.peek() if peek == .colon || p.tok == .rcbr { - t := p.table.find_type(typ) for p.tok != .rcbr { field := p.check_name() if !t.has_field(field) { @@ -2942,6 +2960,9 @@ fn (p mut Parser) cast(typ string) string { p.check(.lpar) p.expected_type = typ expr_typ := p.bool_expression() + // `face := FT_Face(cobj)` => `FT_Face face = *((FT_Face*)cobj);` + casting_voidptr_to_value := expr_typ == 'void*' && typ != 'int' && + typ != 'byteptr' && !typ.ends_with('*') p.expected_type = '' // `string(buffer)` => `tos2(buffer)` // `string(buffer, len)` => `tos(buffer, len)` @@ -2976,6 +2997,9 @@ fn (p mut Parser) cast(typ string) string { else if typ == 'byte' && expr_typ == 'string' { p.error('cannot cast `$expr_typ` to `$typ`, use backquotes `` to create a `$typ` or access the value of an index of `$expr_typ` using []') } + else if casting_voidptr_to_value { + p.cgen.set_placeholder(pos, '*($typ*)(') + } else { p.cgen.set_placeholder(pos, '($typ)(') } @@ -3524,7 +3548,13 @@ fn (p &Parser) building_v() bool { fn (p mut Parser) attribute() { p.check(.lsbr) - p.attr = p.check_name() + if p.tok == .key_interface { + p.check(.key_interface) + p.check(.colon) + p.attr = 'interface:' + p.check_name() + } else { + p.attr = p.check_name() + } p.check(.rsbr) if p.tok == .func { p.fn_decl() diff --git a/compiler/table.v b/compiler/table.v index cafbc61186..93e8a90680 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -43,17 +43,26 @@ enum AccessMod { public_mut_mut // public and mutable both inside and outside (not recommended to use, that's why it's so verbose) } +enum TypeCategory { + struct_ + func + interface_ // 2 + enum_ + union_ + c_struct // 5 + c_typedef +} + struct Type { mut: mod string name string + cat TypeCategory fields []Var methods []Fn parent string func Fn // For cat == FN (type myfn fn()) - is_c bool // C.FI.le - is_interface bool - is_enum bool + is_c bool // `C.FILE` enum_vals []string gen_types []string // This field is used for types that are not defined yet but are known to exist. @@ -488,7 +497,7 @@ fn (p mut Parser) _check_types(got_, expected_ string, throw bool) bool { return true } // Todo void* allows everything right now - if got=='void*' || expected=='void*' { + if got=='void*' || expected=='void*' {// || got == 'cvoid' || expected == 'cvoid' { // if !p.builtin_mod { if p.pref.is_play { return false @@ -623,7 +632,7 @@ fn type_default(typ string) string { // TODO PERF O(n) fn (t &Table) is_interface(name string) bool { for typ in t.types { - if typ.is_interface && typ.name == name { + if typ.cat == .interface_ && typ.name == name { return true } } @@ -757,7 +766,7 @@ fn (t mut Table) register_generic_fn_type(fn_name, typ string) { fn (p mut Parser) typ_to_fmt(typ string, level int) string { t := p.table.find_type(typ) - if t.is_enum { + if t.cat == .enum_ { return '%d' } switch typ { diff --git a/vlib/builtin/int.v b/vlib/builtin/int.v index 4f28cffdd9..831ba96784 100644 --- a/vlib/builtin/int.v +++ b/vlib/builtin/int.v @@ -195,7 +195,7 @@ pub fn (n int) hex() string { } else { 11 } - hex := malloc(len) // 0x + \n + hex := malloc(len) // 0x + \n count := int(C.sprintf(hex, '0x%x', n)) return tos(hex, count) } @@ -245,14 +245,14 @@ pub fn (c byte) str() string { } pub fn (c byte) is_capital() bool { - return c >= `A` && c <= `Z` -} + return c >= `A` && c <= `Z` +} pub fn (b []byte) clone() []byte { - mut res := [byte(0); b.len] + mut res := [byte(0); b.len] for i := 0; i < b.len; i++ { - res[i] = b[i] - } - return res -} + res[i] = b[i] + } + return res +} diff --git a/vlib/darwin/darwin.v b/vlib/darwin/darwin.v new file mode 100644 index 0000000000..f820ce57d3 --- /dev/null +++ b/vlib/darwin/darwin.v @@ -0,0 +1,22 @@ +module darwin + +#include +#flag -framework Cocoa + +struct C.NSString { } + +// macOS and iOS helpers +fn nsstring(s string) *NSString { + // #return @"" ; + // println('ns $s len=$s.len') + # return [ [ NSString alloc ] initWithBytesNoCopy:s.str length:s.len + # encoding:NSUTF8StringEncoding freeWhenDone: false]; + return 0 + + //ns := C.alloc_NSString() + //return ns.initWithBytesNoCopy(s.str, length: s.len, + //encoding: NSUTF8StringEncoding, freeWhenDone: false) + + +} + diff --git a/vlib/freetype/freetype.v b/vlib/freetype/freetype.v index 2913f6efaa..9d108e9b79 100644 --- a/vlib/freetype/freetype.v +++ b/vlib/freetype/freetype.v @@ -2,25 +2,25 @@ // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. -module freetype +module freetype import ( - os - gx - gg + os + gx + gg stbi glm gl -) +) #flag darwin -I/usr/local/include/freetype2 #flag darwin -I/opt/local/include/freetype2 -#flag -lfreetype +#flag -lfreetype -//#flag -I @VROOT/thirdparty/freetype +//#flag -I @VROOT/thirdparty/freetype -//#flag @VROOT/thirdparty/freetype/libfreetype.a -#flag darwin -lpng -lbz2 -lz +//#flag @VROOT/thirdparty/freetype/libfreetype.a +#flag darwin -lpng -lbz2 -lz #flag linux -I/usr/include/freetype2 @@ -30,6 +30,8 @@ import ( #include "ft2build.h" #include FT_FREETYPE_H + + const ( DEFAULT_FONT_SIZE = 12 ) @@ -45,6 +47,11 @@ struct Face { cobj voidptr } +[typedef] +struct C.FT_Library { + +} + struct Context { shader gl.Shader // use_ortho bool @@ -63,67 +70,67 @@ struct Context { scale int // retina = 2 , normal = 1 } -/* -struct Cfg { - width int - height int - use_ortho bool - retina bool - scale int - font_size int - create_window bool - window_user_ptr voidptr - window_title string - always_on_top bool +struct C.Bitmap { + width int + rows int + buffer int } -*/ +struct C.Advance { + x int +} + +struct C.Glyph { + bitmap Bitmap + bitmap_left int + bitmap_top int + advance Advance +} + +[typedef] +struct C.FT_Face { + glyph *Glyph +} -// jfn ft_load_char(face FT_Face, code FT_ULong) Character { -// fn ft_load_char(_face voidptr, _code voidptr) Character { fn ft_load_char(_face Face, code i64) Character { - // #FT_Face face = *(FT_Face*)(_face); FT_ULong code = *(FT_ULong*)(code); - # FT_Face face = *((FT_Face*)_face.cobj); - # int condition = FT_Load_Char(face, code, FT_LOAD_RENDER); - if (C.condition != 0) - { - println('freetype: Failed to load Glyph') - exit(1) + //println('ftload_char( code=$code)') + //C.printf('face=%p\n', _face) + face := FT_Face(_face.cobj) + ret := int(C.FT_Load_Char(face, code, C.FT_LOAD_RENDER)) + if ret != 0 { + println('freetype: failed to load glyph (utf32 code=$code, ' + + 'error code=$ret)') + return Character{} } // Generate texture - # GLuint texture; - # glGenTextures(1, &texture); - # glBindTexture(GL_TEXTURE_2D, texture); - # glTexImage2D( - # GL_TEXTURE_2D, - # 0, - # GL_RED, - # face->glyph->bitmap.width, - # face->glyph->bitmap.rows, - # 0, - # GL_RED, - # GL_UNSIGNED_BYTE, - # face->glyph->bitmap.buffer - # ); + mut texture := 0 + C.glGenTextures(1, &texture) + C.glBindTexture(C.GL_TEXTURE_2D, texture) + fgwidth := face.glyph.bitmap.width + fgrows := face.glyph.bitmap.rows + C.glTexImage2D(C.GL_TEXTURE_2D, 0, C.GL_RED, fgwidth, fgrows, + 0, C.GL_RED, C.GL_UNSIGNED_BYTE, face.glyph.bitmap.buffer) // Set texture options - # glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - # glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - # glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - # glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Now store character for later use - ch := Character{} - # ch.texture_id=texture ; - # ch.size = gg__vec2(face->glyph->bitmap.width, face->glyph->bitmap.rows); - # ch.bearing = gg__vec2(face->glyph->bitmap_left, face->glyph->bitmap_top), - # ch.advance = face->glyph->advance.x; - return ch + C.glTexParameteri(GL_TEXTURE_2D, C.GL_TEXTURE_WRAP_S, C.GL_CLAMP_TO_EDGE) + C.glTexParameteri(GL_TEXTURE_2D, C.GL_TEXTURE_WRAP_T, C.GL_CLAMP_TO_EDGE) + C.glTexParameteri(GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR) + C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_LINEAR) + fgleft := face.glyph.bitmap_left + fgtop := face.glyph.bitmap_top + // Create the character + return Character { + texture_id: u32(texture) + size: gg.vec2(int(u32(fgwidth)), int(u32(fgrows))) + bearing: gg.vec2(int(u32(fgleft)), int(u32(fgtop))) + advance: (u32(face.glyph.advance.x)) + } } pub fn new_context(cfg gg.Cfg) *Context { - scale := cfg.scale + scale := cfg.scale // Can only have text in ortho mode if !cfg.use_ortho { - return &Context{} + return &Context{} } mut width := cfg.width * scale mut height := cfg.height * scale @@ -135,27 +142,25 @@ pub fn new_context(cfg gg.Cfg) *Context { // height = height * 2// scale// 2 // font_size *= scale// 2 // } - /* + /* gl.viewport(0, 0, width, height) */ - // gl.enable(GL_CULL_FACE) // TODO NEED CULL? + // gl.enable(GL_CULL_FACE) // TODO NEED CULL? gl.enable(GL_BLEND) -//return &GG{} - // return &GG{} - # glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + C.glBlendFunc(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA) shader := gl.new_shader('text') shader.use() projection := glm.ortho(0, width, 0, height)// 0 at BOT - // projection_new := ortho(0, width, 0, height)// 0 at BOT - // projection := gl.ortho(0, width,height,0) // 0 at TOP shader.set_mat4('projection', projection) // FREETYPE - # FT_Library ft; - // All functions return a value different than 0 whenever an error occurred - # if (FT_Init_FreeType(&ft)) - println('ERROR::FREETYPE: Could not init FreeType Library') + ft := FT_Library{} + // All functions return a value different than 0 whenever + // an error occurred + mut ret := C.FT_Init_FreeType(&ft) + if ret != 0 { + panic('freetype: Could not init FreeType Library') + } // Load font as face - // face := FT_Face{} mut font_path := cfg.font_path if font_path == '' { font_path = 'RobotoMono-Regular.ttf' @@ -170,37 +175,27 @@ pub fn new_context(cfg gg.Cfg) *Context { return 0 } println('Trying to load font from $font_path') - # FT_Face face; - # int condition = FT_New_Face(ft, font_path.str, 0, &face); - if (C.condition != 0) - // # if (FT_New_Face(ft, "/Library/Fonts/Courier New.ttf", 0, &face)) - // # if (FT_New_Face(ft, "/System/Library/Fonts/Apple Color Emoji.ttc", 0, &face)) - { - println('freetyp: Failed to load font') + face := C.FT_Face{} + ret = int(C.FT_New_Face(ft, font_path.str, 0, &face)) + if ret != 0 { + println('freetype: failed to load the font (error=$ret)') exit(1) } // Set size to load glyphs as - # FT_Set_Pixel_Sizes(face, 0, font_size) ; + C.FT_Set_Pixel_Sizes(face, 0, font_size) // Disable byte-alignment restriction - # glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + C.glPixelStorei(C.GL_UNPACK_ALIGNMENT, 1) // Gen texture // Load first 128 characters of ASCII set mut chars := []Character{} f := Face { - cobj: 0 + cobj: &face } - # f.cobj = &face; - // # for (GLubyte c = 0; c < 128; c++) for c := 0; c < 128; c++ { - // ch := Character{} - // ch:=ft_load_char(face, c) - // # ch =gg__ft_load_char(&face, &c); - // //////////////////////////////// mut ch := ft_load_char(f, i64(c)) // s := utf32_to_str(uint(0x043f)) // s := 'п' // ch = ft_load_char(f, s.utf32_code()) - // # ch = gg__ft_load_char(f, 0x043f); // RUS P // # unsigned long c = FT_Get_Char_Index(face, 0x043f ); // # printf("!!!!!!!!! %lu\n", c); // # c = FT_Get_Char_Index(face, 0xd0bf ); @@ -209,9 +204,6 @@ pub fn new_context(cfg gg.Cfg) *Context { chars << ch } ch := Character{} - // # ch = gg__ft_load_char(f, 0x0000043f); - // # ch = gg__ft_load_char(f, 128169); - // chars.push(ch) // Configure VAO vao := gl.gen_vertex_array() println('new gg text context vao=$vao') @@ -225,13 +217,13 @@ pub fn new_context(cfg gg.Cfg) *Context { // gl.bind_buffer(GL_ARRAY_BUFFER, uint(0)) // # glBindVertexArray(0); mut ctx := &Context { - shader: shader, - width: width, - height: height, + shader: shader + width: width + height: height scale: scale - vao: vao, - vbo: vbo, - chars: chars, + vao: vao + vbo: vbo + chars: chars face: f } ctx.init_utf8_runes() @@ -239,10 +231,11 @@ pub fn new_context(cfg gg.Cfg) *Context { } // A dirty hack to implement rendering of cyrillic letters. -// All UTF-8 must be supported. +// All UTF-8 must be supported. fn (ctx mut Context) init_utf8_runes() { s := '≈≠⩽⩾йцукенгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ' - println(s) + print('init utf8 runes: ') + //println(s) us := s.ustring() for i := 0; i < us.len; i++ { _rune := us.at(i) @@ -253,25 +246,18 @@ fn (ctx mut Context) init_utf8_runes() { } } -// fn (ctx &GG) render_text(text string, x, y, scale f32, color gx.Color) { -pub fn (ctx &Context) draw_text(_x, _y int, text string, cfg gx.TextCfg) { +pub fn (ctx mut Context) draw_text(_x, _y int, text string, cfg gx.TextCfg) { //utext := text.ustring_tmp() utext := text.ustring() ctx._draw_text(_x, _y, utext, cfg) - // utext.free() - // # glScissor(0,0,ctx->width*2,ctx->height*2); - // gl.disable(GL_SCISSOR_TEST)// TODO - // #free(text.str); } -fn (ctx &Context) draw_text_fast(_x, _y int, text ustring, cfg gx.TextCfg) { +fn (ctx mut Context) draw_text_fast(_x, _y int, text ustring, cfg gx.TextCfg) { ctx._draw_text(_x, _y, text, cfg) } -// TODO HACK with second text context -// fn (ctx &GG) _draw_text(_x, _y int, text string, cfg gx.TextCfg) { -fn (ctx &Context) _draw_text(_x, _y int, utext ustring, cfg gx.TextCfg) { - /* +fn (ctx mut Context) _draw_text(_x, _y int, utext ustring, cfg gx.TextCfg) { + /* if utext.s.contains('on_seg') { println('\nat(0)') println(utext.runes) @@ -282,8 +268,8 @@ fn (ctx &Context) _draw_text(_x, _y int, utext ustring, cfg gx.TextCfg) { } } */ - mut x := f32(_x) - mut y := f32(_y) + mut x := f32(_x) + mut y := f32(_y) // println('scale=$ctx.scale size=$cfg.size') if cfg.align == gx.ALIGN_RIGHT { width := utext.len * 7 @@ -293,12 +279,12 @@ fn (ctx &Context) _draw_text(_x, _y int, utext ustring, cfg gx.TextCfg) { // println('y=$_y height=$ctx.height') // _y = _y * int(ctx.scale) //+ 26 y = y * int(ctx.scale) + ((cfg.size * ctx.scale) / 2) + 5 * ctx.scale - y = f32(ctx.height) - y + y = f32(ctx.height) - y color := cfg.color // Activate corresponding render state ctx.shader.use() ctx.shader.set_color('textColor', color) - # glActiveTexture(GL_TEXTURE0); + C.glActiveTexture(C.GL_TEXTURE0) gl.bind_vao(ctx.vao) // Iterate through all characters // utext := text.ustring() @@ -318,65 +304,52 @@ fn (ctx &Context) _draw_text(_x, _y int, utext ustring, cfg gx.TextCfg) { // TODO O(1) use map for j := 0; j < ctx.utf_runes.len; j++ { rune_j := ctx.utf_runes[j] - // if string_eq(ctx.utf_runes[j], rune) { if rune_j==_rune { ch = ctx.utf_chars[j] break } } } - if ch.size.x == 0 { + if ch.size.x == 0 && _rune.len > 1{ + c := _rune[0] + println('cant draw rune "$_rune" code=$c, loading') + continue + ch = ft_load_char(ctx.face, _rune.utf32_code()) + println('done loading') + ctx.utf_runes << _rune + ctx.utf_chars << ch // continue } - // mut c := int(text[i]) - // c = 128 - // s := 'A' - // c := int(s[0]) - // ch := ctx.chars[c] xpos := x + f32(ch.bearing.x) * 1 ypos := y - f32(ch.size.y - ch.bearing.y) * 1 w := f32(ch.size.x) * 1 h := f32(ch.size.y) * 1 // Update VBO for each character - # GLfloat vertices[6][4] = { - # { xpos, ypos + h, 0.0, 0.0 }, - # { xpos, ypos, 0.0, 1.0 }, - # { xpos + w, ypos, 1.0, 1.0 }, - # { xpos, ypos + h, 0.0, 0.0 }, - # { xpos + w, ypos, 1.0, 1.0 }, - # { xpos + w, ypos + h, 1.0, 0.0 } - # }; - // t := glfw.get_time() + vertices := [ + xpos, ypos + h, 0.0, 0.0 , + xpos, ypos, 0.0, 1.0 , + xpos + w, ypos, 1.0, 1.0 , + xpos, ypos + h, 0.0, 0.0 , + xpos + w, ypos, 1.0, 1.0 , + xpos + w, ypos + h, 1.0, 0.0 + ] // Render glyph texture over quad - // t1 := glfw.get_time() - # glBindTexture(GL_TEXTURE_2D, ch.texture_id); + C.glBindTexture(C.GL_TEXTURE_2D, ch.texture_id) // Update content of VBO memory gl.bind_buffer(GL_ARRAY_BUFFER, ctx.vbo) - // t2 := glfw.get_time() - // # glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData - # glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); - // t3 := glfw.get_time() - // gl.bind_buffer(GL_ARRAY_BUFFER, uint(0)) - // t4 := glfw.get_time() + // glBufferSubData(..) + C.glBufferData(GL_ARRAY_BUFFER, 96, vertices.data, C.GL_DYNAMIC_DRAW) // Render quad gl.draw_arrays(GL_TRIANGLES, 0, 6) - // t5 := glfw.get_time() - // # if (glfw__get_time() - t > 0.001) - // { - // # printf("do_text = %f '%s' \n", glfw__get_time() - t, text.str); - // # printf("t1=%f, t2=%f, t3=%f, t4=%f, t5=%f\n\n\n", t1-t, t2-t1, t3-t2, t4-t3, t5-t4); - // } // Now advance cursors for next glyph (note that advance is number of 1/64 pixels) // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels)) - # x += (ch.advance >> 6) * 1; + x += ch.advance >> u32(6) } gl.bind_vao(u32(0)) - # glBindTexture(GL_TEXTURE_2D, 0); - // runes.free() - // #free(runes.data); + C.glBindTexture(C.GL_TEXTURE_2D, 0) } -pub fn (ctx &Context) draw_text_def(x, y int, text string) { +pub fn (ctx mut Context) draw_text_def(x, y int, text string) { cfg := gx.TextCfg { color: gx.Black, size: DEFAULT_FONT_SIZE, diff --git a/vlib/ui/examples/users_gui/users.v b/vlib/ui/examples/users_gui/users.v index e9faeebf04..a50b22da49 100644 --- a/vlib/ui/examples/users_gui/users.v +++ b/vlib/ui/examples/users_gui/users.v @@ -19,7 +19,7 @@ struct Context { last_name ui.TextBox age ui.TextBox users []User - window *ui.Window + window &ui.Window txt_pos int }