From eb5fcafa77b65e5b0aa80bafce8b0b72d060ec2e Mon Sep 17 00:00:00 2001
From: Alexander Medvednikov <alexander@medvednikov.com>
Date: Tue, 20 Aug 2019 14:34:29 +0300
Subject: [PATCH] table: TypeCategory; freetype: remove C code; [typedef] C
 structs; Objective-C interfaces

---
 compiler/cheaders.v                |   4 +-
 compiler/fn.v                      |   2 +-
 compiler/parser.v                  | 124 ++++++++-----
 compiler/table.v                   |  21 ++-
 vlib/builtin/int.v                 |  16 +-
 vlib/darwin/darwin.v               |  22 +++
 vlib/freetype/freetype.v           | 269 +++++++++++++----------------
 vlib/ui/examples/users_gui/users.v |   2 +-
 8 files changed, 247 insertions(+), 213 deletions(-)
 create mode 100644 vlib/darwin/darwin.v

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 <Cocoa/Cocoa.h>
+#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
 }