1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

Compare commits

...

351 Commits

Author SHA1 Message Date
Delyan Angelov
5d653a37b6 os: make process_test.v more portable (prepare for windows) 2021-02-22 09:42:00 +02:00
Delyan Angelov
c37daba41d ci: fix the remaining obsolete reference to time.sleep and time.usleep 2021-02-22 09:12:23 +02:00
Delyan Angelov
da05c7ed1a ci: fix a deprecation time.sleep warning in clipboard 2021-02-22 09:00:30 +02:00
Delyan Angelov
9ab291319c builder: fix thirdparty object files compilation with tcc (no -lxyz with -c) 2021-02-22 08:18:24 +02:00
Lukas Neubert
f18adf7759 parser,fmt: handle array pre-comments separately from exprs (#8884) 2021-02-21 20:18:19 +02:00
Lukas Neubert
18e88d2fc8 test-cleancode: add more of vlib/v (#8882) 2021-02-21 20:17:12 +02:00
Louis Schmieder
7a35131721 vweb: add handle static root & documentation (#8865) 2021-02-21 20:01:29 +02:00
Delyan Angelov
0ccd9f9c6e ci: add match_in_map_init_test.v to skip_with_asan_compiler and skip_with_fsanitize_address in v test-self 2021-02-21 19:56:17 +02:00
yuyi
1a838b1f43 checker: fix error of match in map_init (fix #8579) (#8879) 2021-02-21 17:09:42 +02:00
zakuro
ac4791045f time: consolidate the different sleep functions into time.wait(Duration) (#8853) 2021-02-21 17:05:03 +02:00
Delyan Angelov
b1209aac1b ci: fix building of vlib/x/websocket/websocket_test.v 2021-02-21 17:03:25 +02:00
Delyan Angelov
07df2d3484 ci: fix missing jobs: in websockets.yml 2021-02-21 16:42:09 +02:00
Delyan Angelov
772baa74f1 ci: shorten the new job name to just autobahn_tests 2021-02-21 16:38:46 +02:00
Delyan Angelov
f2ce72c2bf ci: split the websockets tests into their own CI .yml file 2021-02-21 16:35:27 +02:00
Lukas Neubert
cfe9f6d5d3 help: remove http doc server options (#8839) 2021-02-21 16:18:50 +02:00
zakuro
95e5f68b64 cli: don't sort flags / commands by default (#8813) 2021-02-21 16:17:50 +02:00
ka-weihe
1039d39846 ci: test-self with address sanitized compiler (#8866) 2021-02-21 16:09:19 +02:00
spaceface
260f677469 term.ui: use the new [flag] enums (#8881) 2021-02-21 16:07:49 +02:00
Joe Conigliaro
0470baafa6 cgen: fix duplicate optional generation for struct field 2021-02-22 00:00:39 +11:00
Delyan Angelov
514cabd7c8 strings: cleanup strings builder, allow reusing it 2021-02-21 13:34:29 +02:00
yuyi
6e46f3850c ast: change expr.is_mut_ident() to expr.is_auto_deref_var() (#8869) 2021-02-21 12:15:36 +02:00
zakuro
7928689ee2 parser: set is_public when registering enum type symbols (#8875) 2021-02-21 12:13:52 +02:00
Ben-Fields
b9edc4a414 docs: document the [console] attribute (#8870)
Document the [console] attribute in docs.md.

Co-authored-by: Ben-Fields <>
2021-02-21 11:56:34 +02:00
yuyi
9a744b6750 cgen: fix in map_literal (fix #8868) (#8871) 2021-02-21 11:54:30 +02:00
Ben-Fields
3907a1ab49 docs: document enum <-> int assignment and casting (#8872) 2021-02-21 11:54:13 +02:00
Ben-Fields
cb7c5d58d9 docs: add a unions section (#8873) 2021-02-21 11:51:34 +02:00
yuyi
e106dc3ad5 cgen: fix match_return with complex expr stmts (#8876) 2021-02-21 11:47:46 +02:00
Stanislav Ershov
44177c4e7c builder: use stable MSVC version instead preview (#8867) 2021-02-21 00:00:44 +02:00
Nicolas Sauzede
f67a4c3ee0 checker, cgen: allow | between bitfield enum values, autogenerate a more specific .str method for them too (#8856) 2021-02-20 21:51:54 +02:00
penguindark
cc565b22a9 regex: remove [deprecated] functions/methods, code clean, add test for regex_base (#8862) 2021-02-20 21:39:08 +02:00
yuyi
8f486cb8cf ast: minor cleanup of ast.v (#8859) 2021-02-20 20:50:43 +02:00
Stanislav Ershov
c190b6a131 vlib: remove older deprecated functions (#8864) 2021-02-20 20:42:55 +02:00
Stanislav Ershov
30ed201600 cgen: cleanup header for MSVC (#8863) 2021-02-20 20:39:46 +02:00
Delyan Angelov
746dfe6317 ci: make vweb and websocket tests more robust to transient errors 2021-02-20 20:24:21 +02:00
Nick Treleaven
28088cc494 checker: check fixed array index when it's a literal (#8831) 2021-02-20 20:18:47 +02:00
Delyan Angelov
5a333b0fdc gen,parser: allow enums as map keys 2021-02-20 19:39:25 +02:00
Nick Treleaven
1e71c0eaca checker: warn for deprecated methods too (#8861) 2021-02-20 19:25:54 +02:00
Wink Saville
5243c5adce doc: update the cross-platform shell scripts section (#8791) 2021-02-20 18:55:24 +02:00
spaceface
adf2aa8760 pref: add a -debug-tcc alias option (#8834) 2021-02-20 18:53:22 +02:00
spaceface
cc3fd5333b builder: print tcc output, when the system C compiler also failed (#8835) 2021-02-20 18:52:54 +02:00
yuyi
c704a49283 parser: fix error of $tmpl in anon_fn (fix #8847) (#8849) 2021-02-20 18:51:08 +02:00
Delyan Angelov
8327c9afc1 checker: support a custom [deprecated: 'message'] 2021-02-20 17:35:44 +02:00
Stanislav Ershov
44cb0426f4 cli: fix checking callbacks (#8858) 2021-02-20 17:30:39 +02:00
Lukas Neubert
a86bf3254a fmt: keep empty line between if statement and comment (#8846) 2021-02-20 16:05:05 +02:00
Lukas Neubert
901aa83e65 vdoc: hide README toc entry without readme (#8841) 2021-02-20 16:03:10 +02:00
Lukas Neubert
329e3938d9 fmt: respect user choice of newlines between functions without body (#8838) 2021-02-20 16:00:30 +02:00
yuyi
783cee98d9 table/parser: minor optimization of anon_fn names (#8851) 2021-02-20 15:54:47 +02:00
yuyi
e8abda189a cgen: minor optimization in match_expr() (#8848) 2021-02-20 15:51:40 +02:00
Nick Treleaven
2be852e461 arrays: use for/in instead of unsafe [direct_array_access] (#8857) 2021-02-20 15:27:36 +02:00
Lukas Neubert
38d1eac7f5 vdoc: fix padding above heading (#8842) 2021-02-20 15:16:51 +02:00
zakuro
f381836f9e fmt: sort names in selective imports (#8827) 2021-02-20 12:22:09 +01:00
yuyi
5e1159e4c3 checker: change non-const size of fixed array error message (#8850) 2021-02-20 12:14:44 +01:00
Lukas Neubert
859d382c6e fmt: remove a few obsolete comments (#8837) 2021-02-20 09:54:55 +01:00
Delyan Angelov
3a65ccd060 examples: make examples/templates/templates.v runable from everywhere, not just . 2021-02-19 17:29:35 +02:00
Nick Treleaven
bcb35e15f9 checker: only allow passing integer *literal* to non-integer pointer method parameter (#8825) 2021-02-19 14:14:40 +02:00
Miccah
a153ec5951 cli: ensure that required flags are set (#8826) 2021-02-19 12:43:18 +02:00
kristof de spiegeleer
3f3bec45fa examples: add a template example, update the regex examples (#8829) 2021-02-19 12:39:15 +02:00
zakuro
6e262b5d84 checker: improve error position of infix expr (#8828) 2021-02-19 12:38:41 +02:00
Swastik Baranwal
ad162cd6fc checker: stricter unknown type checks, show better suggestions (#8816) 2021-02-19 11:23:13 +02:00
Stanislav Ershov
6a752512b2 os: fix os.real_path on Windows (#8822) 2021-02-19 11:20:06 +02:00
Subhomoy Haldar
745b40c0a3 rand: refactor string sampling functions to remove redundancy (#8830) 2021-02-19 11:16:02 +02:00
Delyan Angelov
10de905376 ci: fix thirdparty/stdatomic/win/atomic.h (now __faststorefence is part of tcc's std headers) 2021-02-18 19:49:04 +02:00
yuyi
4878077c62 gen/c: fix gen_str_for_struct with custom ref str (fix #7179) (#8820) 2021-02-18 18:19:42 +02:00
Delyan Angelov
252074836b tools: fix permission problems after sudo v symlink 2021-02-18 18:11:14 +02:00
Alexander Medvednikov
0dbc9417e7 builder: vfmt msvc.v 2021-02-18 17:00:07 +03:00
Stanislav Ershov
51dd22bcc0 builder: support -m32/-m64 flags for msvc (#8819) 2021-02-18 14:58:47 +01:00
zakuro
1891ebf22d scanner: print multibyte char for invalid char error (#8804) 2021-02-18 15:43:39 +02:00
Delyan Angelov
0142d58aa6 v.pref: prevent Too many targets. from triggering when the command is an external one 2021-02-18 12:13:28 +02:00
Delyan Angelov
ac7feb9bca ci: fix sokol_shader_examples.yml 2021-02-18 11:47:01 +02:00
zakuro
0d69d97143 fmt: mark imports as used, when types from them are used in struct declarations (#8810) 2021-02-18 11:32:45 +02:00
zakuro
a34a1ab864 checker/table: minor cleanup by removing unnecessary _ variable (#8801) 2021-02-18 11:30:43 +02:00
penguindark
198b395cde examples: add examples/sokol/05_instancing_glsl, cleanup code (#8809) 2021-02-18 11:11:26 +02:00
zakuro
b3a26ca0ce v.pref: make passing multiple target .v files an error (#8814) 2021-02-18 09:42:00 +02:00
R cqls
a08eb9cd8a sokol: fix dragging events on macos in sokol_app.h (#8817) 2021-02-18 09:40:43 +02:00
yuyi
a119affeba cgen: check unknown sizeof type (#8815) 2021-02-18 09:38:57 +02:00
Delyan Angelov
bf6e9ff95a Revert "parser: make duplicated functions an error (#8792)"
This reverts commit 21bf8fe14e.
2021-02-18 09:02:56 +02:00
zakuro
21bf8fe14e parser: make duplicated functions an error (#8792) 2021-02-17 20:50:10 +01:00
Nick Treleaven
33d8074846 crypto.rand: use byteptr.vbytes instead of c_array_to_bytes_tmp (#8786) 2021-02-17 21:47:19 +02:00
Nick Treleaven
4ccf991f61 checker: warn when casting a fixed array (use &arr[0] instead) (#8787) 2021-02-17 20:45:11 +01:00
yuyi
177c8bfc78 builtin/array: merge array_eq_test.v into array_test.v (#8796) 2021-02-17 20:44:44 +01:00
yuyi
4fa315edc2 checker: fix for _, mut j in array (#8785) 2021-02-17 20:44:28 +01:00
zakuro
600f6ad2a0 fmt: do not prepend mod to selectively imported types from nested module (#8805) 2021-02-17 20:42:26 +01:00
Delyan Angelov
ab6517c5fc gg: support passing down the state of pressed mouse buttons in mouse moves events 2021-02-17 20:14:37 +02:00
Alexander Medvednikov
e662d61573 examples: fix 2048 scaling 2021-02-17 16:18:33 +01:00
Delyan Angelov
aa3d0ea345 vfmt: cleanup spurious printlns, remove obsolete code 2021-02-17 14:59:42 +02:00
Delyan Angelov
217e8c9146 ci,examples: fix compilation of 03_march_tracing_glsl/rt_glsl.v 2021-02-17 11:07:31 +02:00
Alexander Medvednikov
023f6829a1 examples: fix rt_glsl.v 2021-02-17 06:57:32 +01:00
R cqls
ba131ce914 gg: fix mouse_down on macos (#8799) 2021-02-17 06:56:58 +01:00
Alexander Medvednikov
2f328f952e examples: fix fireworks.v 2021-02-17 06:50:09 +01:00
Alexander Medvednikov
60a8881326 examples: fix and vfmt cube_glsl example 2021-02-17 06:47:41 +01:00
Alexander Medvednikov
d4a05bebde gg: use gg types for Events instead of sapp 2021-02-17 06:44:01 +01:00
zakuro
3341c17202 fmt: keep one empty line in struct decl (#8782) 2021-02-17 05:45:09 +01:00
Lukas Neubert
55b69a76a6 fmt: minor cleanup of or_expr (#8789) 2021-02-17 05:43:29 +01:00
Nick Treleaven
0f8edd918a checker: disallow unsafe map copy (#8720) 2021-02-17 05:19:25 +01:00
Lukas Neubert
e4a67dea37 json2: wrap Builder.free() calls inside unsafe (#8790) 2021-02-17 02:19:26 +02:00
Delyan Angelov
2002d20249 io: remove unused Zzz_CoerceInterfaceTableGeneration struct; add test for x := Enum{} 2021-02-17 01:37:05 +02:00
Delyan Angelov
995e1c84a2 ci: fix ./v -cc gcc -cflags "-Werror" vlib/io/os_file_reader_test.v 2021-02-17 01:08:28 +02:00
Delyan Angelov
fb09333a73 ci: fix interface table generation for vlib/io/os_file_reader_test.v with -cflags "-Werror" 2021-02-16 23:36:44 +02:00
Delyan Angelov
4961d3ea17 io: fix detection of end_of_stream, when reading files through io.new_buffered_reader(reader: io.make_reader(f)) 2021-02-16 23:22:17 +02:00
Delyan Angelov
843de10442 parser,gen: fix `arr << map[key] using map_get_and_set_1, leading to double free 2021-02-16 16:39:31 +02:00
yuyi
982e35909d cgen: fix mut var in for loop reads as address (fix #8548) (#8745) 2021-02-16 13:24:19 +01:00
Nick Treleaven
01aa09d515 checker: do not allow copying any map lvalue (#8662) 2021-02-16 12:46:12 +01:00
zakuro
51c286df5a fmt: fix bug that vfmt removes emmbeded struct in struct decl (#8775) 2021-02-16 12:45:56 +01:00
Christopher Dieringer
94429c8fd8 gg: window_size: normalize dpi scaling (#8738) 2021-02-16 12:41:21 +01:00
Uwe Krüger
0520b755f4 checker/cgen: support print*(), .str() and '$x' for shared (#8771) 2021-02-16 12:40:13 +01:00
zakuro
6813866141 fmt: fix bug of disappearing pub in struct decl (#8777) 2021-02-16 12:39:50 +01:00
Delyan Angelov
0bbc5a5c6a fmt: add a small comment about f.line_len 2021-02-16 10:22:39 +02:00
Lukas Neubert
ad20b3806f fmt: fix possible code corruption by unwrapped single line if (#8780) 2021-02-16 10:13:48 +02:00
Delyan Angelov
230372df09 clipboard: fix unsafe warning on windows (affects v-ui) 2021-02-15 20:09:02 +02:00
Nick Treleaven
c057b45bb1 checker: check argument count for C fn with attribute (#8728) 2021-02-15 18:56:26 +02:00
zakuro
2911f03627 checker: reject method that have multi-value type receiver (#8696) 2021-02-15 17:55:54 +02:00
zakuro
70a30374b9 parser: cleanup fn_decl (#8700) 2021-02-15 17:55:08 +02:00
Lukas Neubert
848295cdea scanner: do not warn on \' after string interpolation (#8729) 2021-02-15 17:54:30 +02:00
Quix
486bf8517f builtin: fix typo (#8747) 2021-02-15 17:54:07 +02:00
Quix
6a21b8cc8b pg: fix typo (#8750) 2021-02-15 17:53:38 +02:00
Quix
35f45b8e5e glm: fix typo (#8748) 2021-02-15 17:53:07 +02:00
Quix
49505d4090 hash.crc32: fix typo (#8749) 2021-02-15 17:52:45 +02:00
Quix
64018e6f14 encoding.utf8: fix 'length' typo in two spots (#8746) 2021-02-15 17:52:00 +02:00
zakuro
d08a0b5a7c parser: check not used expression for all exprs in multi-expr (#8733) 2021-02-15 17:41:04 +02:00
spaceface
fe007f9b16 gen: fix type_name for sumtype/interface pointers (#8769) 2021-02-15 17:35:31 +02:00
AAAA
4213851e22 cli: fix typo (#8742) 2021-02-15 17:25:30 +02:00
Nick Treleaven
4a0367a63c vlib: add [unsafe] tag to more functions: tos, string_from_wide, strings.Builder: write_bytes, free (#8766) 2021-02-15 17:15:52 +02:00
Louis Schmieder
4bdbb0cfa8 orm: add type detection of db (#8756) 2021-02-15 17:14:39 +02:00
Ruofan XU
94acc27ee6 ci: enable v to js, build-examples, v doctor, build-vbinaries, self-compilation on all windows CI (#8739) 2021-02-15 17:12:22 +02:00
yuyi
a9c2045dbd cgen: fix var name clash of array/map (fix #1994) (#8765) 2021-02-15 15:51:57 +02:00
Nick Treleaven
629d43caf5 checker: warn when using goto outside of unsafe (#8741) 2021-02-15 15:48:24 +02:00
Peter Badida
6781f732f4 gen: fix infinite loop when struct's ref field is pointing to self (#8632) (#8641) 2021-02-15 15:43:10 +02:00
penguindark
325aef6d41 gg: add gg.m4, use it in the sokol GLSL examples (#8755) 2021-02-15 15:40:28 +02:00
spaceface
e3649ec4d3 all: implement type_name() for interfaces too (#8767) 2021-02-15 15:29:44 +02:00
zakuro
4e2418e9cf os: add test for os.file_name (#8757) 2021-02-15 07:37:35 +01:00
Nick Treleaven
b07f373433 builtin: make 5 C functions trusted, tweak signatures (#8730) 2021-02-14 19:37:32 +01:00
Nick Treleaven
ea803113c3 checker: check unsafe V function calls (#8752) 2021-02-14 19:31:42 +01:00
zakuro
d3bcd5d305 fmt: keep single line if in struct init (#8734) 2021-02-14 19:22:24 +01:00
zakuro
e534b4397d checker: report correct position for non-bool cond error (#8735) 2021-02-14 19:19:41 +01:00
Nick Treleaven
82650ee813 parser: fix parsing attribute after fn prototype with no return type (#8727) 2021-02-14 08:05:20 +01:00
zakuro
e4f15605c0 checker: reject void type condition (#8737) 2021-02-14 07:33:24 +01:00
Delyan Angelov
3d29f819cf builder: add markused.mark_used calls to js.v and x64.v 2021-02-13 18:09:04 +02:00
Delyan Angelov
e809264f12 builder,checker: split the unused marking into a new v.markused module 2021-02-13 18:02:31 +02:00
Nick Treleaven
4ef3a21c8a doc: fix Modules position in contents (#8722) 2021-02-13 16:57:51 +02:00
Nick Treleaven
99270c6935 doc: improve const docs (#8723) 2021-02-13 16:54:42 +02:00
Nick Treleaven
f23ffb8322 doc: group for/in forms (#8721) 2021-02-13 16:53:02 +02:00
Uwe Krüger
374739b804 all: rename [ref_only] -> [heap] (#8718) 2021-02-13 16:52:01 +02:00
Delyan Angelov
2a8d0ddaf5 checker: add os.init_os_args_wide to the -skip-unused whitelist too 2021-02-13 16:33:35 +02:00
Delyan Angelov
60c16313f3 checker: enable ./v -skip-unused self 2021-02-13 16:08:44 +02:00
Delyan Angelov
eaaac220be checker: make -skip-unused more conservative to make v test vlib/builtin pass 2021-02-13 15:47:17 +02:00
Uwe Krüger
835b3b2b81 sync: simplify WaitGroup and PoolProcessor and use atomic counters (#8715) 2021-02-13 13:52:27 +01:00
Nick Treleaven
d03c1d615a os: improve rm error message (#8719) 2021-02-13 13:51:38 +01:00
Delyan Angelov
0b60510c9c cgen: cleanup generating helper comments with -skip-unused 2021-02-13 10:31:48 +02:00
Ned Palacios
ebb5305b27 vdoc: fix markdown toc link rendering (#8714) 2021-02-13 09:04:47 +02:00
Ned Palacios
db609a0784 checker: skip checking for invalid fn return type (#8703) 2021-02-13 01:21:05 +01:00
Uwe Krüger
40066a5daa checker: obey [ref_only] tag, allow embedding in other ref struct (#8707) 2021-02-13 00:47:37 +01:00
glebbash
aa548f45ea docs: fix functions in array/map example (#8695) 2021-02-12 21:10:54 +02:00
bettafish04
0b777c68c3 net: fix unix sockets (#8697) 2021-02-12 20:10:06 +02:00
odidev
2781a2b923 binary_artifact.yml: add a V release for Linux/ARM64 too (#8698)
Added 'build-linux-arm64' job with the QEMU support to the binary_artifact.yml file, to release vlang/v Linux/ARM64 zip archive.

Signed-off-by: odidev <odidev@puresoftware.com>
2021-02-12 20:08:55 +02:00
StunxFS
6b431b18f5 vweb.tmpl: fix a little typo (#8704) 2021-02-12 20:06:37 +02:00
Joe Conigliaro
c904c9178d checker: support ParExpr for trying to take address errors & simplify messages 2021-02-13 02:49:22 +11:00
Delyan Angelov
1675b6f3e0 ci: fix code-formatting job 2021-02-12 15:44:12 +02:00
Joe Conigliaro
5d36a59dd8 checker: fix returning [] from fn which retuns optional array 2021-02-12 22:30:30 +11:00
Alexander Medvednikov
0a03856c83 parser: small c2v fixes 2021-02-12 09:12:26 +01:00
yuyi
67c6f24c84 cgen: format match_expr (#8692) 2021-02-12 03:37:31 +01:00
yuyi
3164e29651 all: fix fn_or_for_in mut value (part 1) (#8671) 2021-02-12 02:03:11 +02:00
Nick Treleaven
84a16d8684 map: add move method (#8660) 2021-02-12 02:02:33 +02:00
Larpon
65f2420516 os: fix cp_all mkdir panic (#8680) 2021-02-12 01:55:36 +02:00
Nick Treleaven
375efb0953 checker: improve errors for return count mismatch (#8686) 2021-02-12 01:47:11 +02:00
penguindark
9d5243a410 examples: add an example of march tracing in glsl, first release (#8689) 2021-02-12 01:42:10 +02:00
Joe Conigliaro
317d450723 checker: add error when trying to take address of call expr 2021-02-12 10:39:02 +11:00
Larpon
4770036e23 docs: fix "plugin-in" beef (#8688) 2021-02-12 01:36:47 +02:00
Delyan Angelov
8f6fec4364 ci: fix building examples/concurrency/concurrency.v on macos 2021-02-12 01:18:40 +02:00
Delyan Angelov
58393bd3f9 ci: fix unix_test.v on unix != macos 2021-02-12 01:12:42 +02:00
Delyan Angelov
89521584a2 ci: fix unix sockets test on macos 2021-02-11 22:34:38 +02:00
bettafish04
9b4f2edbfa net: move unix socket code to net.unix and skip net/unix/unix_test.v … (#8681) 2021-02-11 18:51:12 +02:00
Delyan Angelov
f8db44bb15 ci: update reference to pool_test.v in skip_with_werror in v test-self 2021-02-11 13:12:00 +02:00
Delyan Angelov
ea401b1192 ci: #include <afunix.h> in vlib/net/net_windows.c.v 2021-02-11 12:45:25 +02:00
Larpon
23a7d4a0c6 readme: mention graphical app android support (#8679) 2021-02-11 11:17:00 +01:00
zakuro
f390fe3086 CONTRIBUTING.md: update outdated name to correct one (#8677) 2021-02-11 11:04:44 +02:00
Delyan Angelov
578de634fe sync: move pool related code to sync.pool, cleanup, add a README.md 2021-02-11 10:55:23 +02:00
Delyan Angelov
93c1c1cec3 builder: add generated C lines with -stats too 2021-02-11 08:38:09 +02:00
cbracketdash
c636a7080d rand: add rand.ascii (#8675) 2021-02-11 08:32:40 +02:00
bettafish04
d4f6488afd net: add better unix socket support (#8651) 2021-02-11 01:24:15 +01:00
Ruofan XU
8b1337029f ci: add build-examples task to tcc-windows CI (#8653) 2021-02-11 01:23:03 +01:00
zakuro
f371803a32 cgen: move comp_if_to_ifdef to comptime.v (#8668) 2021-02-11 01:22:49 +01:00
Delyan Angelov
de287c0add builder: add C source code size info on -stats 2021-02-10 19:12:12 +02:00
zakuro
4305ce1493 checker: extract long match branches in c.stmt(), into separate checker functions (#8666) 2021-02-10 18:51:41 +02:00
SurmanPP
f2ad6dd4d9 os: fix os.walk, when passing paths ending with path_separator (#8672) 2021-02-10 18:48:01 +02:00
Delyan Angelov
4646c414d8 checker: fix -skip-unused with struct inits with default expressions 2021-02-10 18:25:57 +02:00
cbracketdash
eb7009b60a rand: generate hexadecimal numbers (#8664) 2021-02-10 11:01:25 +01:00
yuyi
f2e74bce7a checker: fix sumtype assign error (fix #7988) (#8655) 2021-02-10 10:59:56 +01:00
Alexander Medvednikov
035a163454 json: encode_pretty (p. 2) + tests 2021-02-10 10:17:29 +01:00
Alexander Medvednikov
f67e4ab57c json: encode_pretty (p. 1) 2021-02-10 10:13:06 +01:00
Delyan Angelov
db2266598a binary_artifact.yml: ensure v_old.exe is not in the release archives. 2021-02-10 11:06:17 +02:00
yuyi
95c3ef3a6a cgen: minor cleanup in stmt() (#8659) 2021-02-09 23:00:43 +01:00
Uwe Krüger
f3c5f24c17 allow lock expression to return multiple objects (#8657) 2021-02-09 17:09:10 +02:00
Nick Treleaven
d37fb5641f parser: improve printing of unexpected tokens (#8654) 2021-02-09 17:07:30 +02:00
Bobitsmagic
0f92485698 builtin: fix typo in builtin/array.v (#8658) 2021-02-09 17:04:47 +02:00
Swastik Baranwal
6de78ecb59 term: implement term.clear() for windows (#8650) 2021-02-09 14:25:31 +02:00
Delyan Angelov
5308b63a01 ci: fix the -cflags "-Werror" job, by explicit casting to void** 2021-02-09 14:22:51 +02:00
Delyan Angelov
d110f0de74 tests: add a regression test for 3d2afcf 2021-02-09 14:11:09 +02:00
Delyan Angelov
3d2afcf02e cgen: fix gohandle_name generation (use .cname) 2021-02-09 12:55:05 +02:00
spaceface
1bb4be17d8 cgen: remove srwlock definition workaround for tcc on windows (#8652) 2021-02-09 12:44:18 +02:00
spaceface
4152c704f3 sokol: remove .lib extensions in #pragma directives (#8639)
fixes tcc on windows - this kind of fix has been done several times in the past, and should probably be upstreamed to sokol soon to prevent things from breaking every time we update the headers.
2021-02-09 11:36:01 +02:00
Mohammad Ali Chraghi
86e6b4f926 examples: improve the pg and vweb output (#8640) 2021-02-09 11:31:25 +02:00
Alexander Medvednikov
bfee8a528c cgen: add "case" to c_reserved 2021-02-09 03:49:19 +01:00
bettafish04
1a2ae0aead net: add basic unix socket support (#8642) 2021-02-08 23:48:23 +01:00
Swastik Baranwal
09cff69919 all: allow using aliases as keys in map (#8589) 2021-02-08 18:51:05 +01:00
Lukas Neubert
8cb01ba8db fmt: keep comments between and after imports (#8637) 2021-02-08 19:48:48 +02:00
Lukas Neubert
cb1f63f765 parser: replace eat_line_end_comments() with configurable eat_comments() (#8636) 2021-02-08 18:16:02 +02:00
Lukas Neubert
5abd49d9bc cgen: cast default struct field value to correct SumType/interface (#8619) 2021-02-08 17:33:05 +02:00
Swastik Baranwal
e2ff26a066 cgen: fix gen of .sort method for > operator and improve grammar of error (#8615) 2021-02-08 17:19:54 +02:00
Nick Treleaven
e2ff2a5405 parser: deprecate {var | struct update (#8618) 2021-02-08 17:03:05 +02:00
yuyi
f2100166c7 cgen: minor cleanup in gen_str_for_option (#8622) 2021-02-08 17:00:51 +02:00
Nick Treleaven
9e751f72c4 doc, fmt: use map{key: value} syntax for map literals (#8623) 2021-02-08 16:57:42 +02:00
zakuro
8ae23cd89e parser: make `v := f(v)' an undefined variable error (#8634) 2021-02-08 16:55:01 +02:00
Delyan Angelov
03d5bfbc95 repl: use os.temp_dir() for the temporary .noprefix.vrepl.v files 2021-02-08 09:44:04 +02:00
zakuro
e5839effbc checker/cgen: allow << operator for aliases (#8561) 2021-02-08 01:41:47 +01:00
Lukas Neubert
473cd1d416 fmt: single line ternary return (#8605) 2021-02-08 00:28:46 +01:00
Uwe Krüger
118ca1240e all: allow shared element types for struct and arrays (#8631) 2021-02-08 00:28:29 +01:00
Lukas Neubert
7f4c582f1a fmt: unwrap long infix exprs inside parenthesis if necessary (#8609) 2021-02-07 23:10:39 +01:00
Nick Treleaven
ff1aa06455 parser: require ++/-- to be on the same line as the previous token (#8621) 2021-02-07 23:10:16 +01:00
ka-weihe
367dbc7707 ci: add tests with -Werror (#8630) 2021-02-07 23:10:01 +01:00
yuyi
81e8c3bc1b cgen: minor optimization in infix_expr (#8625) 2021-02-07 17:22:54 +01:00
Lukas Neubert
46f8e68bec ci: skip process/command example on windows (#8617) 2021-02-07 13:46:22 +02:00
Charles WANG
13350681dd docs.md: use make.bat -tcc under Windows. (#8555) 2021-02-07 12:53:26 +02:00
Larpon
bfd0bd1fb4 builtin: doc chan.v channel stub (#8577) 2021-02-07 12:42:24 +02:00
Larpon
d62918581e example: support running flappylearning on Android (#8612) 2021-02-07 12:40:12 +02:00
Alexander Medvednikov
f589a70874 examples: make a process example compile with -prod 2021-02-07 05:23:45 +01:00
kristof de spiegeleer
2d875260e8 examples: Process examples (#8598) 2021-02-07 05:19:05 +01:00
Alexander Medvednikov
68b4051a6e tools/fast: simplify logic now that it's run on each commit 2021-02-07 05:11:48 +01:00
Alexander Medvednikov
a81ee0e94e tools/fast: measure v.c size and parse/check/cgen steps 2021-02-07 04:48:54 +01:00
Alexander Medvednikov
32cd2846f5 tools/fast: run the job every minute 2021-02-07 04:01:02 +01:00
zakuro
9f59b04e86 fmt: remove unused selective imports (#8595) 2021-02-07 03:58:43 +01:00
Nick Treleaven
cd4f7101f7 parser: support short struct update syntax {...ident, (#8613) 2021-02-07 03:43:51 +01:00
Nick Treleaven
b92f980274 token: fix Token.str() for punctuation and operators (#8610) 2021-02-07 03:40:00 +01:00
Alexander Medvednikov
d284918554 tools/fast: push changes to gh pages 2021-02-07 03:35:29 +01:00
Delyan Angelov
d77bb2f606 all: improve -skip-unused, track consts, walk all AST nodes, support tests 2021-02-07 02:51:45 +02:00
Alexander Medvednikov
26121d5ae7 tools/fast: cron job to check for new commits 2021-02-06 22:28:42 +01:00
Nick Treleaven
f5f65f929f parser: parse map{key_expr: val_expr} (#8608) 2021-02-06 22:13:24 +01:00
Lukas Neubert
db0fc8fbc9 fmt: better function call wrapping inside ternary if branches (#8604)
* fmt: better funcation call wrap in singel line ifs

* tests

* format files
2021-02-06 21:46:52 +01:00
Uwe Krüger
cf230644b6 fmt: enable shared return types (#8614) 2021-02-06 21:25:06 +01:00
Uwe Krüger
5343f1374b all: allow functions to return shared object (#8606) 2021-02-06 19:41:52 +01:00
zakuro
fe9d062b41 gen: fix bug where unreached defer is executed (#8594) 2021-02-06 18:40:39 +02:00
Larpon
de9813233f gg: support getting system font on Android (#8611) 2021-02-06 18:36:43 +02:00
Delyan Angelov
e57b73bcfc ci: fix the using_comptime_env.vv test (execute only on ubuntu-tcc again) 2021-02-06 13:07:21 +02:00
Swastik Baranwal
9b839b3b7d cgen: fix gen of > operator overloading (#8600) 2021-02-06 12:59:20 +02:00
Delyan Angelov
1fcac4098b tests: use a serial task runner for -skip-unused too 2021-02-06 10:08:59 +02:00
Delyan Angelov
167773dd1c checker: make -skip-unused process a list of root functions, not just main.main 2021-02-06 09:41:24 +02:00
Delyan Angelov
41cc72e8e8 docs: fix broken link to vlib/net/socket.v 2021-02-06 08:12:43 +02:00
Larpon
e83c39c81a builtin: document rest of map.v (#8578) 2021-02-06 03:07:42 +01:00
Uwe Krüger
ab279dace7 cgen: support shared initialization from call returning optional (#8593) 2021-02-06 03:07:05 +01:00
yuyi
1b6efebac7 all: fix map = map2 assignment (#8581) 2021-02-06 03:06:34 +01:00
Larpon
57258c2988 builtin: document remaining pub structs in builtin.v (#8576) 2021-02-05 21:02:29 +01:00
Larpon
1101533dea crypto: document rest of rand submodule (#8580) 2021-02-05 20:26:34 +02:00
Lukas Neubert
59c1c77bfe check-md: fix missing default_command when nofmt was set (#8591) 2021-02-05 20:25:27 +02:00
Subhomoy Haldar
9a1da1a97b rand: move the shuffle function from arrays to rand.util (#8587) 2021-02-05 20:24:38 +02:00
Delyan Angelov
ed6fc79fbe ci: run the -skip-unused tests on linux (so local testing is easier) 2021-02-05 20:03:24 +02:00
Delyan Angelov
99822e51de ci: force println_os_executable.vv to have a stable output on all OSes 2021-02-05 20:01:02 +02:00
Larpon
e1052a5ec7 semver: document all pub functions (#8586) 2021-02-05 19:57:42 +02:00
Lukas Neubert
58b3a30b47 docs/readmes: format almost all remaining code blocks (#8590) 2021-02-05 19:50:28 +02:00
Delyan Angelov
576492af4e examples: fix 2048 on Apple M1 2021-02-05 19:35:51 +02:00
Delyan Angelov
9a7ecf2807 ci: limit the -skip-unused testing to the ubuntu CI jobs for now 2021-02-05 18:41:46 +02:00
Delyan Angelov
a6ecc19040 ci: fix -skip-unused compiler test on windows, using -d no_backtrace 2021-02-05 18:36:57 +02:00
zakuro
6b776e686e parser: display correct position on boolean expression error (#8563) 2021-02-05 16:52:35 +01:00
Larpon
44ab0154b2 builtin: document last of array.v (#8575) 2021-02-05 16:51:45 +01:00
StunxFS
22e23eda5d doc: use '?' in optional functions (#8583) 2021-02-05 16:51:17 +01:00
zakuro
a94228bb16 checker: make [] == ArrayAlias([]) an error (#8562) 2021-02-05 16:49:40 +01:00
Larpon
e78c30d181 clipboard: add android variant (#8585) 2021-02-05 16:49:04 +01:00
Lukas Neubert
9ab1d17cbc fmt: keep __global in struct declarations (#8584) 2021-02-05 16:46:43 +01:00
Lukas Neubert
76ea3e7b41 tools/check-md: allow directories as args and deprecate -all flag (#8582) 2021-02-05 16:46:20 +01:00
Ruofan XU
12e8e31bb2 doc: document !in (#8546) 2021-02-05 16:45:20 +01:00
Delyan Angelov
81789ee106 tests: add vlib/v/tests/skip_unused/ 2021-02-05 17:27:00 +02:00
Delyan Angelov
867d96a077 checker: use @METHOD for util.timing_start in Checker.mark_used/1 2021-02-05 16:41:55 +02:00
Delyan Angelov
16dffc7c1d compiler: move timing_start/timing_measure to util.timing_start/util.timing_measure 2021-02-05 16:34:56 +02:00
Delyan Angelov
25a3873019 parser,checker: support @METHOD, replaced by 'ReceiverType.MethodName' 2021-02-05 16:32:43 +02:00
Delyan Angelov
d30f94507c checker: enable -skip-unused for more examples 2021-02-05 11:55:40 +02:00
Delyan Angelov
8f160ee3ed ci: run vfmt over vlib/v/gen/c/fn.v 2021-02-05 11:18:29 +02:00
Delyan Angelov
40fff7b56a v.pref: support v -skip-unused run examples/hello_world.v 2021-02-05 11:12:28 +02:00
Delyan Angelov
80697ec7f3 table: .is_used => .usages (a counter, instead of a boolean flag) 2021-02-05 10:03:17 +02:00
Delyan Angelov
231182c3ff docs: vfmt the function example too (fix ci) 2021-02-05 09:30:18 +02:00
Delyan Angelov
e5c9fcb7e9 ci: fix building vdoc, vls, etc 2021-02-05 09:27:14 +02:00
Delyan Angelov
395fcc1476 thirdparty: remove unused glad folder (leftover from glfw) 2021-02-05 09:19:30 +02:00
Alexander Medvednikov
5a183d23a9 cgen: disable the new [if xxx] logic for now 2021-02-05 08:16:16 +01:00
Alexander Medvednikov
1084b43ffb all: ast walker for marking unused fns 2021-02-05 08:05:35 +01:00
Delyan Angelov
119dfc0bb0 all: support map[f32]string and map[f64]string (float map keys) too (#8556) 2021-02-04 23:59:49 +01:00
Alexander Medvednikov
97e36cd97a parser: fix method name test 2021-02-04 22:25:58 +01:00
Alexander Medvednikov
fdd8c86fdb parser: make sure methods have names 2021-02-04 22:15:16 +01:00
Ekopalypse
5eef730290 builder: make msvc build if v path contains spaces (#8552) 2021-02-04 20:45:59 +01:00
Delyan Angelov
48892a52fa strings: make valgrind reports for strings builders more usefull (#8553) 2021-02-04 20:45:35 +01:00
Louis Schmieder
97c0ef3505 orm: struct field support (#8517) 2021-02-04 20:28:33 +01:00
Ekopalypse
856246c858 builder: make repl work if path contains spaces (#8550) 2021-02-04 18:18:18 +01:00
Lathanao
a0cbe48977 vweb: fix @include (#8535) 2021-02-04 17:07:04 +01:00
yuyi
abde1cd73d cgen: fix array/map of alias to string (#8549) 2021-02-04 17:52:14 +02:00
Delyan Angelov
32cc95a340 test-cleancode: check some of the examples too 2021-02-04 17:34:59 +02:00
Delyan Angelov
3e4e0a35e3 vvet: fix silent exit when invoked on a single .v file. 2021-02-04 17:23:58 +02:00
Delyan Angelov
1e9ec6a126 vfmt: exit(1) after vfmt-ing a file with a syntax error 2021-02-04 16:00:14 +02:00
Subhomoy Haldar
c6552d7780 rand.util: add sample_r and sample_nr (#8539) 2021-02-04 14:56:53 +02:00
yuyi
a976876211 v.token: correct some comments, and add some missing comments (#8542) 2021-02-04 09:18:38 +02:00
BigBlack
162c42dbe9 ast: fix new_struct := MyStruct{...(*old_struct)} (#8544) 2021-02-04 09:14:43 +02:00
pancake
27239db427 builder: show file:line when import fails (#8537) 2021-02-04 09:09:54 +02:00
Uwe Krüger
112c652ace cgen: auto initialize chan that are struct elements (#8541) 2021-02-04 00:07:20 +01:00
Uwe Krüger
f013e65670 checker/cgen: support lock expressions x := rlock s { s.get() } (#8540) 2021-02-03 23:56:58 +01:00
Uwe Krüger
cee00a3551 cgen: create enclosing block on C side for V lock blocks (#8538) 2021-02-03 23:25:01 +01:00
Uwe Krüger
2424e2cb02 cgen: fix for rlock/lock handling (#8536) 2021-02-03 17:33:18 +01:00
Nick Treleaven
de37b52d4b checker: check goto label exists (#8523) 2021-02-03 15:20:10 +01:00
Nick Treleaven
82482167ce vlib: replace all goto statements with labelled break (#8531) 2021-02-03 15:19:42 +01:00
Swastik Baranwal
7ec116d588 all: only allow defining == and < and auto generate !=, >, >= and <= (#8520) 2021-02-03 15:18:38 +01:00
Uwe Krüger
9dcf673216 all: make lock and rlock dead lock free :-) (#8534) 2021-02-03 15:16:52 +01:00
Delyan Angelov
f4b757e47d examples: add examples/vweb/server_sent_events; implement vweb.sse 2021-02-03 16:03:06 +02:00
Ruofan XU
a73c20916d checker: refactor and clean up c.check_basic() (#8508) 2021-02-03 11:57:06 +02:00
zakuro
4b99d6af95 cgen: fix bug with duplicate defer generation (#8503) 2021-02-03 11:40:21 +02:00
yuyi
b40252bd97 checker: merge array_filter_fn_err tests (#8506) 2021-02-03 11:27:11 +02:00
yuyi
9bcb57eb1f checker: merge array_map_fn_err tests (#8507) 2021-02-03 11:26:26 +02:00
Lukas Neubert
ea06966fd4 fmt: hide ´[]Type{} instead of []Type´ and ´(f mut Foo)´ warnings (#8528) 2021-02-03 11:25:08 +02:00
Aldrin Mathew
49a6f9fb39 README.md: change the V logo url to point to the official V logo repository (#8530) 2021-02-03 11:24:35 +02:00
zakuro
e30e794884 checker: add check for using a private const in another module (#8501) 2021-02-03 10:17:13 +02:00
Lukas Neubert
3ef4885094 vfmt: enable colored warnings/errors (#8527) 2021-02-03 10:03:41 +02:00
Uwe Krüger
df0520b43a checker,cgen: make shared behave like mut inside lock - and like non-mut inside rlock (#8526) 2021-02-03 01:20:19 +02:00
yuyi
91af2418de ftp: minor optimization in dir() (#8518) 2021-02-02 18:51:55 +01:00
Nick Treleaven
9f662002da doc: improve docs for goto, sizeof, __offsetof (#8522) 2021-02-02 18:51:40 +01:00
yuyi
7875164d91 cgen: add gen_alias_equlity_fn (#8514) 2021-02-02 18:37:57 +01:00
Larpon
c818ad97eb examples: tetris: better mobile device support (#8519) 2021-02-02 18:37:43 +01:00
Delyan Angelov
02bef1ae2b vdoc: fix segfault on v doc -m -f html vlib 2021-02-02 17:38:32 +02:00
joe-conigliaro
ffedbe4b81 cgen: move cgen from v.gen to v.gen.c (#8515) 2021-02-02 15:41:51 +01:00
Daniel Däschle
d477e525bb checker/gen: fix generic struct init (#8322) 2021-02-03 00:42:00 +11:00
Lukas Neubert
58b37519e0 scanner: fix warning for \" after string interpolation (#8510) 2021-02-02 14:14:06 +02:00
Uwe Krüger
1de299ad22 cgen: allow shared initialization from return values of functions (#8512) 2021-02-02 14:13:13 +02:00
Larpon
975206f38e examples: support better placment and scaling on nonsquare viewports in cube.v (#8513) 2021-02-02 14:09:40 +02:00
Delyan Angelov
17062dc5c8 v.pref: support -obf in addition to -obfuscate, as described in v help build 2021-02-02 12:24:34 +02:00
Lukas Neubert
5aaeac79fa ci: fix compilation (#8511) 2021-02-02 12:06:54 +02:00
Delyan Angelov
d57a9c419d examples: add net_udp_server_and_client.v 2021-02-02 10:36:56 +02:00
Alexander Medvednikov
2c4674eb42 cgen: obfuscate functions 2021-02-02 09:14:41 +01:00
yuyi
5ec6f7a781 ftp: fix error in dir() (#8504) 2021-02-02 08:22:52 +01:00
yuyi
9a2820fa7b checker: fix pass fixed array of function as argument (#8502) 2021-02-02 03:58:54 +01:00
Ruofan XU
a0a33f7ff1 checker: fix map of function as argument and direct call of function in map (#8494) 2021-02-02 03:58:32 +01:00
Louis Schmieder
969f19daf4 orm: fix null strings (#8497) 2021-02-01 21:44:09 +01:00
Uwe Krüger
8bf3fe5d48 docs: remove & from shared initializers (#8499) 2021-02-01 21:43:45 +01:00
Ruofan XU
51f2eb81f4 checker/cgen: fix mut array of fn as argument (#8469) 2021-02-01 20:10:24 +01:00
William Gooch
49244d91ce doc: goto (#8462) 2021-02-01 20:09:25 +01:00
Lukas Neubert
cf1084105c fmt: allow single line ternary if as function argument (#8486) 2021-02-01 20:08:42 +01:00
Nick Treleaven
79e9084f7b checker: allow Struct{...expr} where expr is another struct type (#8495) 2021-02-01 20:08:25 +01:00
Uwe Krüger
17746561f2 cgen: put shared arrays and maps always on heap (#8496) 2021-02-01 20:07:01 +01:00
yuyi
4d268d1436 cgen: minor cleanup of gen_fn_decl (#8474) 2021-02-01 20:06:34 +01:00
Delyan Angelov
fab7b9d9d9 checker: fix x := match enumexpr { .case2 { fn1 } .case2 { fn2} }, where fn1 and fn2 have compatible signature 2021-02-01 21:01:58 +02:00
BigBlack
e3c2604338 cgen: fixed array slice in function, add docs (#8481) 2021-02-01 19:11:17 +02:00
Lucas Hernán Tarche
7813ecbb75 gg: add draw_convex_poly/2 and draw_empty_poly/2 methods (#8487) 2021-02-01 18:18:23 +02:00
yuyi
1e07173234 cgen: minor cleanup of array_init (#8477) 2021-02-01 15:56:55 +01:00
Alexander Medvednikov
6804fdaa56 doc: document $tmpl 2021-02-01 15:45:52 +01:00
Nick Treleaven
c537578481 checker: ensure expr is an lvalue with Struct{...expr (#8489) 2021-02-01 15:18:03 +01:00
Lukas Neubert
d660f2cc6f fmt: insert newline after last HashStmt (#8482) 2021-02-01 14:50:41 +01:00
yuyi
53a5aad855 cgen: fix fixed array of function (#8490) 2021-02-01 14:50:10 +01:00
Lukas Neubert
8755f40430 fmt: keep comments after imports (#8483) 2021-02-01 14:45:08 +01:00
Uwe Krüger
44ec9e3ebc checker/cgen: put shared struct always on heap (#8492) 2021-02-01 14:39:36 +01:00
Delyan Angelov
5b9a7bf6b3 cgen: support #flag -DWIN32_FULL, when you do NOT want WIN32_FULL 2021-02-01 14:40:51 +02:00
585 changed files with 18798 additions and 12384 deletions

View File

@@ -38,7 +38,40 @@ jobs:
with:
name: linux-binary
path: ./v
build-linux-arm64:
runs-on: ubuntu-20.04
strategy:
matrix:
compiler: [gcc]
env:
img: quay.io/pypa/manylinux2014_aarch64
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
- name: Compile
env:
CC: ${{ matrix.compiler }}
run: |
docker run --platform=linux/arm64 --rm -v `pwd`:`pwd` -w `pwd` ${{ env.img }} /bin/bash -c "make -j4 && ./v -cc $CC -o v -prod cmd/v && ./v -prod cmd/tools/vup.v && ./v -prod cmd/tools/vdoctor.v"
- name: Create artifact
uses: actions/upload-artifact@v2
with:
name: linux_arm64
path: |
.
./cmd/tools/vup
./cmd/tools/vdoctor
!./.git
!./vc
!./v_old
- name: Create binary only artifact
uses: actions/upload-artifact@v2
with:
name: linux_arm64-binary
path: ./v
build-macos:
runs-on: macos-latest
strategy:
@@ -90,7 +123,7 @@ jobs:
./cmd/tools/vdoctor.exe
!./.git
!./vc
!./v_old
!./v_old.exe
- name: Create binary only artifact
uses: actions/upload-artifact@v2
with:
@@ -99,7 +132,7 @@ jobs:
release:
name: Create Github Release
needs: [build-linux, build-windows, build-macos]
needs: [build-linux-arm64, build-linux, build-windows, build-macos]
runs-on: ubuntu-20.04
steps:
- name: Get short tag name
@@ -124,7 +157,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
version: [linux, macos, windows]
version: [linux_arm64, linux, macos, windows]
steps:
- uses: actions/checkout@v1
- name: Fetch artifacts
@@ -144,6 +177,7 @@ jobs:
chmod 755 cmd/tools/vup.exe || true
chmod 755 cmd/tools/vdoctor || true
chmod 755 cmd/tools/vdoctor.exe || true
rm -rf v_old v_old.exe
cd ..
zip -r9 --symlinks ../v_${{ matrix.version }}.zip v/*
cd ..

View File

@@ -106,6 +106,8 @@ jobs:
./cmd/tools/test_if_v_test_system_works
- name: Self tests
run: ./v -silent test-self
- name: Self tests (-Werror)
run: ./v -cflags "-Werror" test-self
- name: Test time functions in a timezone UTC-12
run: TZ=Etc/GMT+12 ./v test vlib/time/
- name: Test time functions in a timezone UTC-3
@@ -254,7 +256,7 @@ jobs:
## sudo apt-get install --quiet -y libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev
- name: Build V
run: make -j4 && ./v -cc gcc -cg -cflags -Werror -o v cmd/v
- name: Valgrind
- name: Valgrind v.c
run: valgrind --error-exitcode=1 ./v -o v.c cmd/v
- name: Run sanitizers
run: |
@@ -289,6 +291,8 @@ jobs:
./v -silent test-self
- name: Self tests (-prod)
run: ./v -o vprod -prod cmd/v && ./vprod -silent test-self
- name: Self tests (-Werror)
run: ./v -cc gcc -cflags "-Werror" test-self
- name: Build examples
run: ./v build-examples
- name: Build examples with -autofree
@@ -306,7 +310,7 @@ jobs:
./v build-module vlib/v/token
./v build-module vlib/v/ast
./v build-module vlib/v/parser
./v build-module vlib/v/gen
./v build-module vlib/v/gen/c
./v build-module vlib/v/depgraph
./v build-module vlib/os/cmdline
- name: x64 machine code generation
@@ -358,9 +362,11 @@ jobs:
./v -o v2 cmd/v -cflags -fsanitize=memory
./v -o v3 cmd/v -cflags -fsanitize=thread
./v -o v4 cmd/v -cflags -fsanitize=undefined
./v -o v5 cmd/v -cflags -fsanitize=address
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v2 -o v.c cmd/v
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v3 -o v.c cmd/v
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v4 -o v.c cmd/v
ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v5 -o v.c cmd/v
- name: v self compilation
run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
- name: v self with -usecache
@@ -374,6 +380,8 @@ jobs:
./v -silent test-self
- name: Self tests (-prod)
run: ./v -o vprod -prod cmd/v && ./vprod -silent test-self
- name: Self tests (-Werror)
run: ./v -cflags "-Werror" test-self
- name: Build examples
run: ./v build-examples
- name: Build examples with -autofree
@@ -391,7 +399,7 @@ jobs:
./v build-module vlib/v/token
./v build-module vlib/v/ast
./v build-module vlib/v/parser
./v build-module vlib/v/gen
./v build-module vlib/v/gen/c
./v build-module vlib/v/depgraph
./v build-module vlib/os/cmdline
- name: x64 machine code generation
@@ -407,7 +415,7 @@ jobs:
echo "Running it..."
ls
tests-sanitize-undefined:
tests-sanitize-undefined-clang:
runs-on: ubuntu-20.04
timeout-minutes: 30
env:
@@ -426,11 +434,33 @@ jobs:
sudo apt-get install clang
## sudo apt-get install --quiet -y libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev
- name: Build V
run: make -j4 && ./v -cc clang -cg -cflags -Werror -o v cmd/v
run: make -j4 && ./v -cg -cflags -Werror -o v cmd/v
- name: Self tests (-fsanitize=undefined)
run: ./v -cc clang -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
run: ./v -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
tests-sanitize-undefined-gcc:
runs-on: ubuntu-20.04
timeout-minutes: 30
env:
VFLAGS: -cc gcc
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Install dependencies
run: |
sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list;
sudo apt-get update;
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
sudo apt-get install --quiet -y libglfw3 libglfw3-dev libfreetype6-dev libxi-dev libxcursor-dev libasound2-dev
## sudo apt-get install --quiet -y libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev
- name: Build V
run: make -j4 && ./v -cg -cflags -Werror -o v cmd/v
- name: Self tests (-fsanitize=undefined)
run: ./v -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
tests-sanitize-address:
tests-sanitize-address-clang:
runs-on: ubuntu-20.04
timeout-minutes: 30
env:
@@ -449,11 +479,67 @@ jobs:
sudo apt-get install clang
## sudo apt-get install --quiet -y libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev
- name: Build V
run: make -j4 && ./v -cc clang -cg -cflags -Werror -o v cmd/v
run: make -j4 && ./v -cg -cflags -Werror -o v cmd/v
- name: Self tests (-fsanitize=address)
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags -fsanitize=address test-self
- name: Self tests (V compiled with -fsanitize=address)
run:
./v -cflags -fsanitize=address -o v cmd/v &&
ASAN_OPTIONS=detect_leaks=0 ./v -cc tcc test-self -asan-compiler
tests-sanitize-address-msvc:
runs-on: windows-2019
timeout-minutes: 30
env:
VFLAGS: -cc msvc
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Build
run: |
echo %VFLAGS%
echo $VFLAGS
.\make.bat -msvc
.\v.exe -cflags /WX self
- name: Install dependencies
run: |
.\v.exe setup-freetype
.\.github\workflows\windows-install-sqlite.bat
## .\.github\workflows\windows-install-sdl.bat
- name: Self tests (-fsanitize=address)
run: |
.\v.exe -cflags "-fsanitize=address" test-self
tests-sanitize-memory:
tests-sanitize-address-gcc:
runs-on: ubuntu-20.04
timeout-minutes: 30
env:
VFLAGS: -cc gcc
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Install dependencies
run: |
sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list;
sudo apt-get update;
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
sudo apt-get install --quiet -y libglfw3 libglfw3-dev libfreetype6-dev libxi-dev libxcursor-dev libasound2-dev
sudo apt-get install clang
## sudo apt-get install --quiet -y libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev
- name: Build V
run: make -j4 && ./v -cg -cflags -Werror -o v cmd/v
- name: Self tests (-fsanitize=address)
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags -fsanitize=address test-self
- name: Self tests (V compiled with -fsanitize=address)
run:
./v -cflags -fsanitize=address -o v cmd/v &&
ASAN_OPTIONS=detect_leaks=0 ./v -cc tcc test-self -asan-compiler
tests-sanitize-memory-clang:
runs-on: ubuntu-20.04
timeout-minutes: 30
env:
@@ -559,9 +645,9 @@ jobs:
VFLAGS: -cc gcc
steps:
- uses: actions/checkout@v2
#- uses: actions/setup-node@v1
# with:
# node-version: 12.x
- uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Build
run: |
gcc --version
@@ -573,6 +659,9 @@ jobs:
.\v.exe setup-freetype
.\.github\workflows\windows-install-sqlite.bat
## .\.github\workflows\windows-install-sdl.bat
- name: v doctor
run: |
./v doctor
- name: Verify `v test` works
run: |
./v cmd/tools/test_if_v_test_system_works.v
@@ -580,14 +669,15 @@ jobs:
- name: Self tests
run: |
.\v.exe -silent test-self
# - name: Test
# run: |
# .\v.exe -silent test-all
## v.js dosent work on windows
#.\v.exe -o hi.js examples/hello_v_js.v
#node hi.js
# - name: Test
# run: |
# .\v.exe -silent test-all
- name: Test v->js
run: ./v -o hi.js examples/hello_v_js.v && node hi.js
- name: Test v binaries
run: ./v build-vbinaries
- name: Build examples
run: ./v build-examples
- name: v2 self compilation
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
@@ -598,9 +688,9 @@ jobs:
VFLAGS: -cc msvc
steps:
- uses: actions/checkout@v2
#- uses: actions/setup-node@v1
# with:
# node-version: 12.x
- uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Build
run: |
echo %VFLAGS%
@@ -623,16 +713,17 @@ jobs:
run: |
./v -cg cmd\tools\vtest-self.v
./v -silent test-self
- name: Build examples
run: ./v build-examples
# - name: Test
# run: |
# .\v.exe -silent test-all
# ## v.js dosent work on windows
#.\v.exe -o hi.js examples/hello_v_js.v
#node hi.js
# - name: Test v binaries
# run: ./v build-vbinaries
- name: Test v->js
run: ./v -o hi.js examples/hello_v_js.v && node hi.js
- name: Test v binaries
run: ./v build-vbinaries
- name: Build examples
run: ./v build-examples
- name: v2 self compilation
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
windows-tcc:
runs-on: windows-2019
@@ -641,6 +732,9 @@ jobs:
VFLAGS: -cc tcc -no-retry-compilation
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Build with make.bat -tcc
run: |
.\make.bat -tcc
@@ -651,6 +745,9 @@ jobs:
.\v.exe setup-freetype
.\.github\workflows\windows-install-sqlite.bat
## .\.github\workflows\windows-install-sdl.bat
- name: v doctor
run: |
./v doctor
- name: Verify `v test` works
run: |
.\v.exe cmd/tools/test_if_v_test_system_works.v
@@ -661,11 +758,12 @@ jobs:
# - name: Test
# run: |
# .\v.exe -silent test-all
## v.js dosent work on windows
#.\v.exe -o hi.js examples/hello_v_js.v
#node hi.js
# - name: Test v binaries
# run: ./v build-vbinaries
- name: Test v->js
run: ./v -o hi.js examples/hello_v_js.v && node hi.js
- name: Test v binaries
run: ./v build-vbinaries
- name: Build examples
run: ./v build-examples
- name: v2 self compilation
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
@@ -760,61 +858,6 @@ jobs:
../v -autofree .
cd ..
websocket_autobahn:
name: Autobahn integrations tests
runs-on: ubuntu-20.04
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run autobahn services
run: docker-compose -f ${{github.workspace}}/vlib/x/websocket/tests/autobahn/docker-compose.yml up -d
- name: Build client test
run: docker exec autobahn_client "/src/v" "/src/vlib/x/websocket/tests/autobahn/autobahn_client.v"
- name: Run client test
run: docker exec autobahn_client "/src/vlib/x/websocket/tests/autobahn/autobahn_client"
- name: Build client wss test
run: docker exec autobahn_client "/src/v" "/src/vlib/x/websocket/tests/autobahn/autobahn_client_wss.v"
- name: Run client wss test
run: docker exec autobahn_client "/src/vlib/x/websocket/tests/autobahn/autobahn_client_wss"
- name: Run server test
run: docker exec autobahn_server "wstest" "-m" "fuzzingclient" "-s" "/config/fuzzingclient.json"
- name: Copy reports
run: docker cp autobahn_server:/reports ${{github.workspace}}/reports
- name: Copy reports wss
run: docker cp autobahn_server_wss:/reports ${{github.workspace}}/reports_wss
- name: Test success
run: docker exec autobahn_server "python" "/check_results.py"
- name: Test success WSS
run: docker exec autobahn_server_wss "python" "/check_results.py"
- name: Publish all reports
uses: actions/upload-artifact@v2
with:
name: full report
path: ${{github.workspace}}/reports
- name: Publish report client
uses: actions/upload-artifact@v2
with:
name: client
path: ${{github.workspace}}/reports/clients/index.html
- name: Publish report server
uses: actions/upload-artifact@v2
with:
name: server
path: ${{github.workspace}}/reports/servers/index.html
- name: Publish all reports WSS
uses: actions/upload-artifact@v2
with:
name: full report wss
path: ${{github.workspace}}/reports_wss
- name: Publish report client wss
uses: actions/upload-artifact@v2
with:
name: client wss
path: ${{github.workspace}}/reports_wss/clients/index.html
parser-silent:
name: Parser silent mode
runs-on: ubuntu-20.04
@@ -831,7 +874,7 @@ jobs:
./v test-parser -S examples/cli.v
./v test-parser -S examples/json.v
./v test-parser -S examples/vmod.v
./v test-parser -S examples/regex_example.v
./v test-parser -S examples/regex/regex_example.v
./v test-parser -S examples/2048/2048.v
parser-silent-fuzzing:
@@ -854,7 +897,7 @@ jobs:
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/cli.v > examples/cli_fuzz.v
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/json.v > examples/json_fuzz.v
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/vmod.v > examples/vmod_fuzz.v
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/regex_example.v > examples/regex_example_fuzz.v
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/regex/regex_example.v > examples/regex_example_fuzz.v
zzuf -R '\x00-\x20\x7f-\xff' -r0.01 < examples/2048/2048.v > examples/2048/2048_fuzz.v
./v test-parser -S examples/hello_world_fuzz.v
./v test-parser -S examples/hanoi_fuzz.v

View File

@@ -13,6 +13,6 @@ jobs:
- name: Build V
run: make
- name: Check markdown line length & code examples
run: ./v run cmd/tools/check-md.v -hide-warnings -all
run: ./v check-md -hide-warnings .
## NB: -hide-warnings is used here, so that the output is less noisy,
## thus real errors are easier to spot.

View File

@@ -0,0 +1,45 @@
name: Sokol Shader Examples
on:
push:
branches:
- master
paths-ignore:
- "**.md"
pull_request:
branches:
- master
paths-ignore:
- "**.md"
jobs:
sokol-shaders-can-be-compiled:
runs-on: ubuntu-20.04
timeout-minutes: 30
env:
VFLAGS: -cc tcc -no-retry-compilation
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: |
sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list; sudo apt-get update;
sudo apt-get install --quiet -y libglfw3 libglfw3-dev libfreetype6-dev libxi-dev libxcursor-dev libasound2-dev xfonts-75dpi xfonts-base
- name: Build v
run: |
echo $VFLAGS
make -j4
./v -cg -cflags -Werror -o v cmd/v
- name: Shader examples can be build
run: |
wget https://github.com/floooh/sokol-tools-bin/archive/pre-feb2021-api-changes.tar.gz
tar -xf pre-feb2021-api-changes.tar.gz
for f in examples/sokol/02_cubes_glsl/cube_glsl \
examples/sokol/03_march_tracing_glsl/rt_glsl \
examples/sokol/04_multi_shader_glsl/rt_glsl_puppy \
examples/sokol/04_multi_shader_glsl/rt_glsl_march \
examples/sokol/05_instancing_glsl/rt_glsl_instancing \
; do \
echo "compiling shader $f.glsl ..."; \
sokol-tools-bin-pre-feb2021-api-changes/bin/linux/sokol-shdc --input $f.glsl --output $f.h --slang glsl330 ; \
done
for vfile in examples/sokol/0?*/*.v; do echo "compiling $vfile ..."; ./v $vfile ; done

86
.github/workflows/websockets.yml vendored Normal file
View File

@@ -0,0 +1,86 @@
name: Websockets CI
on:
push:
paths-ignore:
- "**.md"
pull_request:
paths-ignore:
- "**.md"
jobs:
websocket_tests:
runs-on: ubuntu-20.04
timeout-minutes: 30
env:
VFLAGS: -cc tcc -no-retry-compilation
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: sudo apt-get install --quiet -y libssl-dev
- name: Build v
run: |
echo $VFLAGS
sudo ln -s $PWD/thirdparty/tcc/tcc.exe /usr/local/bin/tcc ## TODO: remove
make -j4
./v -g -o v cmd/v
- name: v doctor
run: ./v doctor
- name: Run websockets tests
run: ./v -g test vlib/x/websocket/
autobahn_tests:
name: Autobahn integrations tests
runs-on: ubuntu-20.04
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run autobahn services
run: docker-compose -f ${{github.workspace}}/vlib/x/websocket/tests/autobahn/docker-compose.yml up -d
- name: Build client test
run: docker exec autobahn_client "/src/v" "/src/vlib/x/websocket/tests/autobahn/autobahn_client.v"
- name: Run client test
run: docker exec autobahn_client "/src/vlib/x/websocket/tests/autobahn/autobahn_client"
- name: Build client wss test
run: docker exec autobahn_client "/src/v" "/src/vlib/x/websocket/tests/autobahn/autobahn_client_wss.v"
- name: Run client wss test
run: docker exec autobahn_client "/src/vlib/x/websocket/tests/autobahn/autobahn_client_wss"
- name: Run server test
run: docker exec autobahn_server "wstest" "-m" "fuzzingclient" "-s" "/config/fuzzingclient.json"
- name: Copy reports
run: docker cp autobahn_server:/reports ${{github.workspace}}/reports
- name: Copy reports wss
run: docker cp autobahn_server_wss:/reports ${{github.workspace}}/reports_wss
- name: Test success
run: docker exec autobahn_server "python" "/check_results.py"
- name: Test success WSS
run: docker exec autobahn_server_wss "python" "/check_results.py"
- name: Publish all reports
uses: actions/upload-artifact@v2
with:
name: full report
path: ${{github.workspace}}/reports
- name: Publish report client
uses: actions/upload-artifact@v2
with:
name: client
path: ${{github.workspace}}/reports/clients/index.html
- name: Publish report server
uses: actions/upload-artifact@v2
with:
name: server
path: ${{github.workspace}}/reports/servers/index.html
- name: Publish all reports WSS
uses: actions/upload-artifact@v2
with:
name: full report wss
path: ${{github.workspace}}/reports_wss
- name: Publish report client wss
uses: actions/upload-artifact@v2
with:
name: client wss
path: ${{github.workspace}}/reports_wss/clients/index.html

View File

@@ -26,7 +26,8 @@
from local variables.
- `__offsetof` for low level needs (works like `offsetof` in C).
- vfmt now preserves empty lines, like gofmt.
- Support for compile time environment variables via `$env('ENV_VAR')`.
- Support for compile time environment variables via `$env('ENV_VAR')`.
- Allow method declaration of `==` and `<` operators and auto generate `!=`, `>`, `<=` and `>=`.
## V 0.2.1
*30 Dec 2020*

View File

@@ -21,7 +21,7 @@ download the C version of the compiler and rebuild it from scratch.
The architecture of the compiler is very simple and has three distinct steps:
Parse/generate AST (`v.parser`) => Check types (`v.checker`)
Parse/generate AST (`v.parser`) => Check types (`v.checker`)
=> Generate C/JavaScript/machine code (`v.gen`)
@@ -53,7 +53,7 @@ for objects by name, register new objects, modify types' fields, etc.
the types are correct. Unresolved types are resolved, type information is added
to the AST.
7. `v/gen` C backend. It simply walks the AST and generates C code that can be
7. `v/gen/c` C backend. It simply walks the AST and generates C code that can be
compiled with Clang, GCC, Visual Studio, and TCC.
8. `json.v` defines the json code generation. This file will be removed once V
@@ -171,11 +171,11 @@ their status.
V allows you to pass custom flags using `-d my_flag` that can then be checked
at compile time (see the documentation about
[compile-time if](https://github.com/vlang/v/blob/master/doc/docs.md#compile-time-if)).
There are numerous flags that can be passed when building the compiler
with `v self` or when creating a copy of the compiler, that will help
There are numerous flags that can be passed when building the compiler
with `v self` or when creating a copy of the compiler, that will help
you when debugging.
Beware that the flags must be passed when building the compiler,
Beware that the flags must be passed when building the compiler,
not the program, so do for example: `v -d time_parsing cmd/v` or
`v -d trace_checker self`.
Some flags can make the compiler very verbose, so it is recommended

View File

@@ -1,6 +1,6 @@
<div align="center">
<p>
<img width="80" src="https://raw.githubusercontent.com/donnisnoni95/v-logo/master/dist/v-logo.svg?sanitize=true">
<img width="80" src="https://raw.githubusercontent.com/vlang/v-logo/master/dist/v-logo.svg?sanitize=true">
</p>
<h1>The V Programming Language</h1>
@@ -244,6 +244,18 @@ Hello from V.js
```
-->
## Android graphical apps
With V's `vab` tool, building V UI and graphical apps for Android can become as easy as:
```
./vab /path/to/v/examples/2048
```
[https://github.com/vlang/vab](https://github.com/vlang/vab).
<img src="https://user-images.githubusercontent.com/768942/107622846-c13f3900-6c58-11eb-8a66-55db12979b73.png">
## Developing web applications
Check out the [Building a simple web blog](https://github.com/vlang/v/blob/master/tutorials/building-a-simple-web-blog-with-vweb.md)

View File

@@ -1,15 +1,15 @@
# Automated tests
TLDR: run `v test-all` locally, after making your changes,
TLDR: run `v test-all` locally, after making your changes,
and before submitting PRs.
## Notes
In the `v` repo there are several different tests. The main types are:
* `_test.v` tests - check that `test_` functions succeed. These can be
* `_test.v` tests - check that `test_` functions succeed. These can be
run per directory or individually.
* `.out` tests - run a `.vv` file and check the output matches the
contents of the `.out` file with the same base name. This is
* `.out` tests - run a `.vv` file and check the output matches the
contents of the `.out` file with the same base name. This is
particularly useful for checking that errors are printed.
Tip: use `v -cc tcc` when compiling tests for speed.
@@ -46,7 +46,7 @@ This is not required.
Test all files in the current directory are formatted.
* `v run cmd/tools/check-md.v -hide-warnings -all`
* `v check-md -hide-warnings .`
Ensure that all .md files in the project are formatted properly,
and that the V code block examples in them can be compiled/formatted too.
@@ -75,7 +75,7 @@ This runs tests for:
## `v test-all`
Test and build *everything*. Usefull to verify *locally*, that the CI will
most likely pass. Slowest, but most comprehensive.
most likely pass. Slowest, but most comprehensive.
It works, by running these in succession:
* `v test-cleancode`
@@ -83,5 +83,5 @@ It works, by running these in succession:
* `v test-fmt`
* `v build-tools`
* `v build-examples`
* `v run cmd/tools/check-md.v -hide-warnings -all`
* `v check-md -hide-warnings .`
* `v install nedpals.args`

View File

@@ -95,7 +95,7 @@ fn (app App) gen_api_for_module_in_os(mod_name string, os_name string) string {
}
mpath := os.join_path('vlib', mod_name.replace('.', '/'))
tmpname := '/tmp/${mod_name}_${os_name}.c'
prefs, _ := pref.parse_args(['-os', os_name, '-o', tmpname, '-shared', mpath])
prefs, _ := pref.parse_args([], ['-os', os_name, '-o', tmpname, '-shared', mpath])
mut b := builder.new_builder(prefs)
b.compile_c()
mut res := []string{}

View File

@@ -12,66 +12,46 @@ fn main() {
println('fast.html generator needs to be located in `v/cmd/tools/fast`')
}
println('fast.html generator\n')
// Fetch the last commit's hash
println('Fetching updates...')
ret := os.system('$vdir/v up')
if ret != 0 {
println('failed to update V')
return
}
mut commit_hash := exec('git rev-parse HEAD')
commit_hash = commit_hash[..8]
if os.exists('last_commit.txt') {
last_commit := os.read_file('last_commit.txt') ?
if last_commit.trim_space() == commit_hash.trim_space() {
println('No new commits to benchmark. Commit $commit_hash has already been processed.')
return
}
commit_hash = last_commit.trim_space()
}
// Fetch the last commit's hash
commit := exec('git rev-parse HEAD')[..8]
if !os.exists('table.html') {
os.create('table.html') ?
}
mut table := os.read_file('table.html') ?
/*
// Do nothing if it's already been processed.
if table.contains(commit_hash) {
println('Commit $commit_hash has already been processed')
if table.contains('>$commit<') {
println('nothing to benchmark')
exit(1)
return
}
*/
last_commits := exec('git log --pretty=format:"%h" -n 50').split('\n')
// Fetch all unprocessed commits (commits after the last processed commit)
mut commits := []string{}
println('!last_commit="$commit_hash"')
for i, c in last_commits {
if c == commit_hash {
commits = last_commits[..i].reverse()
break
}
}
println(last_commits)
println('Commits to benchmark:')
println(commits)
for i, commit in commits {
message := exec('git log --pretty=format:"%s" -n1 $commit')
println('\n${i + 1}/$commits.len Benchmarking commit $commit "$message"')
// Build an optimized V
println('Checking out ${commit}...')
exec('git checkout $commit')
println(' Building vprod...')
exec('v -o $vdir/vprod -prod $vdir/cmd/v')
diff1 := measure('$vdir/vprod -cc clang -o v.c $vdir/cmd/v', 'v.c')
diff2 := measure('$vdir/vprod -cc clang -o v2 $vdir/cmd/v', 'v2')
diff3 := measure('$vdir/vprod -x64 $vdir/cmd/tools/1mil.v', 'x64 1mil')
diff4 := measure('$vdir/vprod -cc clang $vdir/examples/hello_world.v', 'hello.v')
// println('Building V took ${diff}ms')
commit_date := exec('git log -n1 --pretty="format:%at" $commit')
date := time.unix(commit_date.int())
mut out := os.create('table.html') ?
// Place the new row on top
table =
'<tr>
// for i, commit in commits {
message := exec('git log --pretty=format:"%s" -n1 $commit')
// println('\n${i + 1}/$commits.len Benchmarking commit $commit "$message"')
println('\nBenchmarking commit $commit "$message"')
// Build an optimized V
// println('Checking out ${commit}...')
// exec('git checkout $commit')
println(' Building vprod...')
exec('v -o $vdir/vprod -prod $vdir/cmd/v')
diff1 := measure('$vdir/vprod -cc clang -o v.c -show-timings $vdir/cmd/v', 'v.c')
diff2 := measure('$vdir/vprod -cc clang -o v2 $vdir/cmd/v', 'v2')
diff3 := measure('$vdir/vprod -x64 $vdir/cmd/tools/1mil.v', 'x64 1mil')
diff4 := measure('$vdir/vprod -cc clang $vdir/examples/hello_world.v', 'hello.v')
vc_size := os.file_size('v.c') / 1000
// parse/check/cgen
parse, check, cgen := measure_steps(vdir)
// println('Building V took ${diff}ms')
commit_date := exec('git log -n1 --pretty="format:%at" $commit')
date := time.unix(commit_date.int())
mut out := os.create('table.html') ?
// Place the new row on top
table =
'<tr>
<td>$date.format()</td>
<td><a target=_blank href="https://github.com/vlang/v/commit/$commit">$commit</a></td>
<td>$message</td>
@@ -79,21 +59,25 @@ fn main() {
<td>${diff2}ms</td>
<td>${diff3}ms</td>
<td>${diff4}ms</td>
<td>$vc_size KB</td>
<td>${parse}ms</td>
<td>${check}ms</td>
<td>${cgen}ms</td>
</tr>\n' +
table.trim_space()
out.writeln(table) ?
out.close()
// Regenerate index.html
header := os.read_file('header.html') ?
footer := os.read_file('footer.html') ?
mut res := os.create('index.html') ?
res.writeln(header) ?
res.writeln(table) ?
res.writeln(footer) ?
res.close()
}
exec('git checkout master')
os.write_file('last_commit.txt', commits[commits.len - 1]) ?
table.trim_space()
out.writeln(table) ?
out.close()
// Regenerate index.html
header := os.read_file('header.html') ?
footer := os.read_file('footer.html') ?
mut res := os.create('index.html') ?
res.writeln(header) ?
res.writeln(table) ?
res.writeln(footer) ?
res.close()
//}
// exec('git checkout master')
// os.write_file('last_commit.txt', commits[commits.len - 1]) ?
}
fn exec(s string) string {
@@ -125,3 +109,15 @@ fn measure(cmd string, description string) int {
}
return int(sum / 3)
}
fn measure_steps(vdir string) (int, int, int) {
resp := os.exec('$vdir/vprod -o v.c -show-timings $vdir/cmd/v') or { panic(err) }
lines := resp.output.split_into_lines()
if lines.len != 3 {
return 0, 0, 0
}
parse := lines[0].before('.').int()
check := lines[1].before('.').int()
cgen := lines[2].before('.').int()
return parse, check, cgen
}

41
cmd/tools/fast/fast_job.v Normal file
View File

@@ -0,0 +1,41 @@
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
import os
import time
// A job that runs in the background, checks for repo updates,
// runs fast.v, pushes the HTML result to the fast.vlang.io GH pages repo.
fn main() {
println(time.now())
if !os.exists('website') {
println('cloning the website repo...')
os.system('git clone git@github.com:/vlang/website.git')
}
if !os.exists('fast') {
println('"fast" binary (built with `v fast.v`) was not found')
return
}
for {
os.exec('git pull --rebase') or {
println('failed to git pull. uncommitted changes?')
return
}
// println('running fast')
resp := os.exec('./fast') or {
println(err)
return
}
if resp.exit_code != 0 {
println('resp != 0, skipping')
} else {
os.chdir('website')
os.exec('git checkout gh-pages') ?
os.cp('../index.html', 'index.html') ?
os.system('git commit -am "update benchmark"')
os.system('git push origin gh-pages')
os.chdir('..')
}
time.wait(60 * time.second)
}
}

View File

@@ -8,6 +8,9 @@
*, body {
font-family: Menlo, Monospace, 'Courier New';
}
table {
width: 2000px;
}
table, td {
border-collapse: collapse;
border: 1px solid #dfdfdf;
@@ -52,4 +55,8 @@ Source code: <a target=blank href='https://github.com/vlang/v/blob/master/cmd/to
<td style='width:120px'>v -o v</td>
<td style='width:130px'>v -x64 1mil.v</td>
<td style='width:120px'>v hello.v</td>
<td style='width:120px'>v.c size</td>
<td style='width:120px'>parse</td>
<td style='width:120px'>check</td>
<td style='width:120px'>cgen</td>
</tr>

View File

@@ -90,7 +90,7 @@ mut:
struct WebhookServer {
vweb.Context
mut:
gen_vc &GenVC
gen_vc &GenVC = 0 // initialized in init_once
}
// storage for flag options

View File

@@ -4,7 +4,7 @@ import os
import time
import term
import benchmark
import sync
import sync.pool
import v.pref
import v.util.vtest
@@ -124,6 +124,17 @@ pub fn new_test_session(_vargs string) TestSession {
skip_files << 'examples/websocket/ping.v' // requires OpenSSL
skip_files << 'examples/websocket/client-server/client.v' // requires OpenSSL
skip_files << 'examples/websocket/client-server/server.v' // requires OpenSSL
$if tinyc {
skip_files << 'examples/database/orm.v' // try fix it
}
}
if testing.github_job != 'sokol-shaders-can-be-compiled' {
// These examples need .h files that are produced from the supplied .glsl files,
// using by the shader compiler tools in https://github.com/floooh/sokol-tools-bin/archive/pre-feb2021-api-changes.tar.gz
skip_files << 'examples/sokol/02_cubes_glsl/cube_glsl.v'
skip_files << 'examples/sokol/03_march_tracing_glsl/rt_glsl.v'
skip_files << 'examples/sokol/04_multi_shader_glsl/rt_glsl.v'
skip_files << 'examples/sokol/05_instancing_glsl/rt_glsl.v'
}
if testing.github_job != 'ubuntu-tcc' {
skip_files << 'examples/wkhtmltopdf.v' // needs installation of wkhtmltopdf from https://github.com/wkhtmltopdf/packaging/releases
@@ -195,7 +206,7 @@ pub fn (mut ts TestSession) test() {
remaining_files = vtest.filter_vtest_only(remaining_files, fix_slashes: false)
ts.files = remaining_files
ts.benchmark.set_total_expected_steps(remaining_files.len)
mut pool_of_test_runners := sync.new_pool_processor(callback: worker_trunner)
mut pool_of_test_runners := pool.new_pool_processor(callback: worker_trunner)
// for handling messages across threads
ts.nmessages = chan LogMessage{cap: 10000}
ts.nprint_ended = chan int{cap: 0}
@@ -215,7 +226,7 @@ pub fn (mut ts TestSession) test() {
}
}
fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
mut ts := &TestSession(p.get_shared_context())
tmpd := ts.vtmp_dir
show_stats := '-stats' in ts.vargs.split(' ')
@@ -227,7 +238,7 @@ fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
p.set_thread_context(idx, tls_bench)
}
tls_bench.no_cstep = true
dot_relative_file := p.get_string_item(idx)
dot_relative_file := p.get_item<string>(idx)
mut relative_file := dot_relative_file.replace('./', '')
if ts.root_relative {
relative_file = relative_file.replace(ts.vroot + os.path_separator, '')
@@ -236,8 +247,11 @@ fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
// Ensure that the generated binaries will be stored in the temporary folder.
// Remove them after a test passes/fails.
fname := os.file_name(file)
generated_binary_fname := if os.user_os() == 'windows' { fname.replace('.v', '.exe') } else { fname.replace('.v',
'') }
generated_binary_fname := if os.user_os() == 'windows' {
fname.replace('.v', '.exe')
} else {
fname.replace('.v', '')
}
generated_binary_fpath := os.join_path(tmpd, generated_binary_fname)
if os.exists(generated_binary_fpath) {
if ts.rm_binaries {
@@ -255,7 +269,7 @@ fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
ts.benchmark.skip()
tls_bench.skip()
ts.append_message(.skip, tls_bench.step_message_skip(relative_file))
return sync.no_result
return pool.no_result
}
if show_stats {
ts.append_message(.ok, term.h_divider('-'))
@@ -267,7 +281,7 @@ fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
ts.failed = true
ts.benchmark.fail()
tls_bench.fail()
return sync.no_result
return pool.no_result
}
} else {
if testing.show_start {
@@ -278,7 +292,7 @@ fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
ts.benchmark.fail()
tls_bench.fail()
ts.append_message(.fail, tls_bench.step_message_fail(relative_file))
return sync.no_result
return pool.no_result
}
if r.exit_code != 0 {
ts.failed = true
@@ -297,7 +311,7 @@ fn worker_trunner(mut p sync.PoolProcessor, idx int, thread_id int) voidptr {
os.rm(generated_binary_fpath) or { panic(err) }
}
}
return sync.no_result
return pool.no_result
}
pub fn vlib_should_be_present(parent_dir string) {
@@ -339,8 +353,8 @@ pub fn prepare_test_session(zargs string, folder string, oskipped []string, main
continue
}
$if windows {
// skip pico example on windows
if f.ends_with('examples\\pico\\pico.v') {
// skip pico and process/command examples on windows
if f.ends_with('examples\\pico\\pico.v') || f.ends_with('examples\\process\\command.v') {
continue
}
}

View File

@@ -256,7 +256,7 @@ fn (mut context Context) run() {
summary[k] = s
}
// merge current raw results to the previous ones
old_oms := context.results[icmd].oms
old_oms := context.results[icmd].oms.move()
mut new_oms := map[string][]int{}
for k, v in m {
if old_oms[k].len == 0 {
@@ -266,7 +266,7 @@ fn (mut context Context) run() {
new_oms[k] << v
}
}
context.results[icmd].oms = new_oms
context.results[icmd].oms = new_oms.move()
// println('')
}
}
@@ -276,7 +276,7 @@ fn (mut context Context) run() {
for k, v in context.results[icmd].oms {
new_full_summary[k] = new_aints(v, context.nmins, context.nmaxs)
}
context.results[icmd].summary = new_full_summary
context.results[icmd].summary = new_full_summary.move()
}
}

View File

@@ -44,7 +44,7 @@ fn (mut ctx Context) println(s string) {
fn do_timeout(c &Context) {
mut ctx := c
time.sleep_ms(ctx.timeout_ms)
time.wait(ctx.timeout_ms * time.millisecond)
exit(ctx.exitcode)
}
@@ -53,19 +53,20 @@ fn main() {
args := os.args[1..]
if '-h' in args || '--help' in args {
println("Usage:
test_os_process [-v] [-h] [-target stderr/stdout/both/alternate] [-exitcode 0] [-timeout_ms 1000] [-period_ms 100]
test_os_process [-v] [-h] [-target stderr/stdout/both/alternate] [-exitcode 0] [-timeout_ms 200] [-period_ms 50]
Prints lines periodically (-period_ms), to stdout/stderr (-target).
After a while (-timeout_ms), exit with (-exitcode).
This program is useful for platform independent testing
of child process/standart input/output control.
It is used in V\'s `os` module tests.
It is used in V's `os` module tests.
")
return
}
ctx.is_verbose = '-v' in args
ctx.target = s2target(cmdline.option(args, '-target', 'both'))
ctx.exitcode = cmdline.option(args, '-exitcode', '0').int()
ctx.timeout_ms = cmdline.option(args, '-timeout_ms', '1000').int()
ctx.period_ms = cmdline.option(args, '-period_ms', '100').int()
ctx.timeout_ms = cmdline.option(args, '-timeout_ms', '200').int()
ctx.period_ms = cmdline.option(args, '-period_ms', '50').int()
if ctx.target == .alternate {
ctx.omode = .stdout
}
@@ -75,7 +76,7 @@ fn main() {
go do_timeout(&ctx)
for i := 1; true; i++ {
ctx.println('$i')
time.sleep_ms(ctx.period_ms)
time.wait(ctx.period_ms * time.millisecond)
}
time.sleep(100000)
time.wait(100 * time.second)
}

View File

@@ -1,9 +1,13 @@
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module main
import os
import os.cmdline
import rand
import term
import vhelp
import v.pref
const (
@@ -11,35 +15,19 @@ const (
term_colors = term.can_show_color_on_stderr()
is_all = '-all' in os.args
hide_warnings = '-hide-warnings' in os.args
non_option_args = cmdline.only_non_options(os.args[1..])
non_option_args = cmdline.only_non_options(os.args[2..])
)
fn wprintln(s string) {
if !hide_warnings {
println(s)
}
}
fn main() {
if os.args.len == 1 {
println('Usage: checks the passed markdown files for correct ```v ``` code blocks,
and for other style violations. like too long lines/links etc...
a) `v run cmd/tools/check-md.v -all` - will check *all* .md files in the folders.
b) `v run cmd/tools/check-md.v doc/docs.md` - will only check a single file.
c) `v run cmd/tools/check-md.v -hide-warnings file.md` - same, but will not print warnings, only errors.
NB: There are several special keywords, which you can put after the code fences for v.
These are:
compile - default, you do not need to specify it. cmd/tools/check-md.v compile the example.
ignore - ignore the example, useful for examples that just use the syntax highlighting
failcompile - known failing compilation. Useful for examples demonstrating compiler errors.
oksyntax - it should parse, it may not compile. Useful for partial examples.
badsyntax - known bad syntax, it should not even parse
wip - like ignore; a planned feature; easy to search.
')
if non_option_args.len == 0 || '-help' in os.args {
vhelp.show_topic('check-md')
exit(0)
}
files_paths := if is_all { md_file_paths() } else { non_option_args }
if is_all {
println('´-all´ flag is deprecated. Please use ´v check-md .´ instead.')
exit(1)
}
mut files_paths := non_option_args.clone()
mut warnings := 0
mut errors := 0
mut oks := 0
@@ -47,7 +35,12 @@ These are:
if term_colors {
os.setenv('VCOLORS', 'always', true)
}
for file_path in files_paths {
for i := 0; i < files_paths.len; i++ {
file_path := files_paths[i]
if os.is_dir(file_path) {
files_paths << md_file_paths(file_path)
continue
}
real_path := os.real_path(file_path)
lines := os.read_lines(real_path) or {
println('"$file_path" does not exist')
@@ -57,31 +50,31 @@ These are:
mut mdfile := MDFile{
path: file_path
}
for i, line in lines {
for j, line in lines {
if line.len > too_long_line_length {
if mdfile.state == .vexample {
wprintln(wline(file_path, i, line.len, 'long V example line'))
wprintln(wline(file_path, j, line.len, 'long V example line'))
wprintln(line)
warnings++
} else if mdfile.state == .codeblock {
wprintln(wline(file_path, i, line.len, 'long code block line'))
wprintln(wline(file_path, j, line.len, 'long code block line'))
wprintln(line)
warnings++
} else if line.starts_with('|') {
wprintln(wline(file_path, i, line.len, 'long table'))
wprintln(wline(file_path, j, line.len, 'long table'))
wprintln(line)
warnings++
} else if line.contains('https') {
wprintln(wline(file_path, i, line.len, 'long link'))
wprintln(wline(file_path, j, line.len, 'long link'))
wprintln(line)
warnings++
} else {
eprintln(eline(file_path, i, line.len, 'line too long'))
eprintln(eline(file_path, j, line.len, 'line too long'))
eprintln(line)
errors++
}
}
mdfile.parse_line(i, line)
mdfile.parse_line(j, line)
}
all_md_files << mdfile
}
@@ -90,7 +83,6 @@ These are:
errors += new_errors
oks += new_oks
}
// println('all_md_files: $all_md_files')
if warnings > 0 || errors > 0 || oks > 0 {
println('\nWarnings: $warnings | Errors: $errors | OKs: $oks')
}
@@ -99,14 +91,11 @@ These are:
}
}
fn md_file_paths() []string {
fn md_file_paths(dir string) []string {
mut files_to_check := []string{}
md_files := os.walk_ext('.', '.md')
md_files := os.walk_ext(dir, '.md')
for file in md_files {
if file.starts_with('./thirdparty') {
continue
}
if file.contains('CHANGELOG') {
if file.contains_any_substr(['/thirdparty/', 'CHANGELOG']) {
continue
}
files_to_check << file
@@ -114,6 +103,12 @@ fn md_file_paths() []string {
return files_to_check
}
fn wprintln(s string) {
if !hide_warnings {
println(s)
}
}
fn ftext(s string, cb fn (string) string) string {
if term_colors {
return cb(s)
@@ -175,6 +170,8 @@ fn (mut f MDFile) parse_line(lnumber int, line string) {
mut command := line.replace('```v', '').trim_space()
if command == '' {
command = default_command
} else if command == 'nofmt' {
command += ' $default_command'
}
f.current = VCodeExample{
sline: lnumber

View File

@@ -130,7 +130,7 @@ fn (vd VDoc) render_search_index(out Output) {
}
fn (mut vd VDoc) render_static_html(out Output) {
vd.assets = {
vd.assets = map{
'doc_css': vd.get_resource(css_js_assets[0], out)
'normalize_css': vd.get_resource(css_js_assets[1], out)
'doc_js': vd.get_resource(css_js_assets[2], out)
@@ -292,8 +292,10 @@ fn (vd VDoc) gen_html(d doc.Doc) string {
}
modules_toc_str := modules_toc.str()
symbols_toc_str := symbols_toc.str()
modules_toc.free()
symbols_toc.free()
unsafe {
modules_toc.free()
symbols_toc.free()
}
return html_content.replace('{{ title }}', d.head.name).replace('{{ head_name }}',
header_name).replace('{{ version }}', version).replace('{{ light_icon }}', vd.assets['light_icon']).replace('{{ dark_icon }}',
vd.assets['dark_icon']).replace('{{ menu_icon }}', vd.assets['menu_icon']).replace('{{ head_assets }}',
@@ -310,7 +312,7 @@ fn (vd VDoc) gen_html(d doc.Doc) string {
} else {
symbols_toc_str
}).replace('{{ contents }}', contents.str()).replace('{{ right_content }}', if cfg.is_multi
&& vd.docs.len > 1&& d.head.name != 'README' {
&& vd.docs.len > 1 && d.head.name != 'README' {
'<div class="doc-toc"><ul>' + symbols_toc_str + '</ul></div>'
} else {
''
@@ -353,11 +355,7 @@ fn html_highlight(code string, tb &table.Table) string {
} else {
tok.lit
}
return if typ in [.unone, .name] {
lit
} else {
'<span class="token $typ">$lit</span>'
}
return if typ in [.unone, .name] { lit } else { '<span class="token $typ">$lit</span>' }
}
mut s := scanner.new_scanner(code, .parse_comments, &pref.Preferences{})
mut tok := s.scan()
@@ -401,7 +399,7 @@ fn html_highlight(code string, tb &table.Table) string {
if token.is_key(tok.lit) || token.is_decl(tok.kind) {
tok_typ = .keyword
} else if tok.kind == .decl_assign || tok.kind.is_assign() || tok.is_unary()
|| tok.kind.is_relational()|| tok.kind.is_infix() {
|| tok.kind.is_relational() || tok.kind.is_infix() {
tok_typ = .operator
}
}
@@ -475,7 +473,7 @@ fn doc_node_html(dn doc.DocNode, link string, head bool, include_examples bool,
dnw.writeln('</section>')
dnw_str := dnw.str()
defer {
dnw.free()
unsafe { dnw.free() }
}
return dnw_str
}
@@ -517,6 +515,9 @@ fn write_toc(dn doc.DocNode, mut toc strings.Builder) {
}
}
if is_module_readme(dn) {
if dn.comments.len == 0 || (dn.comments.len > 0 && dn.comments[0].text.len == 0) {
return
}
toc.write('<li class="open"><a href="#readme_$toc_slug">README</a>')
} else if dn.name != 'Constants' {
toc.write('<li class="open"><a href="#$toc_slug">$dn.kind $dn.name</a>')

View File

@@ -31,7 +31,7 @@ fn (vd VDoc) gen_markdown(d doc.Doc, with_toc bool) string {
fn (vd VDoc) write_markdown_content(contents []doc.DocNode, mut cw strings.Builder, mut hw strings.Builder, indent int, with_toc bool) {
for cn in contents {
if with_toc && cn.name.len > 0 {
hw.writeln(' '.repeat(2 * indent) + '- [#$cn.name](${slug(cn.name)})')
hw.writeln(' '.repeat(2 * indent) + '- [${slug(cn.name)}](#$cn.name)')
cw.writeln('## $cn.name')
}
if cn.content.len > 0 {

View File

@@ -593,7 +593,7 @@ pre {
.doc-content {
font-size: 0.95rem;
flex: 1;
padding: 1rem 2rem;
padding: 0rem 2rem 1rem 2rem;
}
.doc-toc {
position: relative;

View File

@@ -8,19 +8,6 @@ fn slug(title string) string {
return title.replace(' ', '-')
}
[inline]
fn open_url(url string) {
$if windows {
os.system('start $url')
}
$if macos {
os.system('open $url')
}
$if linux {
os.system('xdg-open $url')
}
}
fn escape(str string) string {
return str.replace_each(['"', '\\"', '\r\n', '\\n', '\n', '\\n', '\t', '\\t'])
}

View File

@@ -366,8 +366,8 @@ fn (mut vd VDoc) generate_docs_from_file() {
vd.render_static_html(out)
}
vd.render_parallel(out)
println('Creating search index...')
if out.typ == .html {
println('Creating search index...')
vd.collect_search_index(out)
vd.render_search_index(out)
// move favicons to target directory

View File

@@ -35,13 +35,12 @@ fn (mut a App) collect_info() {
})
}
if os_kind == 'linux' {
info := a.cpu_info()
mut cpu_details := ''
if cpu_details == '' {
cpu_details = info['model name']
cpu_details = a.cpu_info('model name')
}
if cpu_details == '' {
cpu_details = info['hardware']
cpu_details = a.cpu_info('hardware')
}
if cpu_details == '' {
cpu_details = os.uname().machine
@@ -61,8 +60,7 @@ fn (mut a App) collect_info() {
})
if os_kind == 'linux' {
os_details = a.get_linux_os_name()
info := a.cpu_info()
if 'hypervisor' in info['flags'] {
if 'hypervisor' in a.cpu_info('flags') {
if 'microsoft' in wsl_check {
// WSL 2 is a Managed VM and Full Linux Kernel
// See https://docs.microsoft.com/en-us/windows/wsl/compare-versions
@@ -233,16 +231,15 @@ fn (mut a App) get_linux_os_name() string {
return os_details
}
fn (mut a App) cpu_info() map[string]string {
fn (mut a App) cpu_info(key string) string {
if a.cached_cpuinfo.len > 0 {
return a.cached_cpuinfo
return a.cached_cpuinfo[key]
}
info := os.exec('cat /proc/cpuinfo') or {
return a.cached_cpuinfo
return a.cached_cpuinfo[key]
}
vals := a.parse(info.output, ':')
a.cached_cpuinfo = vals
return vals
a.cached_cpuinfo = a.parse(info.output, ':')
return a.cached_cpuinfo[key]
}
fn (mut a App) git_info() string {

View File

@@ -6,6 +6,7 @@ module main
import os
import os.cmdline
import rand
import term
import v.ast
import v.pref
import v.fmt
@@ -30,6 +31,7 @@ struct FormatOptions {
const (
formatted_file_token = '\@\@\@' + 'FORMATTED_FILE: '
vtmp_folder = util.get_vtmp_folder()
term_colors = term.can_show_color_on_stderr()
)
fn main() {
@@ -52,6 +54,9 @@ fn main() {
is_noerror: '-noerror' in args
is_verify: '-verify' in args
}
if term_colors {
os.setenv('VCOLORS', 'always', true)
}
if foptions.is_verbose {
eprintln('vfmt foptions: $foptions')
}
@@ -150,6 +155,7 @@ fn main() {
if foptions.is_c {
exit(2)
}
exit(1)
}
}
@@ -165,7 +171,7 @@ fn (foptions &FormatOptions) format_file(file string) {
parent: 0
})
// checker.check(file_ast)
formatted_content := fmt.fmt(file_ast, table, foptions.is_debug)
formatted_content := fmt.fmt(file_ast, table, prefs, foptions.is_debug)
file_name := os.file_name(file)
ulid := rand.ulid()
vfmt_output_path := os.join_path(vtmp_folder, 'vfmt_${ulid}_$file_name')
@@ -189,7 +195,7 @@ fn (foptions &FormatOptions) format_pipe() {
parent: 0
})
// checker.check(file_ast)
formatted_content := fmt.fmt(file_ast, table, foptions.is_debug)
formatted_content := fmt.fmt(file_ast, table, prefs, foptions.is_debug)
print(formatted_content)
if foptions.is_verbose {
eprintln('fmt.fmt worked and $formatted_content.len bytes were written to stdout.')

View File

@@ -5,6 +5,7 @@ module main
import os
import term
import rand
import readline
import os.cmdline
import v.util
@@ -24,9 +25,9 @@ mut:
temp_lines []string // all the temporary expressions/printlns
}
const (
is_stdin_a_pipe = (is_atty(0) == 0)
)
const is_stdin_a_pipe = (is_atty(0) == 0)
const vexe = os.getenv('VEXE')
fn new_repl() Repl {
return Repl{
@@ -112,7 +113,6 @@ fn run_repl(workdir string, vrepl_prefix string) {
cleanup_files([file, temp_file])
}
mut r := new_repl()
vexe := os.getenv('VEXE')
for {
if r.indent == 0 {
prompt = '>>> '
@@ -185,10 +185,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
if r.line.starts_with('print') {
source_code := r.current_source_code(false) + '\n$r.line\n'
os.write_file(file, source_code) or { panic(err) }
s := os.exec('"$vexe" -repl run "$file"') or {
rerror(err)
return
}
s := repl_run_vfile(file) or { return }
print_output(s)
} else {
mut temp_line := r.line
@@ -255,10 +252,7 @@ fn run_repl(workdir string, vrepl_prefix string) {
temp_source_code = r.current_source_code(true) + '\n$temp_line\n'
}
os.write_file(temp_file, temp_source_code) or { panic(err) }
s := os.exec('"$vexe" -repl run "$temp_file"') or {
rerror(err)
return
}
s := repl_run_vfile(temp_file) or { return }
if !func_call && s.exit_code == 0 && !temp_flag {
for r.temp_lines.len > 0 {
if !r.temp_lines[0].starts_with('print') {
@@ -313,9 +307,8 @@ fn main() {
// so that the repl can be launched in parallel by several different
// threads by the REPL test runner.
args := cmdline.options_after(os.args, ['repl'])
replfolder := os.real_path(cmdline.option(args, '-replfolder', '.'))
replprefix := cmdline.option(args, '-replprefix', 'noprefix.')
os.chdir(replfolder)
replfolder := os.real_path(cmdline.option(args, '-replfolder', os.temp_dir()))
replprefix := cmdline.option(args, '-replprefix', 'noprefix.${rand.ulid()}.')
if !os.exists(os.getenv('VEXE')) {
println('Usage:')
println(' VEXE=vexepath vrepl\n')
@@ -356,3 +349,14 @@ fn cleanup_files(files []string) {
}
}
}
fn repl_run_vfile(file string) ?os.Result {
$if trace_repl_temp_files ? {
eprintln('>> repl_run_vfile file: $file')
}
s := os.exec('"$vexe" -repl run "$file"') or {
rerror(err)
return error(err)
}
return s
}

View File

@@ -1,23 +1,29 @@
import os
import v.pref
import v.util
$if windows {
$if tinyc {
#flag -lAdvapi32
#flag -lUser32
}
}
fn main() {
C.atexit(cleanup_vtmp_folder)
vexe := os.real_path(pref.vexe_path())
$if windows {
setup_symlink_windows(vexe)
} $else {
setup_symlink(vexe)
setup_symlink_unix(vexe)
}
}
fn setup_symlink(vexe string) {
fn cleanup_vtmp_folder() {
os.rmdir_all(util.get_vtmp_folder()) or { }
}
fn setup_symlink_unix(vexe string) {
link_dir := '/usr/local/bin'
if !os.exists(link_dir) {
os.mkdir_all(link_dir) or { panic(err) }
@@ -142,11 +148,11 @@ fn get_reg_value(reg_env_key voidptr, key string) ?string {
$if windows {
// query the value (shortcut the sizing step)
reg_value_size := 4095 // this is the max length (not for the registry, but for the system %PATH%)
mut reg_value := &u16(malloc(reg_value_size))
mut reg_value := unsafe { &u16(malloc(reg_value_size)) }
if C.RegQueryValueEx(reg_env_key, key.to_wide(), 0, 0, reg_value, &reg_value_size) != 0 {
return error('Unable to get registry value for "$key", try rerunning as an Administrator')
}
return string_from_wide(reg_value)
return unsafe { string_from_wide(reg_value) }
}
return error('not on windows')
}
@@ -166,7 +172,8 @@ fn set_reg_value(reg_key voidptr, key string, value string) ?bool {
// letting them know that the system environment has changed and should be reloaded
fn send_setting_change_msg(message_data string) ?bool {
$if windows {
if C.SendMessageTimeout(os.hwnd_broadcast, os.wm_settingchange, 0, message_data.to_wide(), os.smto_abortifhung, 5000, 0) == 0 {
if C.SendMessageTimeout(os.hwnd_broadcast, os.wm_settingchange, 0, message_data.to_wide(),
os.smto_abortifhung, 5000, 0) == 0 {
return error('Could not broadcast WM_SETTINGCHANGE')
}
return true

View File

@@ -78,7 +78,7 @@ fn get_all_commands() []Command {
okmsg: 'All examples can be compiled.'
}
res << Command{
line: '$vexe run cmd/tools/check-md.v -hide-warnings -all'
line: '$vexe check-md -hide-warnings .'
label: 'Check ```v ``` code examples and formatting of .MD files...'
okmsg: 'All .md files look good.'
}

View File

@@ -11,6 +11,9 @@ const (
'vlib/v',
'cmd/v',
'cmd/tools',
'examples/2048',
'examples/tetris',
'examples/term.ui',
]
verify_known_failing_exceptions = []string{}
vfmt_verify_list = [
@@ -34,28 +37,26 @@ const (
'vlib/v/checker/',
'vlib/v/depgraph/',
'vlib/v/doc/',
'vlib/v/embed_file/',
'vlib/v/errors/',
'vlib/v/eval/',
'vlib/v/fmt/',
'vlib/v/gen/auto_str_methods.v',
'vlib/v/gen/cgen.v',
'vlib/v/gen/cgen_test.v',
'vlib/v/gen/cmain.v',
'vlib/v/gen/comptime.v',
'vlib/v/gen/fn.v',
'vlib/v/gen/json.v',
'vlib/v/gen/live.v',
'vlib/v/gen/profile.v',
'vlib/v/gen/sql.v',
'vlib/v/gen/str.v',
'vlib/v/gen/x64/elf.v',
'vlib/v/gen/x64/elf_obj.v',
'vlib/v/gen/x64/gen.v',
'vlib/v/gen/c/',
/* 'vlib/v/gen/js/', */
'vlib/v/gen/tests/',
'vlib/v/gen/x64/',
'vlib/v/live/',
'vlib/v/markused/',
'vlib/v/parser/',
/* 'vlib/v/pkgconfig/', */
'vlib/v/pref/',
'vlib/v/preludes',
'vlib/v/scanner/',
'vlib/v/table/',
/* 'vlib/v/tests/', */
'vlib/v/token/',
'vlib/v/util/',
'vlib/v/vcache/',
'vlib/v/vet/',
'vlib/v/vmod/',
'vlib/cli/',

View File

@@ -14,7 +14,7 @@ const (
ecode_timeout = 101
ecode_memout = 102
ecode_exec = 103
ecode_details = {
ecode_details = map{
'101': 'too slow'
'102': 'too memory hungry'
'103': 'worker executable not found'
@@ -37,7 +37,7 @@ mut:
// parser context in the worker processes:
table table.Table
scope ast.Scope
pref pref.Preferences
pref &pref.Preferences
period_ms int // print periodic progress
stop_print bool // stop printing the periodic progress
}
@@ -60,7 +60,7 @@ fn main() {
source = source[..context.cut_index]
go fn (ms int) {
time.sleep_ms(ms)
time.wait(ms * time.millisecond)
exit(ecode_timeout)
}(context.timeout_ms)
_ := parser.parse_text(source, context.path, context.table, .skip_comments, context.pref,
@@ -96,7 +96,9 @@ fn main() {
}
fn process_cli_args() &Context {
mut context := &Context{}
mut context := &Context{
pref: pref.new_preferences()
}
context.myself = os.executable()
mut fp := flag.new_flag_parser(os.args_after('test-parser'))
fp.application(os.file_name(context.myself))
@@ -257,7 +259,7 @@ fn (mut context Context) start_printing() {
fn (mut context Context) stop_printing() {
context.stop_print = true
time.sleep_ms(context.period_ms / 5)
time.wait(time.millisecond * context.period_ms / 5)
}
fn (mut context Context) print_status() {
@@ -282,7 +284,7 @@ fn (mut context Context) print_periodic_status() {
for !context.stop_print {
context.print_status()
for i := 0; i < 10 && !context.stop_print; i++ {
time.sleep_ms(context.period_ms / 10)
time.wait(time.millisecond * context.period_ms / 10)
if context.cut_index > 50 && !printed_at_least_once {
context.print_status()
printed_at_least_once = true

View File

@@ -6,54 +6,318 @@ import v.pref
const (
skip_with_fsanitize_memory = [
'vlib/encoding/csv/reader_test.v',
'vlib/net/tcp_test.v',
'vlib/net/tcp_simple_client_server_test.v',
'vlib/net/udp_test.v',
'vlib/net/http/cookie_test.v',
'vlib/net/http/http_test.v',
'vlib/net/http/status_test.v',
'vlib/net/http/http_httpbin_test.v',
'vlib/net/udp_test.v',
'vlib/net/tcp_test.v',
'vlib/orm/orm_test.v',
'vlib/sqlite/sqlite_test.v',
'vlib/v/tests/orm_sub_struct_test.v',
'vlib/vweb/tests/vweb_test.v',
'vlib/v/tests/unsafe_test.v',
'vlib/x/websocket/websocket_test.v',
'vlib/net/http/http_httpbin_test.v',
]
skip_with_fsanitize_address = [
'vlib/encoding/base64/base64_test.v',
'vlib/encoding/csv/reader_test.v',
'vlib/flag/flag_test.v',
'vlib/io/util/util_test.v',
'vlib/io/reader_test.v',
'vlib/encoding/base64/base64_test.v',
'vlib/json/json_test.v',
'vlib/net/http/cookie_test.v',
'vlib/os/inode_test.v',
'vlib/os/os_test.v',
'vlib/regex/regex_test.v',
'vlib/semver/semver_test.v',
'vlib/sync/channel_opt_propagate_test.v',
'vlib/time/parse_test.v',
'vlib/v/fmt/fmt_keep_test.v',
'vlib/v/fmt/fmt_test.v',
'vlib/v/tests/array_init_test.v',
'vlib/v/doc/doc_test.v',
'vlib/v/tests/const_test.v',
'vlib/v/tests/fn_multiple_returns_test.v',
'vlib/v/tests/inout/compiler_test.v',
'vlib/v/tests/option_default_values_test.v',
'vlib/v/tests/option_test.v',
'vlib/v/tests/ptr_arithmetic_test.v',
'vlib/v/tests/str_gen_test.v',
'vlib/v/tests/unsafe_test.v',
'vlib/v/tests/vmod_parser_test.v',
'vlib/v/vcache/vcache_test.v',
'vlib/x/json2/decoder_test.v',
'vlib/x/websocket/websocket_test.v',
'vlib/v/tests/match_in_map_init_test.v',
]
skip_with_fsanitize_undefined = [
'vlib/encoding/csv/reader_test.v',
]
skip_with_werror = [
'vlib/builtin/array_test.v',
'vlib/clipboard/clipboard_test.v',
'vlib/dl/example/use_test.v',
'vlib/eventbus/eventbus_test.v',
'vlib/gx/color_test.v',
'vlib/json/json_test.v',
'vlib/net/ftp/ftp_test.v',
'vlib/net/smtp/smtp_test.v',
'vlib/net/http/cookie_test.v',
'vlib/net/tcp_test.v',
'vlib/net/udp_test.v',
'vlib/net/tcp_simple_client_server_test.v',
'vlib/net/unix/unix_test.v',
'vlib/net/http/http_httpbin_test.v',
'vlib/net/http/status_test.v',
'vlib/net/http/http_test.v',
'vlib/orm/orm_test.v',
'vlib/readline/readline_test.v',
'vlib/sqlite/sqlite_test.v',
'vlib/strconv/number_to_base_test.v',
'vlib/sync/channel_1_test.v',
'vlib/sync/atomic2/atomic_test.v',
'vlib/sync/channel_2_test.v',
'vlib/sync/channel_4_test.v',
'vlib/sync/channel_fill_test.v',
'vlib/sync/channel_array_mut_test.v',
'vlib/sync/channel_close_test.v',
'vlib/sync/channel_3_test.v',
'vlib/sync/channel_opt_propagate_test.v',
'vlib/sync/channel_polling_test.v',
'vlib/sync/channel_push_or_1_test.v',
'vlib/sync/channel_push_or_2_test.v',
'vlib/sync/channel_select_2_test.v',
'vlib/sync/channel_select_3_test.v',
'vlib/sync/channel_select_5_test.v',
'vlib/sync/channel_select_4_test.v',
'vlib/sync/channel_select_6_test.v',
'vlib/sync/channel_try_unbuf_test.v',
'vlib/sync/channel_select_test.v',
'vlib/sync/channel_try_buf_test.v',
'vlib/sync/pool/pool_test.v',
'vlib/sync/select_close_test.v',
'vlib/sync/struct_chan_init_test.v',
'vlib/szip/szip_test.v',
'vlib/v/compiler_errors_test.v',
'vlib/v/tests/anon_fn_test.v',
'vlib/v/tests/array_map_ref_test.v',
'vlib/v/tests/array_test.v',
'vlib/v/tests/assert_sumtype_test.v',
'vlib/v/tests/autolock_array1_test.v',
'vlib/v/tests/autolock_array2_test.v',
'vlib/v/tests/blank_ident_test.v',
'vlib/v/tests/comptime_call_test.v',
'vlib/v/tests/comptime_at_test.v',
'vlib/v/tests/comptime_if_expr_test.v',
'vlib/v/tests/fixed_array_test.v',
'vlib/v/tests/fn_variadic_test.v',
'vlib/v/tests/fn_shared_return_test.v',
'vlib/v/tests/for_loops_2_test.v',
'vlib/v/tests/generic_chan_test.v',
'vlib/v/tests/generics_method_test.v',
'vlib/v/tests/generics_test.v',
'vlib/v/tests/go_call_generic_fn_test.v',
'vlib/v/tests/go_wait_2_test.v',
'vlib/v/tests/interface_edge_cases/assign_to_interface_field_test.v',
'vlib/v/tests/interface_fields_test.v',
'vlib/v/tests/interface_variadic_test.v',
'vlib/v/tests/orm_sub_struct_test.v',
'vlib/v/tests/ref_struct_test.v',
'vlib/v/tests/semaphore_test.v',
'vlib/v/tests/repl/repl_test.v',
'vlib/v/tests/semaphore_timed_test.v',
'vlib/v/tests/shared_arg_test.v',
'vlib/v/tests/shared_array_test.v',
'vlib/v/tests/shared_elem_test.v',
'vlib/v/tests/shared_autolock_test.v',
'vlib/v/tests/shared_fn_return_test.v',
'vlib/v/tests/shared_lock_2_test.v',
'vlib/v/tests/shared_lock_3_test.v',
'vlib/v/tests/shared_lock_5_test.v',
'vlib/v/tests/shared_lock_4_test.v',
'vlib/v/tests/shared_lock_6_test.v',
'vlib/v/tests/shared_lock_expr_test.v',
'vlib/v/tests/shared_lock_test.v',
'vlib/v/tests/shift_test.v',
'vlib/v/tests/shared_unordered_mixed_test.v',
'vlib/v/tests/shared_map_test.v',
'vlib/v/tests/str_gen_test.v',
'vlib/v/tests/string_interpolation_multi_return_test.v',
'vlib/v/tests/string_interpolation_shared_test.v',
'vlib/v/tests/string_interpolation_test.v',
'vlib/v/tests/struct_allow_both_field_defaults_and_skip_flag_test.v',
'vlib/v/tests/struct_test.v',
'vlib/v/tests/sum_type_test.v',
'vlib/v/tests/type_name_test.v',
'vlib/v/tests/unsafe_test.v',
'vlib/v/tests/working_with_an_empty_struct_test.v',
'vlib/vweb/tests/vweb_test.v',
'vlib/x/json2/any_test.v',
'vlib/x/json2/decoder_test.v',
'vlib/x/json2/json2_test.v',
'vlib/x/websocket/websocket_test.v',
'vlib/math/big/big_test.v',
'vlib/os/os_test.v',
'vlib/rand/mt19937/mt19937_test.v',
'vlib/regex/regex_test.v',
'vlib/strconv/atof_test.v',
'vlib/v/tests/cstrings_test.v',
'vlib/v/tests/enum_test.v',
'vlib/v/tests/in_expression_test.v',
'vlib/v/tests/operator_overloading_with_string_interpolation_test.v',
'vlib/v/tests/voidptr_to_u64_cast_a_test.v',
'vlib/v/tests/voidptr_to_u64_cast_b_test.v',
'vlib/dl/dl_test.v',
'vlib/strconv/f32_f64_to_string_test.v',
'vlib/x/ttf/ttf_test.v',
]
skip_with_asan_compiler = [
'vlib/builtin/map_of_floats_test.v',
'vlib/builtin/int_test.v',
'vlib/builtin/string_test.v',
'vlib/crypto/aes/aes_test.v',
'vlib/crypto/md5/md5_test.v',
'vlib/crypto/rc4/rc4_test.v',
'vlib/crypto/sha1/sha1_test.v',
'vlib/crypto/sha256/sha256_test.v',
'vlib/crypto/sha512/sha512_test.v',
'vlib/dl/example/use_test.v',
'vlib/encoding/base64/base64_test.v',
'vlib/encoding/csv/reader_test.v',
'vlib/encoding/csv/writer_test.v',
'vlib/encoding/utf8/encoding_utf8_test.v',
'vlib/eventbus/eventbus_test.v',
'vlib/encoding/utf8/utf8_util_test.v',
'vlib/flag/flag_test.v',
'vlib/glm/glm_test.v',
'vlib/hash/crc32/crc32_test.v',
'vlib/hash/hash_wyhash_test.v',
'vlib/math/big/big_test.v',
'vlib/math/complex/complex_test.v',
'vlib/math/fractions/approximations_test.v',
'vlib/math/fractions/fraction_test.v',
'vlib/net/urllib/urllib_test.v',
'vlib/os/os_test.v',
'vlib/readline/readline_test.v',
'vlib/strconv/f32_f64_to_string_test.v',
'vlib/strings/builder_test.v',
'vlib/szip/szip_test.v',
'vlib/v/embed_file/embed_file_test.v',
'vlib/v/tests/anon_fn_call_test.v',
'vlib/v/tests/anon_fn_returning_question_test.v',
'vlib/v/tests/appending_to_mut_array_in_fn_param_test.v',
'vlib/v/tests/array_append_short_struct_test.v',
'vlib/v/tests/array_methods_test.v',
'vlib/v/tests/assert_sumtype_test.v',
'vlib/v/tests/as_cast_is_expr_sumtype_fn_result_test.v',
'vlib/v/tests/array_to_string_test.v',
'vlib/v/tests/array_type_alias_test.v',
'vlib/v/tests/assign_bitops_with_type_aliases_test.v',
'vlib/v/tests/cast_to_byte_test.v',
'vlib/v/tests/cast_to_interface_test.v',
'vlib/v/tests/complex_assign_test.v',
'vlib/v/tests/blank_ident_test.v',
'vlib/v/tests/comptime_field_selector_test.v',
'vlib/v/tests/comptime_call_test.v',
'vlib/v/tests/comptime_if_expr_test.v',
'vlib/v/tests/comptime_for_test.v',
'vlib/v/tests/const_test.v',
'vlib/v/tests/cross_assign_test.v',
'vlib/v/tests/differently_named_structs_test.v',
'vlib/v/tests/defer_test.v',
'vlib/v/tests/enum_default_value_in_struct_test.v',
'vlib/v/tests/enum_bitfield_test.v',
'vlib/v/tests/enum_hex_test.v',
'vlib/v/tests/enum_array_field_test.v',
'vlib/v/tests/enum_test.v',
'vlib/v/tests/fixed_array_test.v',
'vlib/v/tests/fixed_array_const_size_test.v',
'vlib/v/tests/fn_cross_assign_test.v',
'vlib/v/tests/fn_expecting_ref_but_returning_struct_test.v',
'vlib/v/tests/fn_variadic_test.v',
'vlib/v/tests/fn_type_aliases_test.v',
'vlib/v/tests/fn_with_fixed_array_function_args_test.v',
'vlib/v/tests/for-in-iterator_test.v',
'vlib/v/tests/for_in_mut_val_test.v',
'vlib/v/tests/generic_fn_returning_type_with_T_test.v',
'vlib/v/tests/generics_method_test.v',
'vlib/v/tests/generics_return_multi_array_test.v',
'vlib/v/tests/go_wait_3_test.v',
'vlib/v/tests/imported_symbols_test.v',
'vlib/v/tests/go_handle_for_functions_returning_array_test.v',
'vlib/v/tests/in_expression_test.v',
'vlib/v/tests/interface_edge_cases/array_of_interfaces_with_utility_fn_test.v',
'vlib/v/tests/interface_edge_cases/assign_to_interface_field_test.v',
'vlib/v/tests/interface_edge_cases/i4_test.v',
'vlib/v/tests/interface_edge_cases/array_of_interfaces_test.v',
'vlib/v/tests/interface_edge_cases/i3_test.v',
'vlib/v/tests/interface_edge_cases/i1_test.v',
'vlib/v/tests/interface_edge_cases/i2_test.v',
'vlib/v/tests/interface_edge_cases/i5_test.v',
'vlib/v/tests/interface_struct_test.v',
'vlib/v/tests/interface_variadic_test.v',
'vlib/v/tests/interface_edge_cases/i8_test.v',
'vlib/v/tests/interfaces_map_test.v',
'vlib/v/tests/interface_edge_cases/i6_test.v',
'vlib/v/tests/interface_fields_test.v',
'vlib/v/tests/interface_edge_cases/i7_test.v',
'vlib/v/tests/interop_test.v',
'vlib/v/tests/map_alias_key_test.v',
'vlib/v/tests/map_and_array_with_fns_test.v',
'vlib/v/tests/map_complex_fixed_array_test.v',
'vlib/v/tests/map_high_order_assign_test.v',
'vlib/v/tests/map_to_string_test.v',
'vlib/v/tests/map_key_expr_test.v',
'vlib/v/tests/match_expression_for_types_test.v',
'vlib/v/tests/map_type_alias_test.v',
'vlib/v/tests/match_sumtype_var_shadow_and_as_test.v',
'vlib/v/tests/match_expression_with_fn_names_in_branches_test.v',
'vlib/v/tests/method_call_chain_test.v',
'vlib/v/tests/methods_on_interfaces_test.v',
'vlib/v/tests/modules/methods_struct_another_module/methods_struct_test.v',
'vlib/v/tests/modules/simplemodule/importing_test.v',
'vlib/v/tests/multiret_with_ptrtype_test.v',
'vlib/v/tests/offsetof_test.v',
'vlib/v/tests/nested_option_call_test.v',
'vlib/v/tests/operator_overloading_cmp_test.v',
'vlib/v/tests/operator_overloading_with_string_interpolation_test.v',
'vlib/v/tests/option_default_values_test.v',
'vlib/v/tests/pointers_test.v',
'vlib/v/tests/pointers_str_test.v',
'vlib/v/tests/project_with_c_code/main_test.v',
'vlib/v/tests/project_with_c_code_2/main2_test.v',
'vlib/v/tests/ptr_arithmetic_test.v',
'vlib/v/tests/ref_return_test.v',
'vlib/v/tests/return_voidptr_test.v',
'vlib/v/tests/shift_test.v',
'vlib/v/tests/sizeof_2_test.v',
'vlib/v/tests/short_struct_param_syntax_test.v',
'vlib/v/tests/sorting_by_references_test.v',
'vlib/v/tests/sorting_by_different_criteria_test.v',
'vlib/v/tests/string_interpolation_array_test.v',
'vlib/v/tests/string_alias_test.v',
'vlib/v/tests/string_interpolation_alias_test.v',
'vlib/v/tests/string_interpolation_custom_str_test.v',
'vlib/v/tests/string_interpolation_multi_return_test.v',
'vlib/v/tests/string_interpolation_of_array_of_structs_test.v',
'vlib/v/tests/string_interpolation_test.v',
'vlib/v/tests/string_interpolation_variadic_test.v',
'vlib/v/tests/string_struct_interpolation_test.v',
'vlib/v/tests/struct_allow_both_field_defaults_and_skip_flag_test.v',
'vlib/v/tests/struct_child_field_default_test.v',
'vlib/v/tests/struct_equality_test.v',
'vlib/v/tests/struct_field_default_value_interface_cast_test.v',
'vlib/v/tests/struct_field_default_value_sumtype_cast_test.v',
'vlib/v/tests/struct_eq_op_only_test.v',
'vlib/v/tests/struct_map_method_test.v',
'vlib/v/tests/struct_fields_storing_functions_test.v',
'vlib/v/tests/struct_transmute_test.v',
'vlib/v/tests/sumtype_literal_test.v',
'vlib/v/tests/sumtype_calls_test.v',
'vlib/v/tests/sumtype_str_for_subtypes_with_str_test.v',
'vlib/v/tests/type_alias_str_method_override_test.v',
'vlib/v/tests/type_alias_test.v',
'vlib/v/tests/type_name_test.v',
'vlib/v/tests/type_promotion_test.v',
'vlib/v/tests/unsafe_test.v',
'vlib/v/tests/vargs_auto_str_method_and_println_test.v',
'vlib/v/tests/vargs_empty_param_test.v',
'vlib/v/tests/working_with_an_empty_struct_test.v',
'vlib/v/vcache/vcache_test.v',
'vlib/vweb/tests/vweb_test.v',
'vlib/v/compiler_errors_test.v',
'vlib/v/tests/map_enum_keys_test.v',
'vlib/v/tests/tmpl_test.v',
'vlib/v/checker/tests/arrow_op_wrong_left_type_err_b.vv',
'vlib/v/checker/tests/arrow_op_wrong_right_type_err_a.vv',
'vlib/v/checker/tests/lock_already_locked.vv',
'vlib/v/checker/tests/lock_already_rlocked.vv',
'vlib/v/checker/tests/lock_needed.vv',
'vlib/v/checker/tests/lock_nonshared.vv',
'vlib/v/checker/tests/shared_type_mismatch.vv',
'vlib/v/tests/match_with_complex_exprs_in_branches_test.v',
'vlib/v/tests/match_in_map_init_test.v',
]
skip_test_files = []string{}
skip_on_musl = [
'vlib/v/tests/profile/profile_test.v',
@@ -66,6 +330,7 @@ const (
'vlib/net/websocket/ws_test.v',
'vlib/sqlite/sqlite_test.v',
'vlib/orm/orm_test.v',
'vlib/v/tests/orm_sub_struct_test.v',
'vlib/clipboard/clipboard_test.v',
'vlib/vweb/tests/vweb_test.v',
'vlib/x/websocket/websocket_test.v',
@@ -77,7 +342,9 @@ const (
]
skip_on_windows = [
'vlib/orm/orm_test.v',
'vlib/v/tests/orm_sub_struct_test.v',
'vlib/net/websocket/ws_test.v',
'vlib/net/unix/unix_test.v',
'vlib/x/websocket/websocket_test.v',
'vlib/vweb/tests/vweb_test.v',
]
@@ -101,10 +368,18 @@ fn main() {
mut tsession := testing.new_test_session(cmd_prefix)
tsession.files << all_test_files
tsession.skip_files << skip_test_files
mut werror := false
mut sanitize_memory := false
mut sanitize_address := false
mut sanitize_undefined := false
mut asan_compiler := false
for arg in args {
if '-asan-compiler' in arg {
asan_compiler = true
}
if '-Werror' in arg {
werror = true
}
if '-fsanitize=memory' in arg {
sanitize_memory = true
}
@@ -115,6 +390,9 @@ fn main() {
sanitize_undefined = true
}
}
if werror {
tsession.skip_files << skip_with_werror
}
if sanitize_memory {
tsession.skip_files << skip_with_fsanitize_memory
}
@@ -124,6 +402,9 @@ fn main() {
if sanitize_undefined {
tsession.skip_files << skip_with_fsanitize_undefined
}
if asan_compiler {
tsession.skip_files << skip_with_asan_compiler
}
// println(tsession.skip_files)
if os.getenv('V_CI_MUSL').len > 0 {
tsession.skip_files << skip_on_musl

View File

@@ -71,6 +71,9 @@ fn main() {
}
}
}
if os.is_file(path) {
vet.vet_file(path, false)
}
if os.is_dir(path) {
vet.vprintln("vetting folder: '$path' ...")
vfiles := os.walk_ext(path, '.v')

21
cmd/v/help/check-md.txt Normal file
View File

@@ -0,0 +1,21 @@
check-md is a tool to check the passed markdown files for correct ```v ``` code blocks
and other style violations like too long lines/links etc...
Usage:
a) `v check-md [flags] <...files>` - Check the given .md files.
b) `v check-md [flags] <...dirs>` - Check *all* files in the given directories.
Note: You can also combine files and directories.
Flags:
-hide-warnings Do not print warnings, only errors.
NB: There are several special keywords, which you can put after the code fences for v.
These are:
compile - Default, can be omitted. The example will be compiled and formatting is verified.
live - Compile hot reload examples with the ´-live´ flag set and verify formatting.
ignore - Ignore the example, useful for examples that just use the syntax highlighting
failcompile - Known failing compilation. Useful for examples demonstrating compiler errors.
oksyntax - Should parse and be formatted but may not compile. Useful for partial examples.
badsyntax - Known bad syntax, it should not even parse.
wip - Like ignore; a planned feature; easy to search.
nofmt - Disable fmt verification for individual code blocks.

View File

@@ -35,7 +35,7 @@ V supports the following commands:
list List all installed modules.
outdated Show installed modules that need updates.
* Others:
doctor Display some usefull info about your system to help reporting bugs
doctor Display some usefull info about your system to help reporting bugs.
translate Translate C code to V (coming soon in 0.3).
tracev Produce a tracing version of the v compiler.
Use `tracev yourfile.v` when the compiler panics.
@@ -45,4 +45,4 @@ Use "v help <command>" for more information about a command, example: `v help bu
Use "v help other" to see less frequently used commands.
Note: Help is required to write more help topics.
Only build, doc, fmt, run, test, search, install, remove, update, bin2v are properly documented currently.
Only build, doc, fmt, run, test, search, install, remove, update, bin2v, check-md are properly documented currently.

View File

@@ -27,9 +27,6 @@ Options:
For HTML mode:
-inline-assets Embeds the contents of the CSS and JS assets into the webpage directly.
-open Launches the browser when the server docs has started.
-p Specifies the port to be used for the docs server.
-s Serve HTML-generated docs via HTTP.
For plain text mode:
-l Show the locations of the generated signatures.

View File

@@ -8,6 +8,8 @@ but which are used less frequently by users:
build-tools Test if all tools can be built.
build-vbinaries Test if V can be built with different configuration.
check-md Check that V examples in markdown files are formatted and can compile.
test-all Run most checks, that the CI does locally.
It may take over 2 minutes, and it needs internet connectivity too,
because it tries to also verify that `v install` works.

View File

@@ -10,7 +10,7 @@ import v.util
import v.builder
const (
simple_cmd = [
external_tools = [
'fmt',
'up',
'vet',
@@ -27,6 +27,7 @@ const (
'test-compiler', /* deprecated by test-self */
'test-compiler-full', /* deprecated by test-self */
'test-cleancode',
'check-md',
'repl',
'complete',
'build-tools',
@@ -62,14 +63,14 @@ fn main() {
} else {
mut args_and_flags := util.join_env_vflags_and_os_args()[1..].clone()
args_and_flags << ['run', '-']
pref.parse_args(args_and_flags)
pref.parse_args(external_tools, args_and_flags)
}
}
util.launch_tool(false, 'vrepl', os.args[1..])
return
}
args_and_flags := util.join_env_vflags_and_os_args()[1..]
prefs, command := pref.parse_args(args_and_flags)
prefs, command := pref.parse_args(external_tools, args_and_flags)
if prefs.is_verbose {
// println('args= ')
// println(args) // QTODO
@@ -94,7 +95,7 @@ fn main() {
}
// Start calling the correct functions/external tools
// Note for future contributors: Please add new subcommands in the `match` block below.
if command in simple_cmd {
if command in external_tools {
// External tools
util.launch_tool(prefs.is_verbose, 'v' + command, os.args[1..])
return

View File

@@ -20,18 +20,23 @@ The major way to get the latest and greatest V, is to __install it from source__
It is __easy__, and it usually takes __only a few seconds__.
### Linux, macOS, FreeBSD, etc:
You need `git`, a C compiler like `gcc` or `clang`, and `make`:
You need `git`, and a C compiler like `tcc`, `gcc` or `clang`, and `make`:
```bash
git clone https://github.com/vlang/v && cd v && make
git clone https://github.com/vlang/v
cd v
make
```
### Windows:
You need `git`, and a C compiler like `gcc` or `msvc`:
You need `git`, and a C compiler like `tcc`, `gcc`, `clang` or `msvc`:
```bash
git clone https://github.com/vlang/v
cd v
make
make.bat -tcc
```
NB: You can also pass one of `-gcc`, `-msvc`, `-clang` to `make.bat` instead,
if you do prefer to use a different C compiler, but -tcc is small, fast, and
easy to install (V will download a prebuilt binary automatically).
### Android
Running V graphical apps on Android is also possible via [vab](https://github.com/vlang/vab).
@@ -39,7 +44,7 @@ Running V graphical apps on Android is also possible via [vab](https://github.co
V Android dependencies: **V**, **Java JDK** >= 8, Android **SDK + NDK**.
1. Install dependencies (see [vab](https://github.com/vlang/vab))
2. Plugin-in your Android device
2. Connect your Android device
3. Run:
```bash
git clone https://github.com/vlang/vab && cd vab && v vab.v
@@ -63,6 +68,7 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
* [Strings](#strings)
* [Numbers](#numbers)
* [Arrays](#arrays)
* [Fixed size arrays](#fixed-size-arrays)
* [Maps](#maps)
* [Module imports](#module-imports)
* [Statements & expressions](#statements--expressions)
@@ -80,15 +86,16 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
</td><td width=33% valign=top>
* [Unions](#unions)
* [Functions 2](#functions-2)
* [Pure functions by default](#pure-functions-by-default)
* [Mutable arguments](#mutable-arguments)
* [Anonymous & high order functions](#anonymous--high-order-functions)
* [References](#references)
* [Modules](#modules)
* [Constants](#constants)
* [Builtin functions](#builtin-functions)
* [Printing custom types](#custom-print-of-types)
* [Printing custom types](#printing-custom-types)
* [Modules](#modules)
* [Types 2](#types-2)
* [Interfaces](#interfaces)
* [Enums](#enums)
@@ -125,6 +132,7 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
* [Cross compilation](#cross-compilation)
* [Cross-platform shell scripts in V](#cross-platform-shell-scripts-in-v)
* [Attributes](#attributes)
* [Goto](#goto)
* [Appendices](#appendices)
* [Keywords](#appendix-i-keywords)
* [Operators](#appendix-ii-operators)
@@ -134,8 +142,8 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
<!--
NB: there are several special keywords, which you can put after the code fences for v:
compile, ignore, failcompile, oksyntax, badsyntax, wip
For more details, do: `v run cmd/tools/check-md.v`
compile, live, ignore, failcompile, oksyntax, badsyntax, wip, nofmt
For more details, do: `v check-md`
-->
## Hello World
@@ -416,7 +424,7 @@ Literals like `123` or `4.56` are treated in a special way. They do
not lead to type promotions, however they default to `int` and `f64`
respectively, when their type has to be decided:
```v ignore
```v nofmt
u := u16(12)
v := 13 + u // v is of type `u16` - no promotion
x := f32(45.6)
@@ -716,7 +724,7 @@ numbers.sort() // 1, 2, 3
numbers.sort(a > b) // 3, 2, 1
```
```v nofmt
```v
struct User {
age int
name string
@@ -753,6 +761,34 @@ array_2 << array_1[..3]
println(array_2) // [0, 1, 3, 5, 4]
```
### Fixed size arrays
V also supports arrays with fixed size. Unlike ordinary arrays, their
length is constant. You cannot append elements to them, nor shrink them.
You can only modify their elements in place.
However, access to the elements of fixed size arrays is more efficient,
they need less memory than ordinary arrays, and unlike ordinary arrays,
their data is on the stack, so you may want to use them as buffers if you
do not want additional heap allocations.
Most methods are defined to work on ordinary arrays, not on fixed size arrays.
You can convert a fixed size array to an ordinary array with slicing:
```v
mut fnums := [3]int{} // fnums is a fixed size array with 3 elements.
fnums[0] = 1
fnums[1] = 10
fnums[2] = 100
println(fnums) // => [1, 10, 100]
println(typeof(fnums).name) // => [3]int
anums := fnums[0..fnums.len]
println(anums) // => [1, 10, 100]
println(typeof(anums).name) // => []int
```
Note that slicing will cause the data of the fixed size array to be copied to
the newly created ordinary array.
### Maps
```v
@@ -763,9 +799,12 @@ println(m['one']) // "1"
println(m['bad_key']) // "0"
println('bad_key' in m) // Use `in` to detect whether such key exists
m.delete('two')
// NB: map keys can have any type, `int` in this case,
// and the whole map can be initialized using this short syntax:
numbers := {
```
Maps can have keys of type string, rune, integer, float or voidptr.
The whole map can be initialized using this short syntax:
```v
numbers := map{
1: 'one'
2: 'two'
}
@@ -775,12 +814,14 @@ println(numbers)
If a key is not found, a zero value is returned by default:
```v
sm := {
sm := map{
'abc': 'xyz'
}
val := sm['bad_key']
println(val) // ''
intm := {
```
```v
intm := map{
1: 1234
2: 5678
}
@@ -835,8 +876,12 @@ You can also import specific functions and types from modules directly:
```v
import os { input }
import crypto.sha256 { sum }
import time { Time }
fn main() {
// read text from stdin
name := input('Enter your name: ')
println('Hello, $name!')
}
```
Note: This is not allowed for constants - they must always be prefixed.
@@ -1016,15 +1061,18 @@ match mut x {
### In operator
`in` allows to check whether an array or a map contains an element.
To do the opposite, use `!in`.
```v
nums := [1, 2, 3]
println(1 in nums) // true
m := {
println(4 !in nums) // true
m := map{
'one': 1
'two': 2
}
println('one' in m) // true
println('three' !in m) // true
```
It's also useful for writing boolean expressions that are clearer and more compact:
@@ -1057,7 +1105,12 @@ so both `if` statements above produce the same machine code and no arrays are cr
V has only one looping keyword: `for`, with several forms.
#### Array `for`
#### `for`/`in`
This is the most common form. You can use it with an array, map or
numeric range.
##### Array `for`
```v
numbers := [1, 2, 3, 4, 5]
@@ -1087,10 +1140,10 @@ println(numbers) // [1, 2, 3]
```
When an identifier is just a single underscore, it is ignored.
#### Map `for`
##### Map `for`
```v
m := {
m := map{
'one': 1
'two': 2
}
@@ -1103,7 +1156,7 @@ for key, value in m {
Either key or value can be ignored by using a single underscore as the identifier.
```v
m := {
m := map{
'one': 1
'two': 2
}
@@ -1121,7 +1174,7 @@ for _, value in m {
}
```
#### Range `for`
##### Range `for`
```v
// Prints '01234'
@@ -1454,7 +1507,7 @@ assert button.height == 20
As you can see, both the struct name and braces can be omitted, instead of:
```v ignore
```v oksyntax nofmt
new_button(ButtonConfig{text:'Click me', width:100})
```
@@ -1466,20 +1519,20 @@ Struct fields are private and immutable by default (making structs immutable as
Their access modifiers can be changed with
`pub` and `mut`. In total, there are 5 possible options:
```v nofmt
```v
struct Foo {
a int // private immutable (default)
a int // private immutable (default)
mut:
b int // private mutable
c int // (you can list multiple fields with the same access modifier)
b int // private mutable
c int // (you can list multiple fields with the same access modifier)
pub:
d int // public immutable (readonly)
d int // public immutable (readonly)
pub mut:
e int // public, but mutable only in parent module
e int // public, but mutable only in parent module
__global:
f int // public and mutable both inside and outside parent module
} // (not recommended to use, that's why the 'global' keyword
// starts with __)
// (not recommended to use, that's why the 'global' keyword starts with __)
f int // public and mutable both inside and outside parent module
}
```
For example, here's the `string` type defined in the `builtin` module:
@@ -1535,6 +1588,45 @@ In this example, the `can_register` method has a receiver of type `User` named `
The convention is not to use receiver names like `self` or `this`,
but a short, preferably one letter long, name.
## Unions
Just like structs, unions support embedding.
```v
struct Rgba32_Component {
r byte
g byte
b byte
a byte
}
union Rgba32 {
Rgba32_Component
value u32
}
clr1 := Rgba32{
value: 0x008811FF
}
clr2 := Rgba32{
Rgba32_Component: {
a: 128
}
}
sz := sizeof(Rgba32)
unsafe {
println('Size: ${sz}B,clr1.b: $clr1.b,clr2.b: $clr2.b')
}
```
Output: `Size: 4B, clr1.b: 136, clr2.b: 0`
Union member access must be performed in an `unsafe` block.
Note that the embedded struct arguments are not necessarily stored in the order listed.
## Functions 2
### Pure functions by default
@@ -1554,15 +1646,15 @@ intended for low-level applications like kernels and drivers.
It is possible to modify function arguments by using the keyword `mut`:
```v nofmt
```v
struct User {
name string
mut:
is_registered bool
is_registered bool
}
fn (mut u User) register() {
u.is_registered = true
u.is_registered = true
}
mut user := User{}
@@ -1600,6 +1692,8 @@ Only more complex types such as arrays and maps may be modified.
Use `user.register()` or `user = register(user)`
instead of `register(mut user)`.
#### Struct update syntax
V makes it easy to return a modified version of an object:
```v
@@ -1611,7 +1705,7 @@ struct User {
fn register(u User) User {
return {
u |
...u
is_registered: true
}
}
@@ -1631,11 +1725,16 @@ fn sqr(n int) int {
return n * n
}
fn cube(n int) int {
return n * n * n
}
fn run(value int, op fn (int) int) int {
return op(value)
}
fn main() {
// Functions can be passed to other functions
println(run(5, sqr)) // "25"
// Anonymous functions can be declared inside other functions:
double_fn := fn (n int) int {
@@ -1646,6 +1745,15 @@ fn main() {
res := run(5, fn (n int) int {
return n + n
})
println(res) // "10"
// You can even have an array/map of functions:
fns := [sqr, cube]
println(fns[0](10)) // "100"
fns_map := map{
'sqr': sqr
'cube': cube
}
println(fns_map['cube'](2)) // "8"
}
```
@@ -1699,7 +1807,7 @@ struct Node<T> {
## Constants
```v oksyntax
```v
const (
pi = 3.14
world = '世界'
@@ -1711,8 +1819,12 @@ println(world)
Constants are declared with `const`. They can only be defined
at the module level (outside of functions).
Constant values can never be changed. You can also declare a single
constant separately:
Constant values can never be changed.
```v
const e = 2.71828
```
V constants are more flexible than in most languages. You can assign more complex values:
@@ -1738,7 +1850,7 @@ const (
g: 0
b: 0
}
// evaluate function call at compile-time
// evaluate function call at compile-time*
blue = rgb(0, 0, 255)
)
@@ -1746,29 +1858,32 @@ println(numbers)
println(red)
println(blue)
```
\* WIP - for now function calls are evaluated at program start-up
Global variables are not allowed, so this can be really useful.
Global variables are not normally allowed, so this can be really useful.
### Required module prefix
When naming constants, `snake_case` must be used. In order to distinguish consts
from local variables, the full path to consts must be specified. For example,
to access the PI const, full `math.pi` name must be used both outside the `math`
module, and inside it. That restriction is relaxed only for the `main` module
(the one containing your `fn main()`, where you can use the shorter name of the
constants too, i.e. just `println(numbers)`, not `println(main.numbers)` .
module, and inside it. That restriction is relaxed only for the `main` module
(the one containing your `fn main()`), where you can use the unqualified name of
constants defined there, i.e. `numbers`, rather than `main.numbers`.
vfmt takes care of this rule, so you can type `println(pi)` inside the `math` module,
and vffmt will automatically update it to `println(math.pi)`.
and vfmt will automatically update it to `println(math.pi)`.
<!--
Many people prefer all caps consts: `TOP_CITIES`. This wouldn't work
well in V, because consts are a lot more powerful than in other languages.
They can represent complex structures, and this is used quite often since there
are no globals:
-->
```v ignore
println('Top cities: $top_cities.filter(.usa)')
```v oksyntax
println('Top cities: ${top_cities.filter(.usa)}')
```
-->
## Builtin functions
@@ -1789,15 +1904,21 @@ fn print_backtrace() // print backtraces on stderr
`println` is a simple yet powerful builtin function, that can print anything:
strings, numbers, arrays, maps, structs.
```v nofmt
struct User{ name string age int }
```v
struct User {
name string
age int
}
println(1) // "1"
println('hi') // "hi"
println([1,2,3]) // "[1, 2, 3]"
println(User{name:'Bob', age:20}) // "User{name:'Bob', age:20}"
println([1, 2, 3]) // "[1, 2, 3]"
println(User{ name: 'Bob', age: 20 }) // "User{name:'Bob', age:20}"
```
## Custom print of types
<a id='custom-print-of-types' />
## Printing custom types
If you want to define a custom print value for your type, simply define a
`.str() string` method:
@@ -2011,6 +2132,25 @@ color := Color.@none
println(color)
```
Integers may be assigned to enum fields.
```v
enum Grocery {
apple
orange = 5
pear
}
g1 := int(Grocery.apple)
g2 := int(Grocery.orange)
g3 := int(Grocery.pear)
println('Grocery IDs: $g1, $g2, $g3')
```
Output: `Grocery IDs: 0, 5, 6`.
Operations are not allowed on enum variables; they must be explicity cast to `int`.
### Sum types
A sum type instance can hold a value of several different types. Use the `type`
@@ -2111,10 +2251,10 @@ That's why you have to declare a `mut` before the `is` expression:
```v ignore
if mut w is Mars {
assert typeof(w).name == 'Mars'
if w.dust_storm() {
println('bad weather!')
}
assert typeof(w).name == 'Mars'
if w.dust_storm() {
println('bad weather!')
}
}
```
Otherwise `w` would keep its original type.
@@ -2436,7 +2576,7 @@ import time
fn task(id int, duration int, mut wg sync.WaitGroup) {
println('task $id begin')
time.sleep_ms(duration)
time.wait(duration * time.millisecond)
println('task $id end')
wg.done()
}
@@ -2627,7 +2767,7 @@ fn (shared b St) g() {
}
fn main() {
shared a := &St{ // create as reference so it's on the heap
shared a := St{
x: 10
}
go a.g()
@@ -2637,6 +2777,7 @@ fn main() {
}
}
```
Shared variables must be structs, arrays or maps.
## Decoding JSON
@@ -3036,8 +3177,8 @@ println(qux)
## sizeof and __offsetof
V supports the usage of `sizeof` to calculate sizes of structs and
`__offsetof` to calculate struct field offsets.
* `sizeof(Type)` gives the size of a type in bytes.
* `__offsetof(Struct, field_name)` gives the offset in bytes of a struct field.
```v
struct Foo {
@@ -3045,9 +3186,9 @@ struct Foo {
b int
}
println(sizeof(Foo))
println(__offsetof(Foo, a))
println(__offsetof(Foo, b))
assert sizeof(Foo) == 8
assert __offsetof(Foo, a) == 0
assert __offsetof(Foo, b) == 4
```
## Calling C functions from V
@@ -3230,7 +3371,7 @@ To cast a `voidptr` to a V reference, use `user := &User(user_void_ptr)`.
`voidptr` can also be dereferenced into a V struct through casting: `user := User(user_void_ptr)`.
[socket.v has an example which calls C code from V](https://github.com/vlang/v/blob/master/vlib/net/socket.v) .
[an example of a module that calls C code from V](https://github.com/vlang/v/blob/master/vlib/v/tests/project_with_c_code/mod1/wrapper.v)
## Debugging generated C code
@@ -3346,6 +3487,56 @@ executable, increasing your binary size, but making it more self contained
and thus easier to distribute. In this case, `f.data()` will cause *no IO*,
and it will always return the same data.
#### $tmpl for embedding and parsing V template files
V has a simple template language for text and html templates, and they can easily
be embedded via `$tmpl('path/to/template.txt')`:
```v ignore
fn build() string {
name := 'Peter'
age := 25
numbers := [1, 2, 3]
return $tmpl('1.txt')
}
fn main() {
println(build())
}
```
1.txt:
```
name: @name
age: @age
numbers: @numbers
@for number in numbers
@number
@end
```
output:
```
name: Peter
age: 25
numbers: [1, 2, 3]
1
2
3
```
#### $env
```v
@@ -3413,7 +3604,7 @@ single block. `customflag` should be a snake_case identifier, it can not
contain arbitrary characters (only lower case latin letters + numbers + `_`).
NB: a combinatorial `_d_customflag_linux.c.v` postfix will not work.
If you do need a custom flag file, that has platform dependent code, use the
postfix `_d_customflag.v`, and then use plaftorm dependent compile time
postfix `_d_customflag.v`, and then use plaftorm dependent compile time
conditional blocks inside it, i.e. `$if linux {}` etc.
## Compile time pseudo variables
@@ -3422,6 +3613,7 @@ V also gives your code access to a set of pseudo string variables,
that are substituted at compile time:
- `@FN` => replaced with the name of the current V function
- `@METHOD` => replaced with ReceiverType.MethodName
- `@MOD` => replaced with the name of the current V module
- `@STRUCT` => replaced with the name of the current V struct
- `@FILE` => replaced with the path of the V source file
@@ -3556,7 +3748,8 @@ To improve safety and maintainability, operator overloading is limited:
- `==` and `!=` are self generated by the compiler but can be overriden.
- Calling other functions inside operator functions is not allowed.
- Operator functions can't modify their arguments.
- When using `<`, `>`, `>=`, `<=`, `==` and `!=` operators, the return type must be `bool`.
- When using `<` and `==` operators, the return type must be `bool`.
- `!=`, `>`, `<=` and `>=` are auto generated when `==` and `<` are defined.
- Both arguments must have the same type (just like with all operators in V).
- Assignment operators (`*=`, `+=`, `/=`, etc)
are auto generated when the operators are defined though they must return the same type.
@@ -3648,7 +3841,7 @@ fn print_message() {
fn main() {
for {
print_message()
time.sleep_ms(500)
time.wait(500 * time.millisecond)
}
}
```
@@ -3693,27 +3886,42 @@ The advantage of using V for this is the simplicity and predictability of the la
cross-platform support. "V scripts" run on Unix-like systems as well as on Windows.
Use the `.vsh` file extension. It will make all functions in the `os`
module global (so that you can use `ls()` instead of `os.ls()`, for example).
module global (so that you can use `mkdir()` instead of `os.mkdir()`, for example).
An example `deploy.vsh`:
```v wip
#!/usr/local/bin/v run
// The shebang above associates the file to V on Unix-like systems,
// so it can be run just by specifying the path to the file
// once it's made executable using `chmod +x`.
rm('build/*')
// Same as:
for file in ls('build/') {
rm(file)
}
// Remove if build/ exits, ignore any errors if it doesn't
rmdir_all('build') or { }
mv('*.v', 'build/')
// Same as:
for file in ls('.') {
if file.ends_with('.v') {
mv(file, 'build/')
}
// Create build/, never fails as build/ does not exist
mkdir('build') ?
// Move *.v files to build/
result := exec('mv *.v build/') ?
if result.exit_code != 0 {
println(result.output)
}
// Similar to:
// files := ls('.') ?
// mut count := 0
// if files.len > 0 {
// for file in files {
// if file.ends_with('.v') {
// mv(file, 'build/') or {
// println('err: $err')
// return
// }
// }
// count++
// }
// }
// if count == 0 {
// println('No files')
// }
```
Now you can either compile this like a normal V program and get an executable you can deploy and run
@@ -3730,8 +3938,8 @@ On Unix-like platforms, the file can be run directly after making it executable
V has several attributes that modify the behavior of functions and structs.
An attribute is specified inside `[]` right before a function/struct declaration
and applies only to the following declaration.
An attribute is a compiler instruction specified inside `[]` right before a
function/struct/enum declaration and applies only to the following declaration.
```v
// Calling this function will result in a deprecation warning
@@ -3744,8 +3952,9 @@ fn old_function() {
fn inlined_function() {
}
// The following struct can only be used as a reference (`&Window`) and allocated on the heap.
[ref_only]
// The following struct must be allocated on the heap. Therefore, it can only be used as a
// reference (`&Window`) or inside another reference (`&OuterStruct{ Window{...} }`).
[heap]
struct Window {
}
@@ -3767,8 +3976,39 @@ struct C.Foo {
// Used in Win32 API code when you need to pass callback function
[windows_stdcall]
fn C.DefWindowProc(hwnd int, msg int, lparam int, wparam int)
// Windows only:
// If a default graphics library is imported (ex. gg, ui), then the graphical window takes
// priority and no console window is created, effectively disabling println() statements.
// Use to explicity create console window. Valid before main() only.
[console]
fn main() {
}
```
## Goto
V allows unconditionally jumping to a label with `goto`. The label name must be contained
within the same function as the `goto` statement. A program may `goto` a label outside
or deeper than the current scope. `goto` allows jumping past variable initialization or
jumping back to code that accesses memory that has already been freed, so it requires
`unsafe`.
```v ignore
if x {
// ...
if y {
unsafe {
goto my_label
}
}
// ...
}
my_label:
```
`goto` should be avoided, particularly when `for` can be used instead.
[Labelled break/continue](#labelled-break--continue) can be used to break out of
a nested loop, and those do not risk violating memory-safety.
# Appendices

View File

@@ -131,12 +131,12 @@ fn i(atomic x u64) {...}
a := St{...}
f(a)
mut b := &St{...} // reference since transferred to coroutine
mut b := St{...}
f(b)
go g(mut b)
// `b` should not be accessed here any more
shared c := &St{...}
shared c := St{...}
h(shared c)
atomic d &u64
@@ -146,7 +146,7 @@ i(atomic d)
Inside a `lock c {...}` block `c` behaves like a `mut`,
inside an `rlock c {...}` block like an immutable:
```v ignore
shared c := &St{...}
shared c := St{...}
lock c {
g(mut c)
f(c)
@@ -166,14 +166,14 @@ block. However in simple and obvious cases the necessary lock/unlock
can be generated automatically for `array`/`map` operations:
```v ignore
shared a []int{...}
shared a := []int{cap: 5}
go h2(shared a)
a << 3
// keep in mind that `h2()` could change `a` between these statements
a << 4
x := a[1] // not necessarily `4`
shared b map[string]int
shared b := map[string]int{}
go h3(shared b)
b['apple'] = 3
c['plume'] = 7

View File

@@ -3,7 +3,6 @@ import gx
import math
import os
import rand
import sokol.sapp
import time
struct App {
@@ -66,7 +65,7 @@ const (
gx.rgb(237, 204, 97), /* 256 */
gx.rgb(237, 200, 80), /* 512 */
gx.rgb(237, 197, 63), /* 1024 */
gx.rgb(237, 194, 46), /* 2048 */
gx.rgb(237, 194, 46),
]
},
&Theme{
@@ -348,11 +347,10 @@ fn (mut b Board) is_game_over() bool {
// there are remaining zeros
return false
}
if (x > 0 && fidx == b.field[y][x - 1]) ||
(x < 4 - 1 && fidx == b.field[y][x + 1]) ||
(y > 0 && fidx == b.field[y - 1][x]) ||
(y < 4 - 1 && fidx == b.field[y + 1][x])
{
if (x > 0 && fidx == b.field[y][x - 1])
|| (x < 4 - 1 && fidx == b.field[y][x + 1])
|| (y > 0 && fidx == b.field[y - 1][x])
|| (y < 4 - 1 && fidx == b.field[y + 1][x]) {
// there are remaining merges
return false
}
@@ -530,48 +528,52 @@ fn (mut app App) ai_move() {
fn (app &App) label_format(kind LabelKind) gx.TextCfg {
match kind {
.points { return {
color: if app.state in [.over, .victory] {
gx.white
} else {
app.theme.text_color
}
.points {
return {
color: if app.state in [.over, .victory] { gx.white } else { app.theme.text_color }
align: .left
size: app.ui.font_size / 2
} }
.moves { return {
color: if app.state in [.over, .victory] {
gx.white
} else {
app.theme.text_color
}
}
}
.moves {
return {
color: if app.state in [.over, .victory] { gx.white } else { app.theme.text_color }
align: .right
size: app.ui.font_size / 2
} }
.tile { return {
}
}
.tile {
return {
color: app.theme.text_color
align: .center
vertical_align: .middle
size: app.ui.font_size
} }
.victory { return {
}
}
.victory {
return {
color: app.theme.victory_color
align: .center
vertical_align: .middle
size: app.ui.font_size * 2
} }
.game_over { return {
}
}
.game_over {
return {
color: app.theme.game_over_color
align: .center
vertical_align: .middle
size: app.ui.font_size * 2
} }
.score_end { return {
}
}
.score_end {
return {
color: gx.white
align: .center
vertical_align: .middle
size: app.ui.font_size * 3 / 4
} }
}
}
}
}
@@ -584,12 +586,13 @@ fn (mut app App) set_theme(idx int) {
}
fn (mut app App) resize() {
mut s := sapp.dpi_scale()
mut s := gg.dpi_scale()
if s == 0.0 {
s = 1.0
}
w := int(sapp.width() / s)
h := int(sapp.height() / s)
window_size := gg.window_size()
w := window_size.width
h := window_size.height
m := f32(min(w, h))
app.ui.dpi_scale = s
app.ui.window_width = w
@@ -790,11 +793,7 @@ fn (mut app App) handle_swipe() {
[inline]
fn (mut app App) next_theme() {
app.set_theme(if app.theme_idx == themes.len - 1 {
0
} else {
app.theme_idx + 1
})
app.set_theme(if app.theme_idx == themes.len - 1 { 0 } else { app.theme_idx + 1 })
}
[inline]
@@ -815,7 +814,7 @@ fn (mut app App) undo() {
}
}
fn (mut app App) on_key_down(key sapp.KeyCode) {
fn (mut app App) on_key_down(key gg.KeyCode) {
// these keys are independent from the game state:
match key {
.a { app.is_ai_mode = !app.is_ai_mode }
@@ -843,7 +842,7 @@ fn (mut app App) on_key_down(key sapp.KeyCode) {
}
}
fn on_event(e &sapp.Event, mut app App) {
fn on_event(e &gg.Event, mut app App) {
match e.typ {
.key_down {
app.on_key_down(e.key_code)
@@ -957,7 +956,7 @@ fn main() {
bg_color: app.theme.bg_color
width: default_window_width
height: default_window_height
sample_count: 8 // higher quality curves
sample_count: 4 // higher quality curves
create_window: true
window_title: window_title_
frame_fn: frame

View File

@@ -5,17 +5,15 @@ import io
fn main() {
// Make a new connection
mut conn := net.dial_tcp('google.com:80')?
mut conn := net.dial_tcp('google.com:80') ?
// Simple http HEAD request for a file
conn.write_str('GET /index.html HTTP/1.0\r\n\r\n')?
conn.write_str('GET /index.html HTTP/1.0\r\n\r\n') ?
// Wrap in a buffered reader
mut r := io.new_buffered_reader(reader: io.make_reader(conn))
for {
l := r.read_line() or {
break
}
l := r.read_line() or { break }
println('$l')
// Make it nice and obvious that we are doing this line by line
time.sleep_ms(10)
time.wait(100 * time.millisecond)
}
}
}

View File

@@ -32,17 +32,17 @@ fn main() {
description: 'Number of times the message gets printed.'
})
greet_cmd.add_flag(Flag{
flag: .string
name: 'fun'
multipe: true
description: 'Just a dumby flags to show multiple.'
flag: .string
name: 'fun'
multiple: true
description: 'Just a dumby flags to show multiple.'
})
cmd.add_command(greet_cmd)
cmd.setup()
cmd.parse(os.args)
}
fn greet_func(cmd Command) {
fn greet_func(cmd Command) ? {
language := cmd.flags.get_string('language') or {
panic('Failed to get `language` flag: $err')
}
@@ -76,10 +76,10 @@ fn greet_func(cmd Command) {
}
}
fn greet_pre_func(cmd Command) {
fn greet_pre_func(cmd Command) ? {
println('This is a function running before the main function.\n')
}
fn greet_post_func(cmd Command) {
fn greet_post_func(cmd Command) ? {
println('\nThis is a function running after the main function.')
}

View File

@@ -4,7 +4,7 @@ import time
// Simulate expensive computing using sleep function
fn expensive_computing(id int, duration int, mut wg sync.WaitGroup) {
println('Executing expensive computing task ($id)...')
time.sleep_ms(duration)
time.wait(duration * time.millisecond)
println('Finish task $id on $duration ms')
wg.done()
}

44
examples/database/orm.v Normal file
View File

@@ -0,0 +1,44 @@
import sqlite
struct Module {
id int
name string
nr_downloads int
creator User
}
struct User {
id int
age int
name string
is_customer bool
skipped_string string [skip]
}
fn main() {
db := sqlite.connect(':memory:') or { panic(err) }
db.exec('drop table if exists User')
db.exec("create table Module (id integer primary key, name text default '', nr_downloads int default 0, creator int default 0);")
db.exec("create table User (id integer primary key, age int default 0, name text default '', is_customer int default 0);")
mod := Module{
name: 'test'
nr_downloads: 10
creator: User{
age: 21
name: 'VUser'
is_customer: true
}
}
sql db {
insert mod into Module
}
modul := sql db {
select from Module where id == 1
}
println(modul.name)
println(modul.creator.name)
}

View File

@@ -2,6 +2,8 @@ module main
import pg
const dash = '----------------------------------------------------------------'
struct Customer {
id int
name string
@@ -24,27 +26,27 @@ fn main() {
println('Total customers: $nr_customers')
// V syntax can be used to build queries
println('----------------------------------------------------------------')
println(dash)
bg_country := 'Bulgaria'
bg_customers := db.select from Customer where country == bg_country && id != 2
for customer in bg_customers {
println('$customer.country | $customer.id - $customer.name')
}
println('----------------------------------------------------------------')
println(dash)
ru_customers := db.select from Customer where country == 'Russia'
for customer in ru_customers {
println('$customer.country | $customer.id - $customer.name')
}
// by adding `limit 1` we tell V that there will be only one object
println('----------------------------------------------------------------')
println(dash)
existing := db.select from Customer where id == 1 limit 1 or { panic(err) }
println('Existing customer name: $existing.name')
println('Existing customer full information:')
println(existing)
println('------------------------------------------------------------------------')
println(dash)
q := Customer{}
// It's easy to handle queries that don't return any data
if anon := db.select from Customer where id == 12345 && name == q.name &&

View File

@@ -3,7 +3,6 @@ import objects
import gg
import gx
import rand
import sokol.sapp
struct App {
mut:
@@ -56,7 +55,7 @@ fn on_frame(mut app App) {
app.gg.end()
}
fn on_event(e &sapp.Event, mut app App) {
fn on_event(e &gg.Event, mut app App) {
match e.typ {
.resized, .restored, .resumed { app.resize() }
else {}
@@ -64,15 +63,14 @@ fn on_event(e &sapp.Event, mut app App) {
}
fn (mut app App) resize() {
mut s := sapp.dpi_scale()
mut s := gg.dpi_scale()
if s == 0.0 {
s = 1.0
}
w := int(sapp.width() / s)
h := int(sapp.height() / s)
size := gg.window_size()
app.ui.dpi_scale = s
app.ui.width = w
app.ui.height = h
app.ui.width = size.width
app.ui.height = size.height
}
fn main() {

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 382 B

After

Width:  |  Height:  |  Size: 382 B

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,7 +1,6 @@
module main
import gg
import sokol.sapp
import gx
import os
import time
@@ -16,10 +15,10 @@ const (
struct Bird {
mut:
x f64 = 80
y f64 = 250
width f64 = 40
height f64 = 30
x f64 = 80
y f64 = 250
width f64 = 40
height f64 = 30
alive bool = true
gravity f64
velocity f64 = 0.3
@@ -40,8 +39,8 @@ fn (b Bird) is_dead(height f64, pipes []Pipe) bool {
return true
}
for pipe in pipes {
if !(b.x > pipe.x + pipe.width ||
b.x + b.width < pipe.x || b.y > pipe.y + pipe.height || b.y + b.height < pipe.y) {
if !(b.x > pipe.x + pipe.width || b.x + b.width < pipe.x || b.y > pipe.y + pipe.height
|| b.y + b.height < pipe.y) {
return true
}
}
@@ -153,8 +152,8 @@ fn (mut app App) update() {
if app.interval == 0 {
delta_bord := f64(50)
pipe_holl := f64(120)
holl_position := math.round(rand.f64() *
(app.height - delta_bord * 2.0 - pipe_holl)) + delta_bord
holl_position := math.round(rand.f64() * (app.height - delta_bord * 2.0 - pipe_holl)) +
delta_bord
app.pipes << Pipe{
x: app.width
y: 0
@@ -178,6 +177,10 @@ fn main() {
mut app := &App{
gg: 0
}
mut font_path := os.resource_abs_path(os.join_path('../assets/fonts/', 'RobotoMono-Regular.ttf'))
$if android {
font_path = 'fonts/RobotoMono-Regular.ttf'
}
app.gg = gg.new_context(
bg_color: gx.white
width: win_width
@@ -189,7 +192,7 @@ fn main() {
event_fn: on_event
user_data: app
init_fn: init_images
font_path: os.resource_abs_path('../assets/fonts/RobotoMono-Regular.ttf')
font_path: font_path
)
app.nv = neuroevolution.Generations{
population: 50
@@ -203,15 +206,26 @@ fn main() {
fn (mut app App) run() {
for {
app.update()
time.sleep_ms(app.timer_period_ms)
time.wait(app.timer_period_ms * time.millisecond)
}
}
fn init_images(mut app App) {
app.background = app.gg.create_image(os.resource_abs_path('./img/background.png'))
app.bird = app.gg.create_image(os.resource_abs_path('./img/bird.png'))
app.pipetop = app.gg.create_image(os.resource_abs_path('./img/pipetop.png'))
app.pipebottom = app.gg.create_image(os.resource_abs_path('./img/pipebottom.png'))
$if android {
background := os.read_apk_asset('img/background.png') or { panic(err) }
app.background = app.gg.create_image_from_byte_array(background)
bird := os.read_apk_asset('img/bird.png') or { panic(err) }
app.bird = app.gg.create_image_from_byte_array(bird)
pipetop := os.read_apk_asset('img/pipetop.png') or { panic(err) }
app.pipetop = app.gg.create_image_from_byte_array(pipetop)
pipebottom := os.read_apk_asset('img/pipebottom.png') or { panic(err) }
app.pipebottom = app.gg.create_image_from_byte_array(pipebottom)
} $else {
app.background = app.gg.create_image(os.resource_abs_path('assets/img/background.png'))
app.bird = app.gg.create_image(os.resource_abs_path('assets/img/bird.png'))
app.pipetop = app.gg.create_image(os.resource_abs_path('assets/img/pipetop.png'))
app.pipebottom = app.gg.create_image(os.resource_abs_path('assets/img/pipebottom.png'))
}
}
fn frame(app &App) {
@@ -251,13 +265,13 @@ fn (app &App) draw() {
app.display()
}
fn on_event(e &sapp.Event, mut app App) {
fn on_event(e &gg.Event, mut app App) {
if e.typ == .key_down {
app.key_down(e.key_code)
}
}
fn (mut app App) key_down(key sapp.KeyCode) {
fn (mut app App) key_down(key gg.KeyCode) {
// global keys
match key {
.escape {

View File

@@ -20,6 +20,6 @@ fn main() {
for {
a.update()
print_automaton(a)
time.sleep_ms(100)
time.wait(100 * time.millisecond)
}
}

34
examples/gg/polygons.v Normal file
View File

@@ -0,0 +1,34 @@
module main
import gg
import gx
struct App {
mut:
gg &gg.Context
}
fn main() {
mut app := &App{
gg: 0
}
app.gg = gg.new_context(
bg_color: gx.rgb(174, 198, 255)
width: 600
height: 400
window_title: 'Polygons'
frame_fn: frame
user_data: app
)
app.gg.run()
}
fn frame(mut app App) {
app.gg.begin()
app.gg.draw_convex_poly([f32(100.0), 100.0, 200.0, 100.0, 300.0, 200.0, 200.0, 300.0, 100.0,
300.0,
], gx.blue)
app.gg.draw_empty_poly([f32(50.0), 50.0, 70.0, 60.0, 90.0, 80.0, 70.0, 110.0], gx.black)
app.gg.draw_triangle(450, 142, 530, 280, 370, 280, gx.red)
app.gg.end()
}

View File

@@ -8,20 +8,20 @@ import time
struct Game {
mut:
gg &gg.Context
x int
y int
dy int
dx int
height int
width int
draw_fn voidptr
gg &gg.Context
x int
y int
dy int
dx int
height int
width int
draw_fn voidptr
}
const (
window_width = 400
window_width = 400
window_height = 300
width = 50
width = 50
)
fn main() {
@@ -33,7 +33,7 @@ fn main() {
width: window_width
draw_fn: 0
}
game.gg = gg.new_context({
game.gg = gg.new_context(
width: window_width
height: window_height
font_size: 20
@@ -44,22 +44,22 @@ fn main() {
frame_fn: frame
bg_color: gx.white
font_path: gg.system_font_path()
})
)
// window.onkeydown(key_down)
println('Starting the game loop...')
go game.run()
game.gg.run()
}
// Try uncommenting or changing the lines inside the live functions.
// Guess what will happen:
[live]
fn frame (mut game Game) {
fn frame(mut game Game) {
game.gg.begin()
game.gg.draw_text_def(10, 5, 'Modify examples/hot_reload/bounce.v to get instant updates')
game.gg.draw_rect(game.x, game.y, width, width, gx.blue)
game.gg.draw_rect(window_width - width - game.x + 10, 200 - game.y + width, width, width, gx.rgb(228, 10, 55))
game.gg.draw_rect(window_width - width - game.x + 10, 200 - game.y + width, width,
width, gx.rgb(228, 10, 55))
game.gg.draw_rect(game.x - 25, 250 - game.y, width, width, gx.rgb(28, 240, 55))
game.gg.end()
}
@@ -80,10 +80,6 @@ fn (mut game Game) update_model() {
fn (mut game Game) run() {
for {
game.update_model()
//glfw.post_empty_event() // Refresh
time.sleep_ms(17) // 60fps
time.wait(16 * time.millisecond) // 60fps
}
}

View File

@@ -2,7 +2,6 @@ module main
import gx
import gg
import sokol.sapp
import time
import math
@@ -20,7 +19,7 @@ fn main() {
mut context := &Context{
gg: 0
}
context.gg = gg.new_context({
context.gg = gg.new_context(
width: size
height: size
font_size: 20
@@ -32,7 +31,7 @@ fn main() {
resizable: true
bg_color: gx.white
font_path: gg.system_font_path()
})
)
context.gg.run()
}
@@ -44,34 +43,45 @@ fn frame(mut ctx Context) {
[live]
fn (ctx &Context) draw() {
mut w := sapp.width()
mut h := sapp.height()
if sapp.high_dpi() {
s := gg.window_size()
mut w := s.width
mut h := s.height
if gg.high_dpi() {
w /= 2
h /= 2
}
ctx.gg.draw_line(0, h/2, w, h/2, gx.gray) // x axis
ctx.gg.draw_line(w/2, 0, w/2, h, gx.gray) // y axis
ctx.gg.draw_line(0, h / 2, w, h / 2, gx.gray) // x axis
ctx.gg.draw_line(w / 2, 0, w / 2, h, gx.gray) // y axis
atime := f64(time.ticks() / 10)
stime := math.sin(2.0 * math.pi * f64(time.ticks() % 6000) / 6000)
mut y := 0.0
blue := gx.Color {r:100, g:100, b:200}
red := gx.Color {r:200, g:100, b:100}
blue := gx.Color{
r: 100
g: 100
b: 200
}
red := gx.Color{
r: 200
g: 100
b: 100
}
y = 1.0
max := f32(w)/(2*scale)
max := f32(w) / (2 * scale)
min := -max
for x := min; x <= max; x += 0.01 {
// y = x*x + 2
// y = x * x + stime * stime
// y = stime
// y = stime * h
y = stime * 1.0 * math.sin((x) + stime + atime / 32) * ((h/256) + x)
y = stime * 1.0 * math.sin((x) + stime + atime / 32) * ((h / 256) + x)
// y = (stime * x) * x + stime
// y = (x + 3) * (x + 3) / stime + stime*2.5
// y = math.sqrt(30.0 - x * x) * stime
// y -= (stime-0.5) + stime
// ctx.gg.draw_rect(f32((w/2) + x * scale), f32((h/2) - y * scale), 2, 2, blue)
ctx.gg.draw_rect(f32((w/2) + x * scale), f32((h/2) - y * scale), 2, (f32(y) * scale), blue)
ctx.gg.draw_rect(f32((w/2) + x * scale), f32((h/2) + y * scale), 2, (f32(y) * scale) + 32, red)
ctx.gg.draw_rect(f32((w / 2) + x * scale), f32((h / 2) - y * scale), 2, (f32(y) * scale),
blue)
ctx.gg.draw_rect(f32((w / 2) + x * scale), f32((h / 2) + y * scale), 2, (f32(y) * scale) +
32, red)
}
}

View File

@@ -13,6 +13,6 @@ fn print_message() {
fn main() {
for {
print_message()
time.sleep_ms(500)
time.wait(500 * time.millisecond)
}
}

View File

@@ -8,6 +8,7 @@ struct Moon {
struct Mars {
}
fn (m Mars) dust_storm() bool {
return rand.int() >= 0
}
@@ -15,10 +16,11 @@ fn (m Mars) dust_storm() bool {
struct Venus {
}
type World = Moon | Mars | Venus
type World = Mars | Moon | Venus
struct Lander {
}
fn (l Lander) deorbit() {
println('leaving orbit')
}
@@ -28,7 +30,7 @@ fn (l Lander) open_parachutes(n int) {
fn wait() {
println('waiting...')
time.sleep(1)
time.wait(1 * time.second)
}
fn (l Lander) land(w World) {
@@ -53,7 +55,7 @@ fn (l Lander) land(w World) {
}
fn main() {
l := Lander {}
l := Lander{}
l.land(Venus{})
l.land(Mars{})
}

View File

@@ -0,0 +1,44 @@
import os
import os.cmdline
import net
fn main() {
println('Usage: net_udp_server_and_client [-l] [-p 5000]')
println(' -l - act as a server and listen')
println(' -p XXXX - custom port number')
println('------------------------------------------')
is_server := '-l' in os.args
port := cmdline.option(os.args, '-p', '40001').int()
mut buf := []byte{len: 100}
if is_server {
println('UDP echo server, listening for udp packets on port: $port')
mut c := net.listen_udp(port) ?
for {
read, addr := c.read(mut buf) or { continue }
println('received $read bytes from $addr')
c.write_to(addr, buf[..read]) or {
println('Server: connection dropped')
continue
}
}
} else {
println('UDP client, sending packets to port: ${port}.\nType `exit` to exit.')
mut c := net.dial_udp('localhost', 'localhost:$port') ?
for {
mut line := os.input('client > ')
match line {
'' {
line = '\n'
}
'exit' {
println('goodbye.')
exit(0)
}
else {}
}
c.write_str(line) ?
read, _ := c.read(mut buf) ?
println('server : ' + buf[0..read].bytestr())
}
}
}

View File

@@ -3,25 +3,25 @@
// that can be found in the LICENSE file.
import net.http
import json
import sync
import sync.pool
struct Story {
title string
url string
}
fn worker_fetch(p &sync.PoolProcessor, cursor int, worker_id int) voidptr {
id := p.get_int_item(cursor)
fn worker_fetch(p &pool.PoolProcessor, cursor int, worker_id int) voidptr {
id := p.get_item<int>(cursor)
resp := http.get('https://hacker-news.firebaseio.com/v0/item/${id}.json') or {
println('failed to fetch data from /v0/item/${id}.json')
return sync.no_result
return pool.no_result
}
story := json.decode(Story,resp.text) or {
story := json.decode(Story, resp.text) or {
println('failed to decode a story')
return sync.no_result
return pool.no_result
}
println('# $cursor) $story.title | $story.url')
return sync.no_result
return pool.no_result
}
// Fetches top HN stories in parallel, depending on how many cores you have
@@ -30,20 +30,20 @@ fn main() {
println('failed to fetch data from /v0/topstories.json')
return
}
mut ids := json.decode([]int,resp.text) or {
mut ids := json.decode([]int, resp.text) or {
println('failed to decode topstories.json')
return
}
if ids.len > 10 {
ids = ids[0..10]
}
mut fetcher_pool := sync.new_pool_processor({
mut fetcher_pool := pool.new_pool_processor(
callback: worker_fetch
})
)
// NB: if you do not call set_max_jobs, the pool will try to use an optimal
// number of threads, one per each core in your system, which in most
// cases is what you want anyway... You can override the automatic choice
// by setting the VJOBS environment variable too.
// fetcher_pool.set_max_jobs( 4 )
fetcher_pool.work_on_items_i(ids)
fetcher_pool.work_on_items(ids)
}

1
examples/process/.ignore Normal file
View File

@@ -0,0 +1 @@
command

View File

@@ -0,0 +1,34 @@
module main
import os
// basic example which shows how to use the Command function
fn exec(path string) string {
mut out := ''
mut line := ''
mut cmd := os.Command{
path: path
}
cmd.start() or { panic(err) }
for {
line = cmd.read_line()
println(line)
out += line
if cmd.eof {
return out
}
}
return out
}
fn main() {
mut out := ''
exec("bash -c 'find /tmp/'")
out = exec('echo to stdout')
out = exec('echo to stderr 1>&2')
println("'$out'")
// THIS DOES NOT WORK, is error, it goes to stderror of the command I run
assert out == 'to stderr'
}

17
examples/process/execve.v Normal file
View File

@@ -0,0 +1,17 @@
module main
import os
fn exec(args []string) {
os.execve('/bin/bash', args, []) or {
// eprintln(err)
panic(err)
}
}
fn main() {
// exec(["-c","find /"]) //works
exec(['-c', 'find /tmp/']) // here it works as well
// exec(["-c","find","/tmp/"]) // does not work I guess is normal
}

View File

@@ -0,0 +1,59 @@
module main
import os
// a test where we execute a bash script but work around where we put script in bash inside bash
fn exec(path string, redirect bool) {
mut line := ''
mut line_err := ''
mut cmd := os.new_process('/bin/bash')
if redirect {
cmd.set_args(['-c', '/bin/bash /tmp/test.sh 2>&1'])
} else {
cmd.set_args([path])
}
cmd.set_redirect_stdio()
cmd.run()
if cmd.is_alive() {
for {
line = cmd.stdout_read()
println('STDOUT: $line')
if !redirect {
line_err = cmd.stderr_read()
println('STDERR: $line_err')
}
if !cmd.is_alive() {
break
}
}
}
if cmd.code > 0 {
println('ERROR:')
println(cmd)
// println(cmd.stderr_read())
}
}
fn main() {
script := '
echo line 1
#will use some stderr now
echo redirect 1 to 2 1>&2
echo line 3
'
os.write_file('/tmp/test.sh', script) or { panic(err) }
// os.chmod("/tmp/test.sh",0o700) //make executable
// this will work because stderr/stdout are smaller than 4096 chars, once larger there can be deadlocks
// in other words this can never work reliably without being able to check if there is data on stderr or stdout
exec('/tmp/test.sh', false)
// this will always work
exec('/tmp/test.sh', true)
}

View File

@@ -0,0 +1,83 @@
module main
import os
// this is a example script to show you stdin can be used and keep a process open
fn exec(cmd string) (string, int) {
mut cmd2 := cmd
mut out := ''
mut line := ''
mut rc := 0
mut p := os.new_process('/bin/bash')
// there are methods missing to know if stderr/stdout has data as such its better to redirect bot on same FD
// not so nice trick to run bash in bash and redirect stderr, maybe someone has a better solution
p.set_args(['-c', 'bash 2>&1'])
p.set_redirect_stdio()
p.run()
if !cmd2.ends_with('\n') {
cmd2 += '\n'
}
p.stdin_write(cmd2)
p.stdin_write('\necho **OK**\n')
for {
if !p.is_alive() {
break
}
line = p.stdout_read()
println(line)
// line_err = p.stderr_read() //IF WE CALL STDERR_READ will block
// we need a mechanism which allows us to check if stderr/stdout has data or it should never block
// is not a good way, need to use a string buffer, is slow like this
out += line
if out.ends_with('**OK**\n') {
out = out[0..(out.len - 7)]
break
}
}
// println("read from stdout, should not block")
// is not really needed but good test to see behaviour
// out += p.stdout_read()
// println("read done")
// println(cmd.stderr_read())
if p.code > 0 {
rc = 1
println('ERROR:')
println(cmd2)
print(out)
}
// documentation says we need to call p.wait(), but this does not seem to work, will be process stop or become zombie?
// p.wait()
return out, rc
}
fn main() {
mut out := ''
mut rc := 0
// the following does not work, not sure why not
// out,rc = exec("find /tmp/ && echo '******'")
out, rc = exec("find /tmp/ ; echo '******'")
println(out)
assert out.ends_with('******\n')
out, rc = exec('echo to stdout')
assert out.contains('to stdout')
out, rc = exec('echo to stderr 1>&2')
assert out.contains('to stderr')
out, rc = exec('ls /sssss')
assert rc > 0 // THIS STILL GIVES AN ERROR !
println('test ok stderr & stdout is indeed redirected')
}

69
examples/regex/pcre.vv Normal file
View File

@@ -0,0 +1,69 @@
module main
// NB: you need to `v install pcre` to be able to compile this example.
import pcre
fn example() {
r := pcre.new_regex('Match everything after this: (.+)', 0) or {
println('An error occured!')
return
}
m := r.match_str('Match everything after this: "I VLang!"', 0, 0) or {
println('No match!')
return
}
// m.get(0) -> Match everything after this: "I ❤️ VLang!"
// m.get(1) -> "I ❤️ VLang!"'
// m.get(2) -> Error!
whole_match := m.get(0) or {
println('We matched nothing...')
return
}
matched_str := m.get(1) or {
println('We matched nothing...')
return
}
println(whole_match) // Match everything after this: "I ❤️ VLang!"
println(matched_str) // "I ❤️ VLang!"
}
fn main() {
example()
mut text := '[ an s. s! ]( wi4ki:something )
[ an s. s! ]( wi4ki:something )
[ an s. s! ](wiki:something)
[ an s. s! ](something)dd
d [ an s. s! ](something ) d
[ more text ]( something ) s [ something b ](something)dd
'
// check the regex on https://regex101.com/r/HdYya8/1/
regex := r'(\[[a-z\.\! ]*\]\( *\w*\:*\w* *\))*'
r := pcre.new_regex(regex, 0) or {
println('An error occured!')
return
}
m := r.match_str(text, 0, 0) or {
println('No match!')
return
}
whole_match1 := m.get(0) or {
println('We matched nothing 0...')
return
}
println(whole_match1)
println(m.get_all())
}

8
examples/regex/readme.md Normal file
View File

@@ -0,0 +1,8 @@
# regex
There are 2 ways to do regex:
a) using the native module called `regex`
b) using an exteranl module called `pcre`, which wraps the C library pcre.
NB: you need to first do: `v install pcre`, for the `pcre` module to work.
You can find examples of both in this directory.

View File

@@ -23,18 +23,18 @@ fn convert_html_rgb(in_col string) u32 {
// NOTE: if you want use escaped code you must use the r"" (raw) strings,
// *** please remember that V interpoaltion doesn't work on raw strings. ***
query:= "#([a-fA-F0-9]{$n_digit})([a-fA-F0-9]{$n_digit})([a-fA-F0-9]{$n_digit})"
query := '#([a-fA-F0-9]{$n_digit})([a-fA-F0-9]{$n_digit})([a-fA-F0-9]{$n_digit})'
mut re := regex.regex_opt(query) or { panic(err) }
start, end := re.match_string(in_col)
println("start: $start, end: $end")
println('start: $start, end: $end')
mut res := u32(0)
if start >= 0 {
group_list := re.get_group_list()
r := ("0x" + in_col[group_list[0].start..group_list[0].end]).int() << col_mul
g := ("0x" + in_col[group_list[1].start..group_list[1].end]).int() << col_mul
b := ("0x" + in_col[group_list[2].start..group_list[2].end]).int() << col_mul
println("r: $r g: $g b: $b")
r := ('0x' + in_col[group_list[0].start..group_list[0].end]).int() << col_mul
g := ('0x' + in_col[group_list[1].start..group_list[1].end]).int() << col_mul
b := ('0x' + in_col[group_list[2].start..group_list[2].end]).int() << col_mul
println('r: $r g: $g b: $b')
res = u32(r) << 16 | u32(g) << 8 | u32(b)
}
return res
@@ -47,23 +47,23 @@ fn convert_html_rgb_n(in_col string) u32 {
mut n_digit := if in_col.len == 4 { 1 } else { 2 }
mut col_mul := if in_col.len == 4 { 4 } else { 0 }
query:= "#(?P<red>[a-fA-F0-9]{$n_digit})(?P<green>[a-fA-F0-9]{$n_digit})(?P<blue>[a-fA-F0-9]{$n_digit})"
query := '#(?P<red>[a-fA-F0-9]{$n_digit})(?P<green>[a-fA-F0-9]{$n_digit})(?P<blue>[a-fA-F0-9]{$n_digit})'
mut re := regex.regex_opt(query) or { panic(err) }
start, end := re.match_string(in_col)
println("start: $start, end: $end")
println('start: $start, end: $end')
mut res := u32(0)
if start >= 0 {
red_s, red_e := re.get_group_bounds_by_name("red")
r := ("0x" + in_col[red_s..red_e]).int() << col_mul
green_s, green_e := re.get_group_bounds_by_name("green")
g := ("0x" + in_col[green_s..green_e]).int() << col_mul
blue_s, blue_e := re.get_group_bounds_by_name("blue")
b := ("0x" + in_col[blue_s..blue_e]).int() << col_mul
println("r: $r g: $g b: $b")
red_s, red_e := re.get_group_bounds_by_name('red')
r := ('0x' + in_col[red_s..red_e]).int() << col_mul
green_s, green_e := re.get_group_bounds_by_name('green')
g := ('0x' + in_col[green_s..green_e]).int() << col_mul
blue_s, blue_e := re.get_group_bounds_by_name('blue')
b := ('0x' + in_col[blue_s..blue_e]).int() << col_mul
println('r: $r g: $g b: $b')
res = u32(r) << 16 | u32(g) << 8 | u32(b)
}
return res
@@ -71,10 +71,10 @@ fn convert_html_rgb_n(in_col string) u32 {
fn main() {
// convert HTML rgb color using groups
println(convert_html_rgb("#A0b0Cc").hex())
println(convert_html_rgb("#ABC").hex())
println(convert_html_rgb('#A0b0Cc').hex())
println(convert_html_rgb('#ABC').hex())
// convert HTML rgb color using named groups
println(convert_html_rgb_n("#A0B0CC").hex())
println(convert_html_rgb_n("#ABC").hex())
println(convert_html_rgb_n('#A0B0CC').hex())
println(convert_html_rgb_n('#ABC').hex())
}

View File

@@ -23,8 +23,8 @@ fn regex_match_core(src string, pat string, src_pos int, pat_pos int, mut memo [
if pat[ppos] == `\\` {
ppos++
}
res := ppos + 1 < pat.len &&
pat[ppos + 1] in [`*`, `?`] && regex_match_core(src, pat, spos, ppos + 2, mut memo)
res := ppos + 1 < pat.len && pat[ppos + 1] in [`*`, `?`]
&& regex_match_core(src, pat, spos, ppos + 2, mut memo)
memo[src_pos][pat_pos] = if res { 1 } else { 0 }
return res
} else {
@@ -32,27 +32,28 @@ fn regex_match_core(src string, pat string, src_pos int, pat_pos int, mut memo [
if first_is_bslash {
ppos++
}
first_bslash_and_match := first_is_bslash && ppos < pat.len &&
(((pat[ppos] == `d` && src[spos].is_digit()) ||
(pat[ppos] == `D` && !src[spos].is_digit()) ||
(pat[ppos] == `s` && src[spos].is_space()) ||
(pat[ppos] == `S` && !src[spos].is_space()) ||
(pat[ppos] == `w` && (src[spos].is_digit() || src[spos].is_letter() || src[spos] == `_`)) ||
(pat[ppos] == `W` && !(src[spos].is_digit() || src[spos].is_letter() || src[spos] == `_`))) ||
(pat[ppos] in [`d`, `D`, `s`, `S`, `w`, `W`] &&
ppos + 1 < pat.len && pat[ppos + 1] in [`*`, `?`, `+`]) ||
(pat[ppos] !in [`d`, `D`, `s`, `S`, `w`, `W`] && src[spos] == pat[ppos]))
first_bslash_and_match := first_is_bslash && ppos < pat.len
&& (((pat[ppos] == `d` && src[spos].is_digit())
|| (pat[ppos] == `D` && !src[spos].is_digit())
|| (pat[ppos] == `s` && src[spos].is_space())
|| (pat[ppos] == `S` && !src[spos].is_space())
|| (pat[ppos] == `w` && (src[spos].is_digit() || src[spos].is_letter()
|| src[spos] == `_`)) || (pat[ppos] == `W` && !(src[spos].is_digit()
|| src[spos].is_letter() || src[spos] == `_`)))
|| (pat[ppos] in [`d`, `D`, `s`, `S`, `w`, `W`] && ppos + 1 < pat.len
&& pat[ppos + 1] in [`*`, `?`, `+`])
|| (pat[ppos] !in [`d`, `D`, `s`, `S`, `w`, `W`] && src[spos] == pat[ppos]))
if ppos + 1 < pat.len {
match pat[ppos + 1] {
`*` {
if first_bslash_and_match {
res := regex_match_core(src, pat, spos + 1, ppos - 1, mut memo) || regex_match_core(src, pat, spos, ppos +
2, mut memo)
res := regex_match_core(src, pat, spos + 1, ppos - 1, mut memo)
|| regex_match_core(src, pat, spos, ppos + 2, mut memo)
memo[src_pos][pat_pos] = if res { 1 } else { 0 }
return res
} else if src[spos] == pat[ppos] || pat[ppos] == `.` {
res := regex_match_core(src, pat, spos + 1, ppos, mut memo) || regex_match_core(src, pat, spos, ppos +
2, mut memo)
res := regex_match_core(src, pat, spos + 1, ppos, mut memo)
|| regex_match_core(src, pat, spos, ppos + 2, mut memo)
memo[src_pos][pat_pos] = if res { 1 } else { 0 }
return res
} else {
@@ -63,13 +64,13 @@ fn regex_match_core(src string, pat string, src_pos int, pat_pos int, mut memo [
}
`+` {
if first_bslash_and_match {
res := regex_match_core(src, pat, spos + 1, ppos - 1, mut memo) || regex_match_core(src, pat, spos +
1, ppos + 2, mut memo)
res := regex_match_core(src, pat, spos + 1, ppos - 1, mut memo)
|| regex_match_core(src, pat, spos + 1, ppos + 2, mut memo)
memo[src_pos][pat_pos] = if res { 1 } else { 0 }
return res
} else if src[spos] == pat[ppos] || pat[ppos] == `.` {
res := regex_match_core(src, pat, spos + 1, ppos, mut memo) || regex_match_core(src, pat, spos +
1, ppos + 2, mut memo)
res := regex_match_core(src, pat, spos + 1, ppos, mut memo)
|| regex_match_core(src, pat, spos + 1, ppos + 2, mut memo)
memo[src_pos][pat_pos] = if res { 1 } else { 0 }
return res
} else {
@@ -79,8 +80,8 @@ fn regex_match_core(src string, pat string, src_pos int, pat_pos int, mut memo [
}
`?` {
if first_bslash_and_match || src[spos] == pat[ppos] || pat[ppos] == `.` {
res := regex_match_core(src, pat, spos + 1, ppos + 2, mut memo) || regex_match_core(src, pat, spos, ppos +
2, mut memo)
res := regex_match_core(src, pat, spos + 1, ppos + 2, mut memo)
|| regex_match_core(src, pat, spos, ppos + 2, mut memo)
memo[src_pos][pat_pos] = if res { 1 } else { 0 }
return res
} else {
@@ -93,13 +94,13 @@ fn regex_match_core(src string, pat string, src_pos int, pat_pos int, mut memo [
}
}
if first_is_bslash {
res := first_bslash_and_match && regex_match_core(src, pat, spos + 1, ppos + 1, mut memo)
res := first_bslash_and_match
&& regex_match_core(src, pat, spos + 1, ppos + 1, mut memo)
memo[src_pos][pat_pos] = if res { 1 } else { 0 }
return res
} else {
res := (src[spos] == pat[ppos] ||
pat[ppos] == `.`) &&
pat[ppos] != `\\` && regex_match_core(src, pat, spos + 1, ppos + 1, mut memo)
res := (src[spos] == pat[ppos] || pat[ppos] == `.`) && pat[ppos] != `\\`
&& regex_match_core(src, pat, spos + 1, ppos + 1, mut memo)
memo[src_pos][pat_pos] = if res { 1 } else { 0 }
return res
}

View File

@@ -1,6 +1,6 @@
import gg
import gx
import sokol.sapp
// import sokol.sapp
import time
import rand
@@ -73,7 +73,7 @@ fn (mut app App) move_food() {
}
// events
fn on_keydown(key sapp.KeyCode, mod sapp.Modifier, mut app App) {
fn on_keydown(key gg.KeyCode, mod gg.Modifier, mut app App) {
match key {
.w, .up {
if app.dir != .down {
@@ -156,9 +156,8 @@ fn on_frame(mut app App) {
app.reset_game()
}
// checking if snake hit a wall
if app.snake[0].x < 0 ||
app.snake[0].x >= game_size || app.snake[0].y < 0 || app.snake[0].y >= game_size
{
if app.snake[0].x < 0 || app.snake[0].x >= game_size || app.snake[0].y < 0
|| app.snake[0].y >= game_size {
app.reset_game()
}

View File

@@ -13,7 +13,6 @@
import gg
import gx
import math
import sokol.sapp
import sokol.gfx
import sokol.sgl
@@ -26,14 +25,13 @@ const (
struct App {
mut:
gg &gg.Context
pip_3d C.sgl_pipeline
texture C.sg_image
init_flag bool
frame_count int
mouse_x int = -1
mouse_y int = -1
gg &gg.Context
pip_3d C.sgl_pipeline
texture C.sg_image
init_flag bool
frame_count int
mouse_x int = -1
mouse_y int = -1
}
/******************************************************************************
@@ -41,15 +39,15 @@ mut:
* Texture functions
*
******************************************************************************/
fn create_texture(w int, h int, buf byteptr) C.sg_image{
fn create_texture(w int, h int, buf byteptr) C.sg_image {
sz := w * h * 4
mut img_desc := C.sg_image_desc{
width: w
height: h
num_mipmaps: 0
min_filter: .linear
mag_filter: .linear
//usage: .dynamic
min_filter: .linear
mag_filter: .linear
// usage: .dynamic
wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge
label: &byte(0)
@@ -60,20 +58,20 @@ fn create_texture(w int, h int, buf byteptr) C.sg_image{
ptr: buf
size: sz
}
sg_img := C.sg_make_image(&img_desc)
return sg_img
}
fn destroy_texture(sg_img C.sg_image){
fn destroy_texture(sg_img C.sg_image) {
C.sg_destroy_image(sg_img)
}
// Use only if usage: .dynamic is enabled
fn update_text_texture(sg_img C.sg_image, w int, h int, buf byteptr){
fn update_text_texture(sg_img C.sg_image, w int, h int, buf byteptr) {
sz := w * h * 4
mut tmp_sbc := C.sg_image_content{}
tmp_sbc.subimage[0][0] = C.sg_subimage_content {
tmp_sbc.subimage[0][0] = C.sg_subimage_content{
ptr: buf
size: sz
}
@@ -88,9 +86,9 @@ fn update_text_texture(sg_img C.sg_image, w int, h int, buf byteptr){
fn draw_triangle() {
sgl.defaults()
sgl.begin_triangles()
sgl.v2f_c3b( 0.0, 0.5, 255, 0, 0)
sgl.v2f_c3b(0.0, 0.5, 255, 0, 0)
sgl.v2f_c3b(-0.5, -0.5, 0, 0, 255)
sgl.v2f_c3b( 0.5, -0.5, 0, 255, 0)
sgl.v2f_c3b(0.5, -0.5, 0, 255, 0)
sgl.end()
}
@@ -99,44 +97,44 @@ fn cube() {
sgl.begin_quads()
// edge color
sgl.c3f(1.0, 0.0, 0.0)
// edge coord
// x,y,z, texture cord: u,v
sgl.v3f_t2f(-1.0, 1.0, -1.0, -1.0, 1.0)
sgl.v3f_t2f( 1.0, 1.0, -1.0, 1.0, 1.0)
sgl.v3f_t2f( 1.0, -1.0, -1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0)
// edge coord
// x,y,z, texture cord: u,v
sgl.v3f_t2f(-1.0, 1.0, -1.0, -1.0, 1.0)
sgl.v3f_t2f(1.0, 1.0, -1.0, 1.0, 1.0)
sgl.v3f_t2f(1.0, -1.0, -1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0)
sgl.c3f(0.0, 1.0, 0.0)
sgl.v3f_t2f(-1.0, -1.0, 1.0, -1.0, 1.0)
sgl.v3f_t2f( 1.0, -1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f( 1.0, 1.0, 1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, 1.0, 1.0, -1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, 1.0, -1.0, 1.0)
sgl.v3f_t2f(1.0, -1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f(1.0, 1.0, 1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, 1.0, 1.0, -1.0, -1.0)
sgl.c3f(0.0, 0.0, 1.0)
sgl.v3f_t2f(-1.0, -1.0, 1.0, -1.0, 1.0)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f(-1.0, 1.0, -1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, 1.0, -1.0, 1.0)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f(-1.0, 1.0, -1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0)
sgl.c3f(1.0, 0.5, 0.0)
sgl.v3f_t2f(1.0, -1.0, 1.0, -1.0, 1.0)
sgl.v3f_t2f(1.0, -1.0, -1.0, 1.0, 1.0)
sgl.v3f_t2f(1.0, 1.0, -1.0, 1.0, -1.0)
sgl.v3f_t2f(1.0, 1.0, 1.0, -1.0, -1.0)
sgl.v3f_t2f(1.0, -1.0, 1.0, -1.0, 1.0)
sgl.v3f_t2f(1.0, -1.0, -1.0, 1.0, 1.0)
sgl.v3f_t2f(1.0, 1.0, -1.0, 1.0, -1.0)
sgl.v3f_t2f(1.0, 1.0, 1.0, -1.0, -1.0)
sgl.c3f(0.0, 0.5, 1.0)
sgl.v3f_t2f( 1.0, -1.0, -1.0, -1.0, 1.0)
sgl.v3f_t2f( 1.0, -1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f(-1.0, -1.0, 1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0)
sgl.v3f_t2f(1.0, -1.0, -1.0, -1.0, 1.0)
sgl.v3f_t2f(1.0, -1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f(-1.0, -1.0, 1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0)
sgl.c3f(1.0, 0.0, 0.5)
sgl.v3f_t2f(-1.0, 1.0, -1.0, -1.0, 1.0)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f( 1.0, 1.0, 1.0, 1.0, -1.0)
sgl.v3f_t2f( 1.0, 1.0, -1.0, -1.0, -1.0)
sgl.v3f_t2f(-1.0, 1.0, -1.0, -1.0, 1.0)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f(1.0, 1.0, 1.0, 1.0, -1.0)
sgl.v3f_t2f(1.0, 1.0, -1.0, -1.0, -1.0)
sgl.end()
}
fn draw_cubes(app App) {
rot := [f32(1.0)*(app.frame_count % 360), 0.5*f32(app.frame_count%360)]
//rot := [f32(app.mouse_x), f32(app.mouse_y)]
rot := [f32(1.0) * (app.frame_count % 360), 0.5 * f32(app.frame_count % 360)]
// rot := [f32(app.mouse_x), f32(app.mouse_y)]
sgl.defaults()
sgl.load_pipeline(app.pip_3d)
@@ -149,56 +147,56 @@ fn draw_cubes(app App) {
sgl.rotate(sgl.rad(rot[1]), 0.0, 1.0, 0.0)
cube()
sgl.push_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-2.0 * sgl.rad(rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(-2.0 * sgl.rad(rot[1]), 0.0, 1.0, 0.0)
cube()
sgl.push_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-3.0 * sgl.rad(2*rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(3.0 * sgl.rad(2*rot[1]), 0.0, 0.0, 1.0)
cube()
sgl.pop_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-2.0 * sgl.rad(rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(-2.0 * sgl.rad(rot[1]), 0.0, 1.0, 0.0)
cube()
sgl.push_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-3.0 * sgl.rad(2 * rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(3.0 * sgl.rad(2 * rot[1]), 0.0, 0.0, 1.0)
cube()
sgl.pop_matrix()
sgl.pop_matrix()
}
fn cube_t(r f32,g f32,b f32) {
fn cube_t(r f32, g f32, b f32) {
sgl.begin_quads()
// edge color
sgl.c3f(r, g, b)
// edge coord
// x,y,z, texture cord: u,v
sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.0 , 0.25)
sgl.v3f_t2f( 1.0, 1.0, -1.0, 0.25, 0.25)
sgl.v3f_t2f( 1.0, -1.0, -1.0, 0.25, 0.0 )
sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0 , 0.0 )
// edge coord
// x,y,z, texture cord: u,v
sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.0, 0.25)
sgl.v3f_t2f(1.0, 1.0, -1.0, 0.25, 0.25)
sgl.v3f_t2f(1.0, -1.0, -1.0, 0.25, 0.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0, 0.0)
sgl.c3f(r, g, b)
sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.0 , 0.25)
sgl.v3f_t2f( 1.0, -1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f( 1.0, 1.0, 1.0, 0.25, 0.0 )
sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.0 , 0.0 )
sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.0, 0.25)
sgl.v3f_t2f(1.0, -1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f(1.0, 1.0, 1.0, 0.25, 0.0)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.0, 0.0)
sgl.c3f(r, g, b)
sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.0 , 0.25)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.25, 0.0 )
sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0 , 0.0 )
sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.0, 0.25)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.25, 0.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0, 0.0)
sgl.c3f(r, g, b)
sgl.v3f_t2f(1.0, -1.0, 1.0, 0.0 , 0.25)
sgl.v3f_t2f(1.0, -1.0, -1.0, 0.25, 0.25)
sgl.v3f_t2f(1.0, 1.0, -1.0, 0.25, 0.0 )
sgl.v3f_t2f(1.0, 1.0, 1.0, 0.0 , 0.0 )
sgl.v3f_t2f(1.0, -1.0, 1.0, 0.0, 0.25)
sgl.v3f_t2f(1.0, -1.0, -1.0, 0.25, 0.25)
sgl.v3f_t2f(1.0, 1.0, -1.0, 0.25, 0.0)
sgl.v3f_t2f(1.0, 1.0, 1.0, 0.0, 0.0)
sgl.c3f(r, g, b)
sgl.v3f_t2f( 1.0, -1.0, -1.0, 0.0 , 0.25)
sgl.v3f_t2f( 1.0, -1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.25, 0.0 )
sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0 , 0.0 )
sgl.v3f_t2f(1.0, -1.0, -1.0, 0.0, 0.25)
sgl.v3f_t2f(1.0, -1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.25, 0.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0, 0.0)
sgl.c3f(r, g, b)
sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.0 , 0.25)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f( 1.0, 1.0, 1.0, 0.25, 0.0 )
sgl.v3f_t2f( 1.0, 1.0, -1.0, 0.0 , 0.0 )
sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.0, 0.25)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f(1.0, 1.0, 1.0, 0.25, 0.0)
sgl.v3f_t2f(1.0, 1.0, -1.0, 0.0, 0.0)
sgl.end()
}
@@ -217,30 +215,30 @@ fn draw_texture_cubes(app App) {
sgl.translate(0.0, 0.0, -12.0)
sgl.rotate(sgl.rad(rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(sgl.rad(rot[1]), 0.0, 1.0, 0.0)
cube_t(1,1,1)
cube_t(1, 1, 1)
sgl.push_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-2.0 * sgl.rad(rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(-2.0 * sgl.rad(rot[1]), 0.0, 1.0, 0.0)
cube_t(1,1,1)
sgl.push_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-3.0 * sgl.rad(2*rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(3.0 * sgl.rad(2*rot[1]), 0.0, 0.0, 1.0)
cube_t(1,1,1)
sgl.pop_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-2.0 * sgl.rad(rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(-2.0 * sgl.rad(rot[1]), 0.0, 1.0, 0.0)
cube_t(1, 1, 1)
sgl.push_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-3.0 * sgl.rad(2 * rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(3.0 * sgl.rad(2 * rot[1]), 0.0, 0.0, 1.0)
cube_t(1, 1, 1)
sgl.pop_matrix()
sgl.pop_matrix()
sgl.disable_texture()
}
fn cube_field(app App){
fn cube_field(app App) {
rot := [f32(app.mouse_x), f32(app.mouse_y)]
xyz_sz := f32(2.0)
field_size := 20
sgl.defaults()
sgl.load_pipeline(app.pip_3d)
@@ -249,57 +247,59 @@ fn cube_field(app App){
sgl.matrix_mode_projection()
sgl.perspective(sgl.rad(45.0), 1.0, 0.1, 200.0)
sgl.matrix_mode_modelview()
sgl.translate(field_size, 0.0, -120.0)
sgl.rotate(sgl.rad(rot[0]), 0.0, 1.0, 0.0)
sgl.rotate(sgl.rad(rot[1]), 1.0, 0.0, 0.0)
// draw field_size*field_size cubes
for y in 0..field_size {
for x in 0..field_size {
for y in 0 .. field_size {
for x in 0 .. field_size {
sgl.push_matrix()
z := f32(math.cos(f32(x*2)/field_size)*math.sin(f32(y*2)/field_size)*xyz_sz)*(xyz_sz*5)
sgl.translate(x*xyz_sz, z, y*xyz_sz)
cube_t(f32(f32(x)/field_size), f32(f32(y)/field_size),1)
z := f32(math.cos(f32(x * 2) / field_size) * math.sin(f32(y * 2) / field_size) * xyz_sz) * (xyz_sz * 5)
sgl.translate(x * xyz_sz, z, y * xyz_sz)
cube_t(f32(f32(x) / field_size), f32(f32(y) / field_size), 1)
sgl.pop_matrix()
}
}
}
sgl.disable_texture()
}
fn frame(mut app App) {
dw := app.gg.width
dh := app.gg.height
ww := dh/2 /* not a bug */
hh := dh/2
x0 := dw/2 - hh
//x1 := dw/2
ws := gg.window_size()
ratio := f32(ws.width) / ws.height
dw := ws.width
dh := ws.height
ww := int(dh / 3) // not a bug
hh := int(dh / 3)
x0 := int(f32(dw) * 0.05)
// x1 := dw/2
y0 := 0
y1 := dh/2
y1 := int(f32(dh) * 0.5)
app.gg.begin()
//sgl.defaults()
// sgl.defaults()
// 2d triangle
sgl.viewport(x0, y0, ww, hh, true)
draw_triangle()
// colored cubes with viewport
sgl.viewport(x0, y1, ww, hh, true)
draw_cubes(app)
// textured cubed with viewport
sgl.viewport(0, 0, dw, dh, true)
sgl.viewport(0, int(dh / 5), dw, int(dh * ratio), true)
draw_texture_cubes(app)
// textured field of cubes with viewport
sgl.viewport(0, 0, dw, dh, true)
sgl.viewport(0, int(dh / 5), dw, int(dh * ratio), true)
cube_field(app)
app.frame_count++
app.gg.end()
}
@@ -310,7 +310,7 @@ fn frame(mut app App) {
******************************************************************************/
fn my_init(mut app App) {
app.init_flag = true
// set max vertices,
// for a large number of the same type of object it is better use the instances!!
desc := sapp.create_desc()
@@ -319,57 +319,59 @@ fn my_init(mut app App) {
max_vertices: 50 * 65536
}
sgl.setup(&sgl_desc)
// 3d pipeline
mut pipdesc := C.sg_pipeline_desc{}
unsafe {C.memset(&pipdesc, 0, sizeof(pipdesc))}
unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) }
pipdesc.blend.enabled = true
pipdesc.blend.src_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA)
pipdesc.blend.dst_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA)
pipdesc.depth_stencil = C.sg_depth_stencil_state{
pipdesc.depth_stencil = C.sg_depth_stencil_state{
depth_write_enabled: true
depth_compare_func : gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL)
depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL)
}
pipdesc.rasterizer = C.sg_rasterizer_state {
pipdesc.rasterizer = C.sg_rasterizer_state{
cull_mode: .back
}
app.pip_3d = sgl.make_pipeline(&pipdesc)
// create chessboard texture 256*256 RGBA
w := 256
h := 256
sz := w * h * 4
tmp_txt := malloc(sz)
tmp_txt := unsafe { malloc(sz) }
mut i := 0
for i < sz {
unsafe {
y := (i >> 0x8) >> 5 // 8 cell
x := (i & 0xFF) >> 5 // 8 cell
y := (i >> 0x8) >> 5 // 8 cell
x := (i & 0xFF) >> 5 // 8 cell
// upper left corner
if x==0 && y==0 {
tmp_txt[i ] = byte(0xFF)
tmp_txt[i+1] = byte(0)
tmp_txt[i+2] = byte(0)
tmp_txt[i+3] = byte(0xFF)
if x == 0 && y == 0 {
tmp_txt[i] = byte(0xFF)
tmp_txt[i + 1] = byte(0)
tmp_txt[i + 2] = byte(0)
tmp_txt[i + 3] = byte(0xFF)
}
// low right corner
else if x==7 && y==7 {
tmp_txt[i ] = byte(0)
tmp_txt[i+1] = byte(0xFF)
tmp_txt[i+2] = byte(0)
tmp_txt[i+3] = byte(0xFF)
else if x == 7 && y == 7 {
tmp_txt[i] = byte(0)
tmp_txt[i + 1] = byte(0xFF)
tmp_txt[i + 2] = byte(0)
tmp_txt[i + 3] = byte(0xFF)
} else {
col := if ((x+y) & 1) == 1 {0xFF} else {0}
tmp_txt[i ] = byte(col) // red
tmp_txt[i+1] = byte(col) // green
tmp_txt[i+2] = byte(col) // blue
tmp_txt[i+3] = byte(0xFF) // alpha
col := if ((x + y) & 1) == 1 { 0xFF } else { 0 }
tmp_txt[i] = byte(col) // red
tmp_txt[i + 1] = byte(col) // green
tmp_txt[i + 2] = byte(col) // blue
tmp_txt[i + 3] = byte(0xFF) // alpha
}
i += 4
}
}
app.texture = create_texture(w, h, tmp_txt)
free(tmp_txt)
unsafe {
app.texture = create_texture(w, h, tmp_txt)
free(tmp_txt)
}
}
fn cleanup(mut app App) {
@@ -381,11 +383,18 @@ fn cleanup(mut app App) {
* event
*
******************************************************************************/
fn my_event_manager(mut ev sapp.Event, mut app App) {
fn my_event_manager(mut ev gg.Event, mut app App) {
if ev.typ == .mouse_move {
app.mouse_x = int(ev.mouse_x)
app.mouse_y = int(ev.mouse_y)
}
if ev.typ == .touches_began || ev.typ == .touches_moved {
if ev.num_touches > 0 {
touch_point := ev.touches[0]
app.mouse_x = int(touch_point.pos_x)
app.mouse_y = int(touch_point.pos_y)
}
}
}
/******************************************************************************
@@ -393,13 +402,14 @@ fn my_event_manager(mut ev sapp.Event, mut app App) {
* Main
*
******************************************************************************/
fn main(){
[console] // is needed for easier diagnostics on windows
fn main() {
// App init
mut app := &App{
gg: 0
}
app.gg = gg.new_context({
app.gg = gg.new_context(
width: win_width
height: win_height
use_ortho: true // This is needed for 2D drawing
@@ -411,7 +421,7 @@ fn main(){
init_fn: my_init
cleanup_fn: cleanup
event_fn: my_event_manager
})
)
app.gg.run()
}

View File

@@ -0,0 +1,95 @@
//------------------------------------------------------------------------------
// Shader code for texcube-sapp sample.
//
// NOTE: This source file also uses the '#pragma sokol' form of the
// custom tags.
//------------------------------------------------------------------------------
//#pragma sokol @ctype mat4 my_mat4
#pragma sokol @vs vs
uniform vs_params {
mat4 mvp;
};
in vec4 pos;
in vec4 color0;
in vec2 texcoord0;
out vec4 color;
out vec2 uv;
void main() {
gl_Position = mvp * pos;
color = color0;
uv = texcoord0;
}
#pragma sokol @end
#pragma sokol @fs fs
uniform sampler2D tex;
uniform fs_params {
vec2 text_res;
float iTime;
};
in vec4 color;
in vec2 uv;
out vec4 frag_color;
//*********************************************************
// RAY TRACE
// original code from: https://www.shadertoy.com/view/ldS3DW
//*********************************************************
float sphere(vec3 ray, vec3 dir, vec3 center, float radius)
{
vec3 rc = ray-center;
float c = dot(rc, rc) - (radius*radius);
float b = dot(dir, rc);
float d = b*b - c;
float t = -b - sqrt(abs(d));
float st = step(0.0, min(t,d));
return mix(-1.0, t, st);
}
vec3 background(float t, vec3 rd)
{
vec3 light = normalize(vec3(sin(t), 0.6, cos(t)));
float sun = max(0.0, dot(rd, light));
float sky = max(0.0, dot(rd, vec3(0.0, 1.0, 0.0)));
float ground = max(0.0, -dot(rd, vec3(0.0, 1.0, 0.0)));
return (pow(sun, 256.0)+0.2*pow(sun, 2.0))*vec3(2.0, 1.6, 1.0) +
pow(ground, 0.5)*vec3(0.4, 0.3, 0.2) +
pow(sky, 1.0)*vec3(0.5, 0.6, 0.7);
}
vec4 mainImage(vec2 fragCoord)
{
vec2 uv = (fragCoord-vec2(0.4,0.4))*2.0;
//vec2 uv = (-1.0 + 2.0*fc.xy / text_res.xy) * vec2(text_res.x/text_res.y, 1.0);
vec3 ro = vec3(0.0, 0.0, -3.0);
vec3 rd = normalize(vec3(uv, 1.0));
vec3 p = vec3(0.0, 0.0, 0.0);
float t = sphere(ro, rd, p, 1.0);
vec3 nml = normalize(p - (ro+rd*t));
vec3 bgCol = background(iTime, rd);
rd = reflect(rd, nml);
vec3 col = background(iTime, rd) * vec3(0.9, 0.8, 1.0);
vec4 fragColor = vec4( mix(bgCol, col, step(0.0, t)), 1.0 );
return fragColor;
}
//*********************************************************
//*********************************************************
void main() {
vec4 c = color;
vec4 txt = texture(tex, uv/4.0);
c = txt * c;
vec4 col_ray = mainImage(uv);
float txt_mix = mod(iTime,5);
frag_color = c*txt_mix*0.1 + col_ray ;
}
#pragma sokol @end
#pragma sokol @program cube vs fs

View File

@@ -0,0 +1,605 @@
/**********************************************************************
*
* Sokol 3d cube demo
*
* Copyright (c) 2021 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
* that can be found in the LICENSE file.
*
* HOW TO COMPILE SHADERS:
* - download the sokol shader convertor tool from https://github.com/floooh/sokol-tools-bin/archive/pre-feb2021-api-changes.tar.gz
* ( also look at https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md )
* - compile the .glsl shader with:
* linux : sokol-shdc --input cube_glsl.glsl --output cube_glsl.h --slang glsl330
* windows: sokol-shdc.exe --input cube_glsl.glsl --output cube_glsl.h --slang glsl330
*
* --slang parameter can be:
* - glsl330: desktop GL
* - glsl100: GLES2 / WebGL
* - glsl300es: GLES3 / WebGL2
* - hlsl4: D3D11
* - hlsl5: D3D11
* - metal_macos: Metal on macOS
* - metal_ios: Metal on iOS device
* - metal_sim: Metal on iOS simulator
* - wgpu: WebGPU
*
* you can have multiple platforms at the same time passing prameter like this: --slang glsl330:hlsl5:metal_macos
* for further infos have a look at the sokol shader tool docs.
*
* TODO:
* - add instancing
**********************************************************************/
import gg
import gx
// import math
import sokol.sapp
import sokol.gfx
import sokol.sgl
import time
import gg.m4
// GLSL Include and functions
#flag -I @VROOT/.
#include "cube_glsl.h" #Please use sokol-shdc to generate the necessary cube_glsl.h file from cube_glsl.glsl (see the instructions at the top of this file)
fn C.cube_shader_desc() &C.sg_shader_desc
const (
win_width = 800
win_height = 800
bg_color = gx.white
)
struct App {
mut:
gg &gg.Context
pip_3d C.sgl_pipeline
texture C.sg_image
init_flag bool
frame_count int
mouse_x int = -1
mouse_y int = -1
// glsl
cube_pip_glsl C.sg_pipeline
cube_bind C.sg_bindings
// time
ticks i64
}
/******************************************************************************
*
* Texture functions
*
******************************************************************************/
fn create_texture(w int, h int, buf byteptr) C.sg_image {
sz := w * h * 4
mut img_desc := C.sg_image_desc{
width: w
height: h
num_mipmaps: 0
min_filter: .linear
mag_filter: .linear
// usage: .dynamic
wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge
label: &byte(0)
d3d11_texture: 0
}
// comment if .dynamic is enabled
img_desc.content.subimage[0][0] = C.sg_subimage_content{
ptr: buf
size: sz
}
sg_img := C.sg_make_image(&img_desc)
return sg_img
}
fn destroy_texture(sg_img C.sg_image) {
C.sg_destroy_image(sg_img)
}
// Use only if usage: .dynamic is enabled
fn update_text_texture(sg_img C.sg_image, w int, h int, buf byteptr) {
sz := w * h * 4
mut tmp_sbc := C.sg_image_content{}
tmp_sbc.subimage[0][0] = C.sg_subimage_content{
ptr: buf
size: sz
}
C.sg_update_image(sg_img, &tmp_sbc)
}
/******************************************************************************
*
* Draw functions
*
******************************************************************************/
fn draw_triangle() {
sgl.defaults()
sgl.begin_triangles()
sgl.v2f_c3b( 0.0, 0.5, 255, 0 , 0 )
sgl.v2f_c3b(-0.5, -0.5, 0, 0 , 255)
sgl.v2f_c3b( 0.5, -0.5, 0, 255, 0 )
sgl.end()
}
// vertex specification for a cube with colored sides and texture coords
fn cube() {
sgl.begin_quads()
// edge color
sgl.c3f(1.0, 0.0, 0.0)
// edge coord
// x,y,z, texture cord: u,v
sgl.v3f_t2f(-1.0, 1.0, -1.0, -1.0, 1.0)
sgl.v3f_t2f( 1.0, 1.0, -1.0, 1.0, 1.0)
sgl.v3f_t2f( 1.0, -1.0, -1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0)
sgl.c3f(0.0, 1.0, 0.0)
sgl.v3f_t2f(-1.0, -1.0, 1.0, -1.0, 1.0)
sgl.v3f_t2f( 1.0, -1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f( 1.0, 1.0, 1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, 1.0, 1.0, -1.0, -1.0)
sgl.c3f(0.0, 0.0, 1.0)
sgl.v3f_t2f(-1.0, -1.0, 1.0, -1.0, 1.0)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f(-1.0, 1.0, -1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0)
sgl.c3f(1.0, 0.5, 0.0)
sgl.v3f_t2f(1.0, -1.0, 1.0, -1.0, 1.0)
sgl.v3f_t2f(1.0, -1.0, -1.0, 1.0, 1.0)
sgl.v3f_t2f(1.0, 1.0, -1.0, 1.0, -1.0)
sgl.v3f_t2f(1.0, 1.0, 1.0, -1.0, -1.0)
sgl.c3f(0.0, 0.5, 1.0)
sgl.v3f_t2f( 1.0, -1.0, -1.0, -1.0, 1.0)
sgl.v3f_t2f( 1.0, -1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f(-1.0, -1.0, 1.0, 1.0, -1.0)
sgl.v3f_t2f(-1.0, -1.0, -1.0, -1.0, -1.0)
sgl.c3f(1.0, 0.0, 0.5)
sgl.v3f_t2f(-1.0, 1.0, -1.0, -1.0, 1.0)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 1.0, 1.0)
sgl.v3f_t2f( 1.0, 1.0, 1.0, 1.0, -1.0)
sgl.v3f_t2f( 1.0, 1.0, -1.0, -1.0, -1.0)
sgl.end()
}
fn draw_cubes(app App) {
rot := [f32(1.0) * (app.frame_count % 360), 0.5 * f32(app.frame_count % 360)]
// rot := [f32(app.mouse_x), f32(app.mouse_y)]
sgl.defaults()
sgl.load_pipeline(app.pip_3d)
sgl.matrix_mode_projection()
sgl.perspective(sgl.rad(45.0), 1.0, 0.1, 100.0)
sgl.matrix_mode_modelview()
sgl.translate(0.0, 0.0, -12.0)
sgl.rotate(sgl.rad(rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(sgl.rad(rot[1]), 0.0, 1.0, 0.0)
cube()
sgl.push_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-2.0 * sgl.rad(rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(-2.0 * sgl.rad(rot[1]), 0.0, 1.0, 0.0)
cube()
sgl.push_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-3.0 * sgl.rad(2 * rot[0]), 1.0, 0.0, 0.0)
sgl.rotate( 3.0 * sgl.rad(2 * rot[1]), 0.0, 0.0, 1.0)
cube()
sgl.pop_matrix()
sgl.pop_matrix()
}
fn cube_texture(r f32, g f32, b f32) {
sgl.begin_quads()
// edge color
sgl.c3f(r, g, b)
// edge coord
// x,y,z, texture cord: u,v
sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.0 , 0.25)
sgl.v3f_t2f( 1.0, 1.0, -1.0, 0.25, 0.25)
sgl.v3f_t2f( 1.0, -1.0, -1.0, 0.25, 0.0 )
sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0 , 0.0 )
sgl.c3f(r, g, b)
sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.0 , 0.25)
sgl.v3f_t2f( 1.0, -1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f( 1.0, 1.0, 1.0, 0.25, 0.0 )
sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.0 , 0.0 )
sgl.c3f(r, g, b)
sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.0 , 0.25)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.25, 0.0 )
sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0 , 0.0 )
sgl.c3f(r, g, b)
sgl.v3f_t2f(1.0, -1.0, 1.0, 0.0 , 0.25)
sgl.v3f_t2f(1.0, -1.0, -1.0, 0.25, 0.25)
sgl.v3f_t2f(1.0, 1.0, -1.0, 0.25, 0.0 )
sgl.v3f_t2f(1.0, 1.0, 1.0, 0.0 , 0.0 )
sgl.c3f(r, g, b)
sgl.v3f_t2f( 1.0, -1.0, -1.0, 0.0 , 0.25)
sgl.v3f_t2f( 1.0, -1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f(-1.0, -1.0, 1.0, 0.25, 0.0 )
sgl.v3f_t2f(-1.0, -1.0, -1.0, 0.0 , 0.0 )
sgl.c3f(r, g, b)
sgl.v3f_t2f(-1.0, 1.0, -1.0, 0.0 , 0.25)
sgl.v3f_t2f(-1.0, 1.0, 1.0, 0.25, 0.25)
sgl.v3f_t2f( 1.0, 1.0, 1.0, 0.25, 0.0 )
sgl.v3f_t2f( 1.0, 1.0, -1.0, 0.0 , 0.0 )
sgl.end()
}
/*
Cube vertex buffer with packed vertex formats for color and texture coords.
Note that a vertex format which must be portable across all
backends must only use the normalized integer formats
(BYTE4N, UBYTE4N, SHORT2N, SHORT4N), which can be converted
to floating point formats in the vertex shader inputs.
The reason is that D3D11 cannot convert from non-normalized
formats to floating point inputs (only to integer inputs),
and WebGL2 / GLES2 don't support integer vertex shader inputs.
*/
struct Vertex_t {
x f32
y f32
z f32
color u32
// u u16
// v u16
u f32
v f32
}
fn init_cube_glsl(mut app App) {
// cube vertex buffer
// d := u16(32767/8) // for compatibility with D3D11, 32767 stand for 1
d := f32(1.0) // 0.05)
c := u32(0xFFFFFF_FF) // color RGBA8
vertices := [
// Face 0
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, d},
Vertex_t{-1.0, 1.0, -1.0, c, 0, d},
// Face 1
Vertex_t{-1.0, -1.0, 1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, 1.0, 1.0, c, 0, d},
// Face 2
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, -1.0, c, d, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, -1.0, 1.0, c, 0, d},
// Face 3
Vertex_t{ 1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, 1.0, c, 0, d},
// Face 4
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, -1.0, c, 0, d},
// Face 5
Vertex_t{-1.0, 1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, 1.0, -1.0, c, 0, d},
]
mut vert_buffer_desc := C.sg_buffer_desc{}
unsafe { C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc)) }
vert_buffer_desc.size = vertices.len * int(sizeof(Vertex_t))
vert_buffer_desc.content = byteptr(vertices.data)
vert_buffer_desc.@type = .vertexbuffer
// vert_buffer_desc.usage = .immutable
vert_buffer_desc.label = 'cube-vertices'.str
vbuf := gfx.make_buffer(&vert_buffer_desc)
/* create an index buffer for the cube */
indices := [
u16(0), 1, 2, 0, 2, 3,
6, 5, 4, 7, 6, 4,
8, 9, 10, 8, 10, 11,
14, 13, 12, 15, 14, 12,
16, 17, 18, 16, 18, 19,
22, 21, 20, 23, 22, 20
]
mut index_buffer_desc := C.sg_buffer_desc{}
unsafe { C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc)) }
index_buffer_desc.size = indices.len * int(sizeof(u16))
index_buffer_desc.content = byteptr(indices.data)
index_buffer_desc.@type = .indexbuffer
index_buffer_desc.label = 'cube-indices'.str
ibuf := gfx.make_buffer(&index_buffer_desc)
// create shader
shader := gfx.make_shader(C.cube_shader_desc())
mut pipdesc := C.sg_pipeline_desc{}
unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) }
pipdesc.layout.buffers[0].stride = int(sizeof(Vertex_t))
// the constants [C.ATTR_vs_pos, C.ATTR_vs_color0, C.ATTR_vs_texcoord0] are generated bysokol-shdc
pipdesc.layout.attrs[C.ATTR_vs_pos ].format = .float3 // x,y,z as f32
pipdesc.layout.attrs[C.ATTR_vs_color0 ].format = .ubyte4n // color as u32
pipdesc.layout.attrs[C.ATTR_vs_texcoord0].format = .float2 // u,v as f32
// pipdesc.layout.attrs[C.ATTR_vs_texcoord0].format = .short2n // u,v as u16
pipdesc.shader = shader
pipdesc.index_type = .uint16
pipdesc.depth_stencil = C.sg_depth_stencil_state{
depth_write_enabled: true
depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL)
}
pipdesc.rasterizer = C.sg_rasterizer_state{
cull_mode: .back
}
pipdesc.label = 'glsl_shader pipeline'.str
app.cube_bind.vertex_buffers[0] = vbuf
app.cube_bind.index_buffer = ibuf
app.cube_bind.fs_images[C.SLOT_tex] = app.texture
app.cube_pip_glsl = gfx.make_pipeline(&pipdesc)
println('GLSL init DONE!')
}
fn draw_cube_glsl(app App) {
if app.init_flag == false {
return
}
rot := [f32(app.mouse_y), f32(app.mouse_x)]
ws := gg.window_size()
// ratio := f32(ws.width)/ws.height
dw := f32(ws.width / 2)
dh := f32(ws.height / 2)
tr_matrix := m4.calc_tr_matrices(dw, dh, rot[0], rot[1], 2.0)
gfx.apply_viewport(ws.width / 2, 0, ws.width / 2, ws.height / 2, true)
// apply the pipline and bindings
gfx.apply_pipeline(app.cube_pip_glsl)
gfx.apply_bindings(app.cube_bind)
//***************
// Uniforms
//***************
// passing the view matrix as uniform
// res is a 4x4 matrix of f32 thus: 4*16 byte of size
gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params, &tr_matrix, 4 * 16)
// fs uniforms
time_ticks := f32(time.ticks() - app.ticks) / 1000
mut text_res := [
f32(512),
512, /* x,y resolution to pass to FS */
time_ticks, /* time as f32 */
0 /* padding 4 Bytes == 1 f32 */,
]!
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &text_res, 4 * 4)
gfx.draw(0, (3 * 2) * 6, 1)
gfx.end_pass()
gfx.commit()
}
fn draw_texture_cubes(app App) {
rot := [f32(app.mouse_x), f32(app.mouse_y)]
sgl.defaults()
sgl.load_pipeline(app.pip_3d)
sgl.enable_texture()
sgl.texture(app.texture)
sgl.matrix_mode_projection()
sgl.perspective(sgl.rad(45.0), 1.0, 0.1, 100.0)
sgl.matrix_mode_modelview()
sgl.translate(0.0, 0.0, -12.0)
sgl.rotate(sgl.rad(rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(sgl.rad(rot[1]), 0.0, 1.0, 0.0)
cube_texture(1, 1, 1)
sgl.push_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-2.0 * sgl.rad(rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(-2.0 * sgl.rad(rot[1]), 0.0, 1.0, 0.0)
cube_texture(1,1,1)
sgl.push_matrix()
sgl.translate(0.0, 0.0, 3.0)
sgl.scale(0.5, 0.5, 0.5)
sgl.rotate(-3.0 * sgl.rad(2*rot[0]), 1.0, 0.0, 0.0)
sgl.rotate(3.0 * sgl.rad(2*rot[1]), 0.0, 0.0, 1.0)
cube_texture(1,1,1)
sgl.pop_matrix()
sgl.pop_matrix()
sgl.disable_texture()
}
fn frame(mut app App) {
ws := gg.window_size()
ratio := f32(ws.width) / ws.height
dw := ws.width
dh := ws.height
ww := int(dh / 3) // not a bug
hh := int(dh / 3)
x0 := int(f32(dw) * 0.05)
// x1 := dw/2
y0 := 0
y1 := int(f32(dh) * 0.5)
// app.gg.begin()
app.gg.begin()
sgl.defaults()
// 2d triangle
sgl.viewport(x0, y0, ww, hh, true)
draw_triangle()
// colored cubes with viewport
sgl.viewport(x0, y1, ww, hh, true)
draw_cubes(app)
// textured cubed with viewport
sgl.viewport(0, int(dh / 5), dw, int(dh * ratio), true)
draw_texture_cubes(app)
app.gg.end()
// clear
mut color_action := C.sg_color_attachment_action{
action: gfx.Action(C.SG_ACTION_DONTCARE) // C.SG_ACTION_CLEAR)
}
color_action.val[0] = 1
color_action.val[1] = 1
color_action.val[2] = 1
color_action.val[3] = 1.0
mut pass_action := C.sg_pass_action{}
pass_action.colors[0] = color_action
gfx.begin_default_pass(&pass_action, ws.width, ws.height)
// glsl cube
draw_cube_glsl(app)
app.frame_count++
}
/******************************************************************************
*
* Init / Cleanup
*
******************************************************************************/
fn my_init(mut app App) {
// set max vertices,
// for a large number of the same type of object it is better use the instances!!
desc := sapp.create_desc()
gfx.setup(&desc)
sgl_desc := C.sgl_desc_t{
max_vertices: 50 * 65536
}
sgl.setup(&sgl_desc)
// 3d pipeline
mut pipdesc := C.sg_pipeline_desc{}
unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) }
pipdesc.blend.enabled = true
pipdesc.blend.src_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_SRC_ALPHA)
pipdesc.blend.dst_factor_rgb = gfx.BlendFactor(C.SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA)
pipdesc.depth_stencil = C.sg_depth_stencil_state{
depth_write_enabled: true
depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL)
}
pipdesc.rasterizer = C.sg_rasterizer_state{
cull_mode: .back
}
app.pip_3d = sgl.make_pipeline(&pipdesc)
// create chessboard texture 256*256 RGBA
w := 256
h := 256
sz := w * h * 4
tmp_txt := unsafe { malloc(sz) }
mut i := 0
for i < sz {
unsafe {
y := (i >> 0x8) >> 5 // 8 cell
x := (i & 0xFF) >> 5 // 8 cell
// upper left corner
if x == 0 && y == 0 {
tmp_txt[i] = byte(0xFF)
tmp_txt[i + 1] = byte(0)
tmp_txt[i + 2] = byte(0)
tmp_txt[i + 3] = byte(0xFF)
}
// low right corner
else if x == 7 && y == 7 {
tmp_txt[i + 0] = byte(0)
tmp_txt[i + 1] = byte(0xFF)
tmp_txt[i + 2] = byte(0)
tmp_txt[i + 3] = byte(0xFF)
} else {
col := if ((x + y) & 1) == 1 { 0xFF } else { 128 }
tmp_txt[i + 0] = byte(col) // red
tmp_txt[i + 1] = byte(col) // green
tmp_txt[i + 2] = byte(col) // blue
tmp_txt[i + 3] = byte(0xFF) // alpha
}
i += 4
}
}
app.texture = create_texture(w, h, tmp_txt)
unsafe { free(tmp_txt) }
// glsl
init_cube_glsl(mut app)
app.init_flag = true
}
fn cleanup(mut app App) {
gfx.shutdown()
}
/******************************************************************************
*
* event
*
******************************************************************************/
fn my_event_manager(mut ev gg.Event, mut app App) {
if ev.typ == .mouse_move {
app.mouse_x = int(ev.mouse_x)
app.mouse_y = int(ev.mouse_y)
}
if ev.typ == .touches_began || ev.typ == .touches_moved {
if ev.num_touches > 0 {
touch_point := ev.touches[0]
app.mouse_x = int(touch_point.pos_x)
app.mouse_y = int(touch_point.pos_y)
}
}
}
/******************************************************************************
*
* Main
*
******************************************************************************/
[console] // is needed for easier diagnostics on windows
fn main() {
// App init
mut app := &App{
gg: 0
}
mut a := [5]int{}
a[0] = 2
println(a)
app.gg = gg.new_context(
width: win_width
height: win_height
use_ortho: true // This is needed for 2D drawing
create_window: true
window_title: '3D Cube Demo'
user_data: app
bg_color: bg_color
frame_fn: frame
init_fn: my_init
cleanup_fn: cleanup
event_fn: my_event_manager
)
app.ticks = time.ticks()
app.gg.run()
}

View File

View File

@@ -0,0 +1,695 @@
//------------------------------------------------------------------------------
// Shader code for texcube-sapp sample.
//
// NOTE: This source file also uses the '#pragma sokol' form of the
// custom tags.
//------------------------------------------------------------------------------
//#pragma sokol @ctype mat4 hmm_mat4
#pragma sokol @vs vs
uniform vs_params {
mat4 mvp;
};
in vec4 pos;
in vec4 color0;
in vec2 texcoord0;
out vec4 color;
out vec2 uv;
void main() {
gl_Position = mvp * pos;
color = color0;
uv = texcoord0;
}
#pragma sokol @end
#pragma sokol @fs fs
uniform sampler2D tex;
uniform fs_params {
vec2 iResolution;
vec2 iMouse;
float iTime;
float iFrame;
};
in vec4 color;
in vec2 uv;
out vec4 frag_color;
// change to 0 to 4 to increment the AntiAliasing,
// increase AA will SLOW the rendering!!
#define AA 1
//*********************************************************
// Ray Marching
// original code from: https://www.shadertoy.com/view/Xds3zN
//*********************************************************
// The MIT License
// Copyright © 2013 Inigo Quilez
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// A list of useful distance function to simple primitives. All
// these functions (except for ellipsoid) return an exact
// euclidean distance, meaning they produce a better SDF than
// what you'd get if you were constructing them from boolean
// operations.
//
// More info here:
//
// https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
//------------------------------------------------------------------
float dot2( in vec2 v ) { return dot(v,v); }
float dot2( in vec3 v ) { return dot(v,v); }
float ndot( in vec2 a, in vec2 b ) { return a.x*b.x - a.y*b.y; }
float sdPlane( vec3 p )
{
return p.y;
}
float sdSphere( vec3 p, float s )
{
return length(p)-s;
}
float sdBox( vec3 p, vec3 b )
{
vec3 d = abs(p) - b;
return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}
float sdBoundingBox( vec3 p, vec3 b, float e )
{
p = abs(p )-b;
vec3 q = abs(p+e)-e;
return min(min(
length(max(vec3(p.x,q.y,q.z),0.0))+min(max(p.x,max(q.y,q.z)),0.0),
length(max(vec3(q.x,p.y,q.z),0.0))+min(max(q.x,max(p.y,q.z)),0.0)),
length(max(vec3(q.x,q.y,p.z),0.0))+min(max(q.x,max(q.y,p.z)),0.0));
}
float sdEllipsoid( in vec3 p, in vec3 r ) // approximated
{
float k0 = length(p/r);
float k1 = length(p/(r*r));
return k0*(k0-1.0)/k1;
}
float sdTorus( vec3 p, vec2 t )
{
return length( vec2(length(p.xz)-t.x,p.y) )-t.y;
}
float sdCappedTorus(in vec3 p, in vec2 sc, in float ra, in float rb)
{
p.x = abs(p.x);
float k = (sc.y*p.x>sc.x*p.y) ? dot(p.xy,sc) : length(p.xy);
return sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb;
}
float sdHexPrism( vec3 p, vec2 h )
{
vec3 q = abs(p);
const vec3 k = vec3(-0.8660254, 0.5, 0.57735);
p = abs(p);
p.xy -= 2.0*min(dot(k.xy, p.xy), 0.0)*k.xy;
vec2 d = vec2(
length(p.xy - vec2(clamp(p.x, -k.z*h.x, k.z*h.x), h.x))*sign(p.y - h.x),
p.z-h.y );
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
float sdOctogonPrism( in vec3 p, in float r, float h )
{
const vec3 k = vec3(-0.9238795325, // sqrt(2+sqrt(2))/2
0.3826834323, // sqrt(2-sqrt(2))/2
0.4142135623 ); // sqrt(2)-1
// reflections
p = abs(p);
p.xy -= 2.0*min(dot(vec2( k.x,k.y),p.xy),0.0)*vec2( k.x,k.y);
p.xy -= 2.0*min(dot(vec2(-k.x,k.y),p.xy),0.0)*vec2(-k.x,k.y);
// polygon side
p.xy -= vec2(clamp(p.x, -k.z*r, k.z*r), r);
vec2 d = vec2( length(p.xy)*sign(p.y), p.z-h );
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
float sdCapsule( vec3 p, vec3 a, vec3 b, float r )
{
vec3 pa = p-a, ba = b-a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
return length( pa - ba*h ) - r;
}
float sdRoundCone( in vec3 p, in float r1, float r2, float h )
{
vec2 q = vec2( length(p.xz), p.y );
float b = (r1-r2)/h;
float a = sqrt(1.0-b*b);
float k = dot(q,vec2(-b,a));
if( k < 0.0 ) return length(q) - r1;
if( k > a*h ) return length(q-vec2(0.0,h)) - r2;
return dot(q, vec2(a,b) ) - r1;
}
float sdRoundCone(vec3 p, vec3 a, vec3 b, float r1, float r2)
{
// sampling independent computations (only depend on shape)
vec3 ba = b - a;
float l2 = dot(ba,ba);
float rr = r1 - r2;
float a2 = l2 - rr*rr;
float il2 = 1.0/l2;
// sampling dependant computations
vec3 pa = p - a;
float y = dot(pa,ba);
float z = y - l2;
float x2 = dot2( pa*l2 - ba*y );
float y2 = y*y*l2;
float z2 = z*z*l2;
// single square root!
float k = sign(rr)*rr*rr*x2;
if( sign(z)*a2*z2 > k ) return sqrt(x2 + z2) *il2 - r2;
if( sign(y)*a2*y2 < k ) return sqrt(x2 + y2) *il2 - r1;
return (sqrt(x2*a2*il2)+y*rr)*il2 - r1;
}
float sdTriPrism( vec3 p, vec2 h )
{
const float k = sqrt(3.0);
h.x *= 0.5*k;
p.xy /= h.x;
p.x = abs(p.x) - 1.0;
p.y = p.y + 1.0/k;
if( p.x+k*p.y>0.0 ) p.xy=vec2(p.x-k*p.y,-k*p.x-p.y)/2.0;
p.x -= clamp( p.x, -2.0, 0.0 );
float d1 = length(p.xy)*sign(-p.y)*h.x;
float d2 = abs(p.z)-h.y;
return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);
}
// vertical
float sdCylinder( vec3 p, vec2 h )
{
vec2 d = abs(vec2(length(p.xz),p.y)) - h;
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
// arbitrary orientation
float sdCylinder(vec3 p, vec3 a, vec3 b, float r)
{
vec3 pa = p - a;
vec3 ba = b - a;
float baba = dot(ba,ba);
float paba = dot(pa,ba);
float x = length(pa*baba-ba*paba) - r*baba;
float y = abs(paba-baba*0.5)-baba*0.5;
float x2 = x*x;
float y2 = y*y*baba;
float d = (max(x,y)<0.0)?-min(x2,y2):(((x>0.0)?x2:0.0)+((y>0.0)?y2:0.0));
return sign(d)*sqrt(abs(d))/baba;
}
// vertical
float sdCone( in vec3 p, in vec2 c, float h )
{
vec2 q = h*vec2(c.x,-c.y)/c.y;
vec2 w = vec2( length(p.xz), p.y );
vec2 a = w - q*clamp( dot(w,q)/dot(q,q), 0.0, 1.0 );
vec2 b = w - q*vec2( clamp( w.x/q.x, 0.0, 1.0 ), 1.0 );
float k = sign( q.y );
float d = min(dot( a, a ),dot(b, b));
float s = max( k*(w.x*q.y-w.y*q.x),k*(w.y-q.y) );
return sqrt(d)*sign(s);
}
float sdCappedCone( in vec3 p, in float h, in float r1, in float r2 )
{
vec2 q = vec2( length(p.xz), p.y );
vec2 k1 = vec2(r2,h);
vec2 k2 = vec2(r2-r1,2.0*h);
vec2 ca = vec2(q.x-min(q.x,(q.y < 0.0)?r1:r2), abs(q.y)-h);
vec2 cb = q - k1 + k2*clamp( dot(k1-q,k2)/dot2(k2), 0.0, 1.0 );
float s = (cb.x < 0.0 && ca.y < 0.0) ? -1.0 : 1.0;
return s*sqrt( min(dot2(ca),dot2(cb)) );
}
float sdCappedCone(vec3 p, vec3 a, vec3 b, float ra, float rb)
{
float rba = rb-ra;
float baba = dot(b-a,b-a);
float papa = dot(p-a,p-a);
float paba = dot(p-a,b-a)/baba;
float x = sqrt( papa - paba*paba*baba );
float cax = max(0.0,x-((paba<0.5)?ra:rb));
float cay = abs(paba-0.5)-0.5;
float k = rba*rba + baba;
float f = clamp( (rba*(x-ra)+paba*baba)/k, 0.0, 1.0 );
float cbx = x-ra - f*rba;
float cby = paba - f;
float s = (cbx < 0.0 && cay < 0.0) ? -1.0 : 1.0;
return s*sqrt( min(cax*cax + cay*cay*baba,
cbx*cbx + cby*cby*baba) );
}
// c is the sin/cos of the desired cone angle
float sdSolidAngle(vec3 pos, vec2 c, float ra)
{
vec2 p = vec2( length(pos.xz), pos.y );
float l = length(p) - ra;
float m = length(p - c*clamp(dot(p,c),0.0,ra) );
return max(l,m*sign(c.y*p.x-c.x*p.y));
}
float sdOctahedron(vec3 p, float s)
{
p = abs(p);
float m = p.x + p.y + p.z - s;
// exact distance
#if 0
vec3 o = min(3.0*p - m, 0.0);
o = max(6.0*p - m*2.0 - o*3.0 + (o.x+o.y+o.z), 0.0);
return length(p - s*o/(o.x+o.y+o.z));
#endif
// exact distance
#if 1
vec3 q;
if( 3.0*p.x < m ) q = p.xyz;
else if( 3.0*p.y < m ) q = p.yzx;
else if( 3.0*p.z < m ) q = p.zxy;
else return m*0.57735027;
float k = clamp(0.5*(q.z-q.y+s),0.0,s);
return length(vec3(q.x,q.y-s+k,q.z-k));
#endif
// bound, not exact
#if 0
return m*0.57735027;
#endif
}
float sdPyramid( in vec3 p, in float h )
{
float m2 = h*h + 0.25;
// symmetry
p.xz = abs(p.xz);
p.xz = (p.z>p.x) ? p.zx : p.xz;
p.xz -= 0.5;
// project into face plane (2D)
vec3 q = vec3( p.z, h*p.y - 0.5*p.x, h*p.x + 0.5*p.y);
float s = max(-q.x,0.0);
float t = clamp( (q.y-0.5*p.z)/(m2+0.25), 0.0, 1.0 );
float a = m2*(q.x+s)*(q.x+s) + q.y*q.y;
float b = m2*(q.x+0.5*t)*(q.x+0.5*t) + (q.y-m2*t)*(q.y-m2*t);
float d2 = min(q.y,-q.x*m2-q.y*0.5) > 0.0 ? 0.0 : min(a,b);
// recover 3D and scale, and add sign
return sqrt( (d2+q.z*q.z)/m2 ) * sign(max(q.z,-p.y));
}
// la,lb=semi axis, h=height, ra=corner
float sdRhombus(vec3 p, float la, float lb, float h, float ra)
{
p = abs(p);
vec2 b = vec2(la,lb);
float f = clamp( (ndot(b,b-2.0*p.xz))/dot(b,b), -1.0, 1.0 );
vec2 q = vec2(length(p.xz-0.5*b*vec2(1.0-f,1.0+f))*sign(p.x*b.y+p.z*b.x-b.x*b.y)-ra, p.y-h);
return min(max(q.x,q.y),0.0) + length(max(q,0.0));
}
//------------------------------------------------------------------
vec2 opU( vec2 d1, vec2 d2 )
{
return (d1.x<d2.x) ? d1 : d2;
}
//------------------------------------------------------------------
#define ZERO (min(int(iFrame),0))
//------------------------------------------------------------------
vec2 map( in vec3 pos )
{
vec2 res = vec2( 1e10, 0.0 );
{
res = opU( res, vec2( sdSphere( pos-vec3(-2.0,0.25, 0.0), 0.25 ), 26.9 ) );
}
// bounding box
if( sdBox( pos-vec3(0.0,0.3,-1.0),vec3(0.35,0.3,2.5) )<res.x )
{
// more primitives
res = opU( res, vec2( sdBoundingBox( pos-vec3( 0.0,0.25, 0.0), vec3(0.3,0.25,0.2), 0.025 ), 16.9 ) );
res = opU( res, vec2( sdTorus( (pos-vec3( 0.0,0.30, 1.0)).xzy, vec2(0.25,0.05) ), 25.0 ) );
res = opU( res, vec2( sdCone( pos-vec3( 0.0,0.45,-1.0), vec2(0.6,0.8),0.45 ), 55.0 ) );
res = opU( res, vec2( sdCappedCone( pos-vec3( 0.0,0.25,-2.0), 0.25, 0.25, 0.1 ), 13.67 ) );
res = opU( res, vec2( sdSolidAngle( pos-vec3( 0.0,0.00,-3.0), vec2(3,4)/5.0, 0.4 ), 49.13 ) );
}
// bounding box
if( sdBox( pos-vec3(1.0,0.3,-1.0),vec3(0.35,0.3,2.5) )<res.x )
{
// more primitives
res = opU( res, vec2( sdCappedTorus((pos-vec3( 1.0,0.30, 1.0))*vec3(1,-1,1), vec2(0.866025,-0.5), 0.25, 0.05), 8.5) );
res = opU( res, vec2( sdBox( pos-vec3( 1.0,0.25, 0.0), vec3(0.3,0.25,0.1) ), 3.0 ) );
res = opU( res, vec2( sdCapsule( pos-vec3( 1.0,0.00,-1.0),vec3(-0.1,0.1,-0.1), vec3(0.2,0.4,0.2), 0.1 ), 31.9 ) );
res = opU( res, vec2( sdCylinder( pos-vec3( 1.0,0.25,-2.0), vec2(0.15,0.25) ), 8.0 ) );
res = opU( res, vec2( sdHexPrism( pos-vec3( 1.0,0.2,-3.0), vec2(0.2,0.05) ), 18.4 ) );
}
// bounding box
if( sdBox( pos-vec3(-1.0,0.35,-1.0),vec3(0.35,0.35,2.5))<res.x )
{
// more primitives
res = opU( res, vec2( sdPyramid( pos-vec3(-1.0,-0.6,-3.0), 1.0 ), 13.56 ) );
res = opU( res, vec2( sdOctahedron( pos-vec3(-1.0,0.15,-2.0), 0.35 ), 23.56 ) );
res = opU( res, vec2( sdTriPrism( pos-vec3(-1.0,0.15,-1.0), vec2(0.3,0.05) ),43.5 ) );
res = opU( res, vec2( sdEllipsoid( pos-vec3(-1.0,0.25, 0.0), vec3(0.2, 0.25, 0.05) ), 43.17 ) );
res = opU( res, vec2( sdRhombus( (pos-vec3(-1.0,0.34, 1.0)).xzy, 0.15, 0.25, 0.04, 0.08 ),17.0 ) );
}
// bounding box
if( sdBox( pos-vec3(2.0,0.3,-1.0),vec3(0.35,0.3,2.5) )<res.x )
{
// more primitives
res = opU( res, vec2( sdOctogonPrism(pos-vec3( 2.0,0.2,-3.0), 0.2, 0.05), 51.8 ) );
res = opU( res, vec2( sdCylinder( pos-vec3( 2.0,0.15,-2.0), vec3(0.1,-0.1,0.0), vec3(-0.2,0.35,0.1), 0.08), 31.2 ) );
res = opU( res, vec2( sdCappedCone( pos-vec3( 2.0,0.10,-1.0), vec3(0.1,0.0,0.0), vec3(-0.2,0.40,0.1), 0.15, 0.05), 46.1 ) );
res = opU( res, vec2( sdRoundCone( pos-vec3( 2.0,0.15, 0.0), vec3(0.1,0.0,0.0), vec3(-0.1,0.35,0.1), 0.15, 0.05), 51.7 ) );
res = opU( res, vec2( sdRoundCone( pos-vec3( 2.0,0.20, 1.0), 0.2, 0.1, 0.3 ), 37.0 ) );
}
return res;
}
// http://iquilezles.org/www/articles/boxfunctions/boxfunctions.htm
vec2 iBox( in vec3 ro, in vec3 rd, in vec3 rad )
{
vec3 m = 1.0/rd;
vec3 n = m*ro;
vec3 k = abs(m)*rad;
vec3 t1 = -n - k;
vec3 t2 = -n + k;
return vec2( max( max( t1.x, t1.y ), t1.z ),
min( min( t2.x, t2.y ), t2.z ) );
}
vec2 raycast( in vec3 ro, in vec3 rd )
{
vec2 res = vec2(-1.0,-1.0);
float tmin = 1.0;
float tmax = 20.0;
// raytrace floor plane
float tp1 = (0.0-ro.y)/rd.y;
if( tp1>0.0 )
{
tmax = min( tmax, tp1 );
res = vec2( tp1, 1.0 );
}
//else return res;
// raymarch primitives
vec2 tb = iBox( ro-vec3(0.0,0.4,-0.5), rd, vec3(2.5,0.41,3.0) );
if( tb.x<tb.y && tb.y>0.0 && tb.x<tmax)
{
//return vec2(tb.x,2.0);
tmin = max(tb.x,tmin);
tmax = min(tb.y,tmax);
float t = tmin;
for( int i=0; i<70 && t<tmax; i++ )
{
vec2 h = map( ro+rd*t );
if( abs(h.x)<(0.0001*t) )
{
res = vec2(t,h.y);
break;
}
t += h.x;
}
}
return res;
}
// http://iquilezles.org/www/articles/rmshadows/rmshadows.htm
float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax )
{
// bounding volume
float tp = (0.8-ro.y)/rd.y; if( tp>0.0 ) tmax = min( tmax, tp );
float res = 1.0;
float t = mint;
for( int i=ZERO; i<24; i++ )
{
float h = map( ro + rd*t ).x;
float s = clamp(8.0*h/t,0.0,1.0);
res = min( res, s*s*(3.0-2.0*s) );
t += clamp( h, 0.02, 0.2 );
if( res<0.004 || t>tmax ) break;
}
return clamp( res, 0.0, 1.0 );
}
// http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm
vec3 calcNormal( in vec3 pos )
{
#if 0
vec2 e = vec2(1.0,-1.0)*0.5773*0.0005;
return normalize( e.xyy*map( pos + e.xyy ).x +
e.yyx*map( pos + e.yyx ).x +
e.yxy*map( pos + e.yxy ).x +
e.xxx*map( pos + e.xxx ).x );
#else
// inspired by tdhooper and klems - a way to prevent the compiler from inlining map() 4 times
vec3 n = vec3(0.0);
for( int i=ZERO; i<4; i++ )
{
vec3 e = 0.5773*(2.0*vec3((((i+3)>>1)&1),((i>>1)&1),(i&1))-1.0);
n += e*map(pos+0.0005*e).x;
//if( n.x+n.y+n.z>100.0 ) break;
}
return normalize(n);
#endif
}
float calcAO( in vec3 pos, in vec3 nor )
{
float occ = 0.0;
float sca = 1.0;
for( int i=ZERO; i<5; i++ )
{
float h = 0.01 + 0.12*float(i)/4.0;
float d = map( pos + h*nor ).x;
occ += (h-d)*sca;
sca *= 0.95;
if( occ>0.35 ) break;
}
return clamp( 1.0 - 3.0*occ, 0.0, 1.0 ) * (0.5+0.5*nor.y);
}
// http://iquilezles.org/www/articles/checkerfiltering/checkerfiltering.htm
float checkersGradBox( in vec2 p, in vec2 dpdx, in vec2 dpdy )
{
// filter kernel
vec2 w = abs(dpdx)+abs(dpdy) + 0.001;
// analytical integral (box filter)
vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w;
// xor pattern
return 0.5 - 0.5*i.x*i.y;
}
vec3 render( in vec3 ro, in vec3 rd, in vec3 rdx, in vec3 rdy )
{
// background
vec3 col = vec3(0.7, 0.7, 0.9) - max(rd.y,0.0)*0.3;
// raycast scene
vec2 res = raycast(ro,rd);
float t = res.x;
float m = res.y;
if( m>-0.5 )
{
vec3 pos = ro + t*rd;
vec3 nor = (m<1.5) ? vec3(0.0,1.0,0.0) : calcNormal( pos );
vec3 ref = reflect( rd, nor );
// material
col = 0.2 + 0.2*sin( m*2.0 + vec3(0.0,1.0,2.0) );
float ks = 1.0;
if( m<1.5 )
{
// project pixel footprint into the plane
vec3 dpdx = ro.y*(rd/rd.y-rdx/rdx.y);
vec3 dpdy = ro.y*(rd/rd.y-rdy/rdy.y);
float f = checkersGradBox( 3.0*pos.xz, 3.0*dpdx.xz, 3.0*dpdy.xz );
col = 0.15 + f*vec3(0.05);
ks = 0.4;
}
// lighting
float occ = calcAO( pos, nor );
vec3 lin = vec3(0.0);
// sun
{
vec3 lig = normalize( vec3(-0.5, 0.4, -0.6) );
vec3 hal = normalize( lig-rd );
float dif = clamp( dot( nor, lig ), 0.0, 1.0 );
//if( dif>0.0001 )
dif *= calcSoftshadow( pos, lig, 0.02, 2.5 );
float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0);
spe *= dif;
spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0);
lin += col*2.20*dif*vec3(1.30,1.00,0.70);
lin += 5.00*spe*vec3(1.30,1.00,0.70)*ks;
}
// sky
{
float dif = sqrt(clamp( 0.5+0.5*nor.y, 0.0, 1.0 ));
dif *= occ;
float spe = smoothstep( -0.2, 0.2, ref.y );
spe *= dif;
spe *= 0.04+0.96*pow(clamp(1.0+dot(nor,rd),0.0,1.0), 5.0 );
//if( spe>0.001 )
spe *= calcSoftshadow( pos, ref, 0.02, 2.5 );
lin += col*0.60*dif*vec3(0.40,0.60,1.15);
lin += 2.00*spe*vec3(0.40,0.60,1.30)*ks;
}
// back
{
float dif = clamp( dot( nor, normalize(vec3(0.5,0.0,0.6))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0);
dif *= occ;
lin += col*0.55*dif*vec3(0.25,0.25,0.25);
}
// sss
{
float dif = pow(clamp(1.0+dot(nor,rd),0.0,1.0),2.0);
dif *= occ;
lin += col*0.25*dif*vec3(1.00,1.00,1.00);
}
col = lin;
col = mix( col, vec3(0.7,0.7,0.9), 1.0-exp( -0.0001*t*t*t ) );
}
return vec3( clamp(col,0.0,1.0) );
}
mat3 setCamera( in vec3 ro, in vec3 ta, float cr )
{
vec3 cw = normalize(ta-ro);
vec3 cp = vec3(sin(cr), cos(cr),0.0);
vec3 cu = normalize( cross(cw,cp) );
vec3 cv = ( cross(cu,cw) );
return mat3( cu, cv, cw );
}
vec4 mainImage( vec2 fragCoord )
{
vec2 mo = iMouse.xy/iResolution.xy;
float time = 32.0 + iTime*1.5;
// camera
vec3 ta = vec3( 0.5, -0.5, -0.6 );
vec3 ro = ta + vec3( 4.5*cos(0.1*time + 7.0*mo.x), 1.3 + 2.0*mo.y, 4.5*sin(0.1*time + 7.0*mo.x) );
// camera-to-world transformation
mat3 ca = setCamera( ro, ta, 0.0 );
vec3 tot = vec3(0.0);
#if AA>1
for( int m=ZERO; m<AA; m++ )
for( int n=ZERO; n<AA; n++ )
{
// pixel coordinates
vec2 o = vec2(float(m),float(n)) / float(AA) - 0.5;
vec2 p = (2.0*(fragCoord+o)-iResolution.xy)/iResolution.y;
#else
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
#endif
// focal length
const float fl = 2.5;
// ray direction
vec3 rd = ca * normalize( vec3(p,fl) );
// ray differentials
vec2 px = (2.0*(fragCoord+vec2(1.0,0.0))-iResolution.xy)/iResolution.y;
vec2 py = (2.0*(fragCoord+vec2(0.0,1.0))-iResolution.xy)/iResolution.y;
vec3 rdx = ca * normalize( vec3(px,fl) );
vec3 rdy = ca * normalize( vec3(py,fl) );
// render
vec3 col = render( ro, rd, rdx, rdy );
// gain
// col = col*3.0/(2.5+col);
// gamma
col = pow( col, vec3(0.4545) );
tot += col;
#if AA>1
}
tot /= float(AA*AA);
#endif
//fragColor = vec4( tot, 1.0 );
return vec4( tot, 1.0 );
}
//*********************************************************
// END Ray Marching
//*********************************************************
void main() {
vec4 c = color;
vec4 txt = texture(tex, uv);
c = txt * c;
vec2 uv1 = uv * iResolution;
vec4 col_ray = mainImage(uv1);
// use this to mix the chessboart texture with the ray marching
//frag_color = clamp(c*iMouse.y/512.0,0.0,1.0) * col_ray ;
frag_color = c*0.00001 + col_ray ;
}
#pragma sokol @end
#pragma sokol @program rt vs fs

View File

@@ -0,0 +1,421 @@
/**********************************************************************
*
* Sokol 3d cube demo
*
* Copyright (c) 2021 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
* that can be found in the LICENSE file.
*
* HOW TO COMPILE SHADERS:
* - download the sokol shader convertor tool from https://github.com/floooh/sokol-tools-bin/archive/pre-feb2021-api-changes.tar.gz
* ( also look at https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md )
* - compile the .glsl shader with:
* linux : sokol-shdc --input rt_glsl.glsl --output rt_glsl.h --slang glsl330
* windows: sokol-shdc.exe --input rt_glsl.glsl --output rt_glsl.h --slang glsl330
*
* --slang parameter can be:
* - glsl330: desktop GL
* - glsl100: GLES2 / WebGL
* - glsl300es: GLES3 / WebGL2
* - hlsl4: D3D11
* - hlsl5: D3D11
* - metal_macos: Metal on macOS
* - metal_ios: Metal on iOS device
* - metal_sim: Metal on iOS simulator
* - wgpu: WebGPU
*
* you can have multiple platforms at the same time passing parameters like this: --slang glsl330:hlsl5:metal_macos
* for further infos have a look at the sokol shader tool docs.
*
* TODO:
* - frame counter
**********************************************************************/
import gg
import gg.m4
import gx
// import math
import sokol.sapp
import sokol.gfx
import sokol.sgl
import time
// GLSL Include and functions
#flag -I @VROOT/.
#include "rt_glsl.h" #Please use sokol-shdc to generate the necessary rt_glsl.h file from rt_glsl.glsl (see the instructions at the top of this file)
fn C.rt_shader_desc() &C.sg_shader_desc
const (
win_width = 800
win_height = 800
bg_color = gx.white
)
struct App {
mut:
gg &gg.Context
texture C.sg_image
init_flag bool
frame_count int
mouse_x int = -1
mouse_y int = -1
// glsl
cube_pip_glsl C.sg_pipeline
cube_bind C.sg_bindings
// time
ticks i64
}
/******************************************************************************
* Texture functions
******************************************************************************/
fn create_texture(w int, h int, buf byteptr) C.sg_image {
sz := w * h * 4
mut img_desc := C.sg_image_desc{
width: w
height: h
num_mipmaps: 0
min_filter: .linear
mag_filter: .linear
// usage: .dynamic
wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge
label: &byte(0)
d3d11_texture: 0
}
// comment if .dynamic is enabled
img_desc.content.subimage[0][0] = C.sg_subimage_content{
ptr: buf
size: sz
}
sg_img := C.sg_make_image(&img_desc)
return sg_img
}
fn destroy_texture(sg_img C.sg_image) {
C.sg_destroy_image(sg_img)
}
// Use only if usage: .dynamic is enabled
fn update_text_texture(sg_img C.sg_image, w int, h int, buf byteptr) {
sz := w * h * 4
mut tmp_sbc := C.sg_image_content{}
tmp_sbc.subimage[0][0] = C.sg_subimage_content{
ptr: buf
size: sz
}
C.sg_update_image(sg_img, &tmp_sbc)
}
/******************************************************************************
* Draw functions
******************************************************************************
Cube vertex buffer with packed vertex formats for color and texture coords.
Note that a vertex format which must be portable across all
backends must only use the normalized integer formats
(BYTE4N, UBYTE4N, SHORT2N, SHORT4N), which can be converted
to floating point formats in the vertex shader inputs.
The reason is that D3D11 cannot convert from non-normalized
formats to floating point inputs (only to integer inputs),
and WebGL2 / GLES2 don't support integer vertex shader inputs.
*/
struct Vertex_t {
x f32
y f32
z f32
color u32
u f32
v f32
// u u16 // for compatibility with D3D11
// v u16 // for compatibility with D3D11
}
fn init_cube_glsl(mut app App) {
// cube vertex buffer
// d := u16(32767) // for compatibility with D3D11, 32767 stand for 1
d := f32(1.0)
c := u32(0xFFFFFF_FF) // color RGBA8
vertices := [
// Face 0
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, d},
Vertex_t{-1.0, 1.0, -1.0, c, 0, d},
// Face 1
Vertex_t{-1.0, -1.0, 1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, 1.0, 1.0, c, 0, d},
// Face 2
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, -1.0, c, d, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, -1.0, 1.0, c, 0, d},
// Face 3
Vertex_t{ 1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, 1.0, c, 0, d},
// Face 4
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, -1.0, c, 0, d},
// Face 5
Vertex_t{-1.0, 1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, 1.0, -1.0, c, 0, d},
]
mut vert_buffer_desc := C.sg_buffer_desc{}
unsafe { C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc)) }
vert_buffer_desc.size = vertices.len * int(sizeof(Vertex_t))
vert_buffer_desc.content = byteptr(vertices.data)
vert_buffer_desc.@type = .vertexbuffer
vert_buffer_desc.label = 'cube-vertices'.str
vbuf := gfx.make_buffer(&vert_buffer_desc)
// create an index buffer for the cube
indices := [
u16(0), 1, 2, 0, 2, 3,
6, 5, 4, 7, 6, 4,
8, 9, 10, 8, 10, 11,
14, 13, 12, 15, 14, 12,
16, 17, 18, 16, 18, 19,
22, 21, 20, 23, 22, 20,
]
mut index_buffer_desc := C.sg_buffer_desc{}
unsafe {C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc))}
index_buffer_desc.size = indices.len * int(sizeof(u16))
index_buffer_desc.content = byteptr(indices.data)
index_buffer_desc.@type = .indexbuffer
index_buffer_desc.label = "cube-indices".str
ibuf := gfx.make_buffer(&index_buffer_desc)
// create shader
shader := gfx.make_shader(C.rt_shader_desc())
mut pipdesc := C.sg_pipeline_desc{}
unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) }
pipdesc.layout.buffers[0].stride = int(sizeof(Vertex_t))
// the constants [C.ATTR_vs_pos, C.ATTR_vs_color0, C.ATTR_vs_texcoord0] are generated by sokol-shdc
pipdesc.layout.attrs[C.ATTR_vs_pos ].format = .float3 // x,y,z as f32
pipdesc.layout.attrs[C.ATTR_vs_color0 ].format = .ubyte4n // color as u32
pipdesc.layout.attrs[C.ATTR_vs_texcoord0].format = .float2 // u,v as f32
// pipdesc.layout.attrs[C.ATTR_vs_texcoord0].format = .short2n // u,v as u16
pipdesc.shader = shader
pipdesc.index_type = .uint16
pipdesc.depth_stencil = C.sg_depth_stencil_state{
depth_write_enabled: true
depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL)
}
pipdesc.rasterizer = C.sg_rasterizer_state{
cull_mode: .back
}
pipdesc.label = 'glsl_shader pipeline'.str
app.cube_bind.vertex_buffers[0] = vbuf
app.cube_bind.index_buffer = ibuf
app.cube_bind.fs_images[C.SLOT_tex] = app.texture
app.cube_pip_glsl = gfx.make_pipeline(&pipdesc)
println('GLSL init DONE!')
}
[inline]
fn vec4(x f32, y f32, z f32, w f32) m4.Vec4 {
return m4.Vec4{e:[x, y, z, w]!}
}
fn calc_tr_matrices(w f32, h f32, rx f32, ry f32, in_scale f32) m4.Mat4 {
proj := m4.perspective(60, w/h, 0.01, 10.0)
view := m4.look_at(vec4(f32(0.0) ,0 , 6, 0), vec4(f32(0), 0, 0, 0), vec4(f32(0), 1, 0, 0))
view_proj := view * proj
rxm := m4.rotate(m4.rad(rx), vec4(f32(1), 0, 0, 0))
rym := m4.rotate(m4.rad(ry), vec4(f32(0), 1, 0, 0))
model := rym * rxm
scale_m := m4.scale(vec4(in_scale, in_scale, in_scale, 1))
res := (scale_m * model) * view_proj
return res
}
fn draw_cube_glsl(app App) {
if app.init_flag == false {
return
}
ws := gg.window_size()
ratio := f32(ws.width) / ws.height
dw := f32(ws.width / 2)
dh := f32(ws.height / 2)
// use the following commented lines to rotate the 3d glsl cube
// rot := [f32(app.mouse_y), f32(app.mouse_x)]
// calc_tr_matrices(dw, dh, rot[0], rot[1] ,2.3)
tr_matrix := calc_tr_matrices(dw, dh, 0, 0, 2.3)
gfx.apply_viewport(0, 0, ws.width, ws.height, true)
// apply the pipline and bindings
gfx.apply_pipeline(app.cube_pip_glsl)
gfx.apply_bindings(app.cube_bind)
// Uniforms
// *** vertex shadeer uniforms ***
// passing the view matrix as uniform
// res is a 4x4 matrix of f32 thus: 4*16 byte of size
gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params, &tr_matrix, 4 * 16)
// *** fragment shader uniforms ***
time_ticks := f32(time.ticks() - app.ticks) / 1000
mut tmp_fs_params := [
f32(ws.width),
ws.height * ratio, // x,y resolution to pass to FS
app.mouse_x, // mouse x
ws.height - app.mouse_y * 2, // mouse y scaled
time_ticks, // time as f32
app.frame_count, // frame count
0,
0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
]!
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &tmp_fs_params, int(sizeof(tmp_fs_params)))
// 3 vertices for triangle * 2 triangles per face * 6 faces = 36 vertices to draw
gfx.draw(0, (3 * 2) * 6, 1)
gfx.end_pass()
gfx.commit()
}
fn frame(mut app App) {
ws := gg.window_size()
// clear
mut color_action := C.sg_color_attachment_action{
action: gfx.Action(C.SG_ACTION_CLEAR)
}
color_action.val[0] = 0
color_action.val[1] = 0
color_action.val[2] = 0
color_action.val[3] = 1.0
mut pass_action := C.sg_pass_action{}
pass_action.colors[0] = color_action
gfx.begin_default_pass(&pass_action, ws.width, ws.height)
// glsl cube
draw_cube_glsl(app)
app.frame_count++
}
/******************************************************************************
* Init / Cleanup
******************************************************************************/
fn my_init(mut app App) {
// set max vertices,
// for a large number of the same type of object it is better use the instances!!
desc := sapp.create_desc()
gfx.setup(&desc)
sgl_desc := C.sgl_desc_t{
max_vertices: 50 * 65536
}
sgl.setup(&sgl_desc)
// create chessboard texture 256*256 RGBA
w := 256
h := 256
sz := w * h * 4
tmp_txt := unsafe { malloc(sz) }
mut i := 0
for i < sz {
unsafe {
y := (i >> 0x8) >> 5 // 8 cell
x := (i & 0xFF) >> 5 // 8 cell
// upper left corner
if x == 0 && y == 0 {
tmp_txt[i + 0] = byte(0xFF)
tmp_txt[i + 1] = byte(0)
tmp_txt[i + 2] = byte(0)
tmp_txt[i + 3] = byte(0xFF)
}
// low right corner
else if x == 7 && y == 7 {
tmp_txt[i + 0] = byte(0)
tmp_txt[i + 1] = byte(0xFF)
tmp_txt[i + 2] = byte(0)
tmp_txt[i + 3] = byte(0xFF)
} else {
col := if ((x + y) & 1) == 1 { 0xFF } else { 128 }
tmp_txt[i + 0] = byte(col) // red
tmp_txt[i + 1] = byte(col) // green
tmp_txt[i + 2] = byte(col) // blue
tmp_txt[i + 3] = byte(0xFF) // alpha
}
i += 4
}
}
unsafe {
app.texture = create_texture(w, h, tmp_txt)
free(tmp_txt)
}
// glsl
init_cube_glsl(mut app)
app.init_flag = true
}
fn cleanup(mut app App) {
gfx.shutdown()
}
/******************************************************************************
* events handling
******************************************************************************/
fn my_event_manager(mut ev gg.Event, mut app App) {
if ev.typ == .mouse_move {
app.mouse_x = int(ev.mouse_x)
app.mouse_y = int(ev.mouse_y)
}
if ev.typ == .touches_began || ev.typ == .touches_moved {
if ev.num_touches > 0 {
touch_point := ev.touches[0]
app.mouse_x = int(touch_point.pos_x)
app.mouse_y = int(touch_point.pos_y)
}
}
}
/******************************************************************************
* Main
******************************************************************************/
[console] // is needed for easier diagnostics on windows
fn main() {
// App init
mut app := &App{
gg: 0
}
app.gg = gg.new_context(
width: win_width
height: win_height
use_ortho: true // This is needed for 2D drawing
create_window: true
window_title: '3D Ray Marching Cube'
user_data: app
bg_color: bg_color
frame_fn: frame
init_fn: my_init
cleanup_fn: cleanup
event_fn: my_event_manager
)
app.ticks = time.ticks()
app.gg.run()
}

View File

@@ -0,0 +1,612 @@
/**********************************************************************
*
* Sokol 3d cube multishader demo
*
* Copyright (c) 2021 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
* that can be found in the LICENSE file.
*
* HOW TO COMPILE SHADERS:
* - download the sokol shader convertor tool from https://github.com/floooh/sokol-tools-bin/archive/pre-feb2021-api-changes.tar.gz
* ( also look at https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md )
* - compile the .glsl shared file with:
* linux : sokol-shdc --input rt_glsl_puppy.glsl --output rt_glsl_puppy.h --slang glsl330
sokol-shdc --input rt_glsl_march.glsl --output rt_glsl_march.h --slang glsl330
* windows: sokol-shdc.exe --input rt_glsl_puppy.glsl --output rt_glsl_puppy.h --slang glsl330
* sokol-shdc.exe --input rt_glsl_march.glsl --output rt_glsl_march.h --slang glsl330
*
* --slang parameter can be:
* - glsl330: desktop GL
* - glsl100: GLES2 / WebGL
* - glsl300es: GLES3 / WebGL2
* - hlsl4: D3D11
* - hlsl5: D3D11
* - metal_macos: Metal on macOS
* - metal_ios: Metal on iOS device
* - metal_sim: Metal on iOS simulator
* - wgpu: WebGPU
*
* you can have multiple platforms at the same time passing parameters like this: --slang glsl330:hlsl5:metal_macos
* for further infos have a look at the sokol shader tool docs.
*
* TODO:
* - frame counter
**********************************************************************/
import gg
import gg.m4
import gx
// import math
import sokol.sapp
import sokol.gfx
import sokol.sgl
import time
// GLSL Include and functions
#flag -I @VROOT/.
#include "rt_glsl_march.h" #Please use sokol-shdc to generate the necessary rt_glsl_march.h file from rt_glsl_march.glsl (see the instructions at the top of this file)
#include "rt_glsl_puppy.h" #Please use sokol-shdc to generate the necessary rt_glsl_puppy.h file from rt_glsl_puppy.glsl (see the instructions at the top of this file)
fn C.rt_march_shader_desc() &C.sg_shader_desc
fn C.rt_puppy_shader_desc() &C.sg_shader_desc
const (
win_width = 800
win_height = 800
bg_color = gx.white
)
struct App {
mut:
gg &gg.Context
texture C.sg_image
init_flag bool
frame_count int
mouse_x int = -1
mouse_y int = -1
mouse_down bool
// glsl
cube_pip_glsl C.sg_pipeline
cube_bind C.sg_bindings
pipe map[string]C.sg_pipeline
bind map[string]C.sg_bindings
// time
ticks i64
}
/******************************************************************************
* Texture functions
******************************************************************************/
fn create_texture(w int, h int, buf byteptr) C.sg_image {
sz := w * h * 4
mut img_desc := C.sg_image_desc{
width: w
height: h
num_mipmaps: 0
min_filter: .linear
mag_filter: .linear
// usage: .dynamic
wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge
label: &byte(0)
d3d11_texture: 0
}
// comment if .dynamic is enabled
img_desc.content.subimage[0][0] = C.sg_subimage_content{
ptr: buf
size: sz
}
sg_img := C.sg_make_image(&img_desc)
return sg_img
}
fn destroy_texture(sg_img C.sg_image) {
C.sg_destroy_image(sg_img)
}
// Use only if usage: .dynamic is enabled
fn update_text_texture(sg_img C.sg_image, w int, h int, buf byteptr) {
sz := w * h * 4
mut tmp_sbc := C.sg_image_content{}
tmp_sbc.subimage[0][0] = C.sg_subimage_content{
ptr: buf
size: sz
}
C.sg_update_image(sg_img, &tmp_sbc)
}
/******************************************************************************
* Draw functions
******************************************************************************
Cube vertex buffer with packed vertex formats for color and texture coords.
Note that a vertex format which must be portable across all
backends must only use the normalized integer formats
(BYTE4N, UBYTE4N, SHORT2N, SHORT4N), which can be converted
to floating point formats in the vertex shader inputs.
The reason is that D3D11 cannot convert from non-normalized
formats to floating point inputs (only to integer inputs),
and WebGL2 / GLES2 don't support integer vertex shader inputs.
*/
struct Vertex_t {
x f32
y f32
z f32
color u32
// u u16 // for compatibility with D3D11
// v u16 // for compatibility with D3D11
u f32
v f32
}
// march shader init
fn init_cube_glsl_m(mut app App) {
// cube vertex buffer
// d := u16(32767) // for compatibility with D3D11, 32767 stand for 1
d := f32(1.0)
c := u32(0xFFFFFF_FF) // color RGBA8
vertices := [
// Face 0
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, d},
Vertex_t{-1.0, 1.0, -1.0, c, 0, d},
// Face 1
Vertex_t{-1.0, -1.0, 1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, 1.0, 1.0, c, 0, d},
// Face 2
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, -1.0, c, d, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, -1.0, 1.0, c, 0, d},
// Face 3
Vertex_t{ 1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, 1.0, c, 0, d},
// Face 4
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, -1.0, c, 0, d},
// Face 5
Vertex_t{-1.0, 1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, 1.0, -1.0, c, 0, d},
]
mut vert_buffer_desc := C.sg_buffer_desc{}
unsafe { C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc)) }
vert_buffer_desc.size = vertices.len * int(sizeof(Vertex_t))
vert_buffer_desc.content = byteptr(vertices.data)
vert_buffer_desc.@type = .vertexbuffer
vert_buffer_desc.label = 'cube-vertices'.str
vbuf := gfx.make_buffer(&vert_buffer_desc)
/* create an index buffer for the cube */
indices := [
u16(0), 1, 2, 0, 2, 3,
6, 5, 4, 7, 6, 4,
8, 9, 10, 8, 10, 11,
/*
u16(14), 13, 12, 15, 14, 12,
16, 17, 18, 16, 18, 19,
22, 21, 20, 23, 22, 20
*/
]
mut index_buffer_desc := C.sg_buffer_desc{}
unsafe { C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc)) }
index_buffer_desc.size = indices.len * int(sizeof(u16))
index_buffer_desc.content = byteptr(indices.data)
index_buffer_desc.@type = .indexbuffer
index_buffer_desc.label = 'cube-indices'.str
ibuf := gfx.make_buffer(&index_buffer_desc)
// create shader
shader := gfx.make_shader(C.rt_march_shader_desc())
mut pipdesc := C.sg_pipeline_desc{}
unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) }
pipdesc.layout.buffers[0].stride = int(sizeof(Vertex_t))
// the constants [C.ATTR_vs_m_pos, C.ATTR_vs_m_color0, C.ATTR_vs_m_texcoord0] are generated by sokol-shdc
pipdesc.layout.attrs[C.ATTR_vs_m_pos ].format = .float3 // x,y,z as f32
pipdesc.layout.attrs[C.ATTR_vs_m_color0 ].format = .ubyte4n // color as u32
pipdesc.layout.attrs[C.ATTR_vs_m_texcoord0].format = .float2 // u,v as f32
// pipdesc.layout.attrs[C.ATTR_vs_m_texcoord0].format = .short2n // u,v as u16
pipdesc.shader = shader
pipdesc.index_type = .uint16
pipdesc.depth_stencil = C.sg_depth_stencil_state{
depth_write_enabled: true
depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL)
}
pipdesc.rasterizer = C.sg_rasterizer_state{
cull_mode: .back
}
pipdesc.label = 'glsl_shader pipeline'.str
mut bind := C.sg_bindings{}
unsafe { C.memset(&bind, 0, sizeof(bind)) }
bind.vertex_buffers[0] = vbuf
bind.index_buffer = ibuf
bind.fs_images[C.SLOT_tex] = app.texture
app.bind['march'] = bind
app.pipe['march'] = gfx.make_pipeline(&pipdesc)
println('GLSL March init DONE!')
}
// putty shader init
fn init_cube_glsl_p(mut app App) {
// cube vertex buffer
// d := u16(32767) // for compatibility with D3D11, 32767 stand for 1
d := f32(1.0)
c := u32(0xFFFFFF_FF) // color RGBA8
vertices := [
// Face 0
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, d},
Vertex_t{-1.0, 1.0, -1.0, c, 0, d},
// Face 1
Vertex_t{-1.0, -1.0, 1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, 1.0, 1.0, c, 0, d},
// Face 2
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, -1.0, c, d, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, -1.0, 1.0, c, 0, d},
// Face 3
Vertex_t{ 1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, 1.0, c, 0, d},
// Face 4
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, -1.0, c, 0, d},
// Face 5
Vertex_t{-1.0, 1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, 1.0, -1.0, c, 0, d},
]
mut vert_buffer_desc := C.sg_buffer_desc{}
unsafe { C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc)) }
vert_buffer_desc.size = vertices.len * int(sizeof(Vertex_t))
vert_buffer_desc.content = byteptr(vertices.data)
vert_buffer_desc.@type = .vertexbuffer
vert_buffer_desc.label = 'cube-vertices'.str
vbuf := gfx.make_buffer(&vert_buffer_desc)
/* create an index buffer for the cube */
indices := [
/*
u16(0), 1, 2, 0, 2, 3,
6, 5, 4, 7, 6, 4,
8, 9, 10, 8, 10, 11,
*/
u16(14), 13, 12, 15, 14, 12,
16, 17, 18, 16, 18, 19,
22, 21, 20, 23, 22, 20
]
mut index_buffer_desc := C.sg_buffer_desc{}
unsafe { C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc)) }
index_buffer_desc.size = indices.len * int(sizeof(u16))
index_buffer_desc.content = byteptr(indices.data)
index_buffer_desc.@type = .indexbuffer
index_buffer_desc.label = 'cube-indices'.str
ibuf := gfx.make_buffer(&index_buffer_desc)
// create shader
shader := gfx.make_shader(C.rt_puppy_shader_desc())
mut pipdesc := C.sg_pipeline_desc{}
unsafe { C.memset(&pipdesc, 0, sizeof(pipdesc)) }
pipdesc.layout.buffers[0].stride = int(sizeof(Vertex_t))
// the constants [C.ATTR_vs_p_pos, C.ATTR_vs_p_color0, C.ATTR_vs_p_texcoord0] are generated by sokol-shdc
pipdesc.layout.attrs[C.ATTR_vs_p_pos ].format = .float3 // x,y,z as f32
pipdesc.layout.attrs[C.ATTR_vs_p_color0 ].format = .ubyte4n // color as u32
pipdesc.layout.attrs[C.ATTR_vs_p_texcoord0].format = .float2 // u,v as f32
// pipdesc.layout.attrs[C.ATTR_vs_p_texcoord0].format = .short2n // u,v as u16
pipdesc.shader = shader
pipdesc.index_type = .uint16
pipdesc.depth_stencil = C.sg_depth_stencil_state{
depth_write_enabled: true
depth_compare_func: gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL)
}
pipdesc.rasterizer = C.sg_rasterizer_state{
cull_mode: .back
}
pipdesc.label = 'glsl_shader pipeline'.str
mut bind := C.sg_bindings{}
unsafe { C.memset(&bind, 0, sizeof(bind)) }
bind.vertex_buffers[0] = vbuf
bind.index_buffer = ibuf
bind.fs_images[C.SLOT_tex] = app.texture
app.bind['puppy'] = bind
app.pipe['puppy'] = gfx.make_pipeline(&pipdesc)
println('GLSL Puppy init DONE!')
}
[inline]
fn vec4(x f32, y f32, z f32, w f32) m4.Vec4 {
return m4.Vec4{e:[x, y, z, w]!}
}
fn calc_tr_matrices(w f32, h f32, rx f32, ry f32, in_scale f32) m4.Mat4 {
proj := m4.perspective(60, w/h, 0.01, 10.0)
view := m4.look_at(vec4(f32(0.0) ,0 , 6, 0), vec4(f32(0), 0, 0, 0), vec4(f32(0), 1, 0, 0))
view_proj := view * proj
rxm := m4.rotate(m4.rad(rx), vec4(f32(1), 0, 0, 0))
rym := m4.rotate(m4.rad(ry), vec4(f32(0), 1, 0, 0))
model := rym * rxm
scale_m := m4.scale(vec4(in_scale, in_scale, in_scale, 1))
res := (scale_m * model) * view_proj
return res
}
// march triangles draw
fn draw_cube_glsl_m(app App) {
if app.init_flag == false {
return
}
ws := gg.window_size()
ratio := f32(ws.width) / ws.height
dw := f32(ws.width / 2)
dh := f32(ws.height / 2)
rot := [f32(app.mouse_y), f32(app.mouse_x)]
tr_matrix := calc_tr_matrices(dw, dh, rot[0], rot[1], 2.3)
gfx.apply_pipeline(app.pipe['march'])
gfx.apply_bindings(app.bind['march'])
// Uniforms
// *** vertex shadeer uniforms ***
// passing the view matrix as uniform
// res is a 4x4 matrix of f32 thus: 4*16 byte of size
gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_m, &tr_matrix, 4 * 16)
// *** fragment shader uniforms ***
time_ticks := f32(time.ticks() - app.ticks) / 1000
mut tmp_fs_params := [
f32(ws.width),
ws.height * ratio, // x,y resolution to pass to FS
0,
0, // dont send mouse position
/* app.mouse_x, // mouse x */
/* ws.height - app.mouse_y*2, // mouse y scaled */
time_ticks, // time as f32
app.frame_count, // frame count
0,
0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
]!
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params_m, &tmp_fs_params, int(sizeof(tmp_fs_params)))
// 3 vertices for triangle * 2 triangles per face * 6 faces = 36 vertices to draw
gfx.draw(0, (3 * 2) * 3, 1)
}
// puppy triangles draw
fn draw_cube_glsl_p(app App) {
if app.init_flag == false {
return
}
ws := gg.window_size()
ratio := f32(ws.width) / ws.height
dw := f32(ws.width / 2)
dh := f32(ws.height / 2)
rot := [f32(app.mouse_y), f32(app.mouse_x)]
tr_matrix := calc_tr_matrices(dw, dh, rot[0], rot[1], 2.3)
// apply the pipline and bindings
gfx.apply_pipeline(app.pipe['puppy'])
gfx.apply_bindings(app.bind['puppy'])
// Uniforms
// *** vertex shadeer uniforms ***
// passing the view matrix as uniform
// res is a 4x4 matrix of f32 thus: 4*16 byte of size
gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_p, &tr_matrix, 4 * 16)
// *** fragment shader uniforms ***
time_ticks := f32(time.ticks() - app.ticks) / 1000
mut tmp_fs_params := [
f32(ws.width),
ws.height * ratio, // x,y resolution to pass to FS
0,
0, // dont send mouse position
/* app.mouse_x, // mouse x */
/* ws.height - app.mouse_y*2, // mouse y scaled */
time_ticks, // time as f32
app.frame_count, // frame count
0,
0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
]!
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params_p, &tmp_fs_params, int(sizeof(tmp_fs_params)))
// 3 vertices for triangle * 2 triangles per face * 6 faces = 36 vertices to draw
gfx.draw(0, (3 * 2) * 3, 1)
}
fn draw_start_glsl(app App) {
if app.init_flag == false {
return
}
ws := gg.window_size()
// ratio := f32(ws.width) / ws.height
// dw := f32(ws.width / 2)
// dh := f32(ws.height / 2)
gfx.apply_viewport(0, 0, ws.width, ws.height, true)
}
fn draw_end_glsl(app App) {
gfx.end_pass()
gfx.commit()
}
fn frame(mut app App) {
ws := gg.window_size()
// clear
mut color_action := C.sg_color_attachment_action{
action: gfx.Action(C.SG_ACTION_CLEAR)
}
color_action.val[0] = 0
color_action.val[1] = 0
color_action.val[2] = 0
color_action.val[3] = 1.0
mut pass_action := C.sg_pass_action{}
pass_action.colors[0] = color_action
gfx.begin_default_pass(&pass_action, ws.width, ws.height)
/*
// glsl cube
if app.frame_count % 1 == 1{
draw_cube_glsl_m(app)
} else {
draw_cube_glsl_p(app)
}
*/
draw_start_glsl(app)
draw_cube_glsl_m(app)
draw_cube_glsl_p(app)
draw_end_glsl(app)
app.frame_count++
}
/******************************************************************************
* Init / Cleanup
******************************************************************************/
fn my_init(mut app App) {
// set max vertices,
// for a large number of the same type of object it is better use the instances!!
desc := sapp.create_desc()
gfx.setup(&desc)
sgl_desc := C.sgl_desc_t{
max_vertices: 50 * 65536
}
sgl.setup(&sgl_desc)
// create chessboard texture 256*256 RGBA
w := 256
h := 256
sz := w * h * 4
tmp_txt := unsafe { malloc(sz) }
mut i := 0
for i < sz {
unsafe {
y := (i >> 0x8) >> 5 // 8 cell
x := (i & 0xFF) >> 5 // 8 cell
// upper left corner
if x == 0 && y == 0 {
tmp_txt[i + 0] = byte(0xFF)
tmp_txt[i + 1] = byte(0)
tmp_txt[i + 2] = byte(0)
tmp_txt[i + 3] = byte(0xFF)
}
// low right corner
else if x == 7 && y == 7 {
tmp_txt[i + 0] = byte(0)
tmp_txt[i + 1] = byte(0xFF)
tmp_txt[i + 2] = byte(0)
tmp_txt[i + 3] = byte(0xFF)
} else {
col := if ((x + y) & 1) == 1 { 0xFF } else { 128 }
tmp_txt[i + 0] = byte(col) // red
tmp_txt[i + 1] = byte(col) // green
tmp_txt[i + 2] = byte(col) // blue
tmp_txt[i + 3] = byte(0xFF) // alpha
}
i += 4
}
}
app.texture = create_texture(w, h, tmp_txt)
unsafe { free(tmp_txt) }
// glsl
init_cube_glsl_m(mut app)
init_cube_glsl_p(mut app)
app.init_flag = true
}
fn cleanup(mut app App) {
gfx.shutdown()
}
/******************************************************************************
* events handling
******************************************************************************/
fn my_event_manager(mut ev gg.Event, mut app App) {
if ev.typ == .mouse_down {
app.mouse_down = true
}
if ev.typ == .mouse_up {
app.mouse_down = false
}
if app.mouse_down == true && ev.typ == .mouse_move {
app.mouse_x = int(ev.mouse_x)
app.mouse_y = int(ev.mouse_y)
}
if ev.typ == .touches_began || ev.typ == .touches_moved {
if ev.num_touches > 0 {
touch_point := ev.touches[0]
app.mouse_x = int(touch_point.pos_x)
app.mouse_y = int(touch_point.pos_y)
}
}
}
/******************************************************************************
* Main
******************************************************************************/
[console] // is needed for easier diagnostics on windows
fn main() {
// App init
mut app := &App{
gg: 0
}
app.gg = gg.new_context(
width: win_width
height: win_height
use_ortho: true // This is needed for 2D drawing
create_window: true
window_title: '3D Dual shader Cube - click and rotate with the mouse'
user_data: app
bg_color: bg_color
frame_fn: frame
init_fn: my_init
cleanup_fn: cleanup
event_fn: my_event_manager
)
app.ticks = time.ticks()
app.gg.run()
}

View File

@@ -0,0 +1,695 @@
//------------------------------------------------------------------------------
// Shader code for texcube-sapp sample.
//
// NOTE: This source file also uses the '#pragma sokol' form of the
// custom tags.
//------------------------------------------------------------------------------
//#pragma sokol @ctype mat4 hmm_mat4
#pragma sokol @vs vs_m
uniform vs_params_m {
mat4 mvp;
};
in vec4 pos;
in vec4 color0;
in vec2 texcoord0;
out vec4 color;
out vec2 uv;
void main() {
gl_Position = mvp * pos;
color = color0;
uv = texcoord0;
}
#pragma sokol @end
#pragma sokol @fs fs_m
uniform sampler2D tex;
uniform fs_params_m {
vec2 iResolution;
vec2 iMouse;
float iTime;
float iFrame;
};
in vec4 color;
in vec2 uv;
out vec4 frag_color;
// change to 0 to 4 to increment the AntiAliasing,
// increase AA will SLOW the rendering!!
#define AA 1
//*********************************************************
// Ray Marching
// original code from: https://www.shadertoy.com/view/Xds3zN
//*********************************************************
// The MIT License
// Copyright © 2013 Inigo Quilez
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// A list of useful distance function to simple primitives. All
// these functions (except for ellipsoid) return an exact
// euclidean distance, meaning they produce a better SDF than
// what you'd get if you were constructing them from boolean
// operations.
//
// More info here:
//
// https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
//------------------------------------------------------------------
float dot2( in vec2 v ) { return dot(v,v); }
float dot2( in vec3 v ) { return dot(v,v); }
float ndot( in vec2 a, in vec2 b ) { return a.x*b.x - a.y*b.y; }
float sdPlane( vec3 p )
{
return p.y;
}
float sdSphere( vec3 p, float s )
{
return length(p)-s;
}
float sdBox( vec3 p, vec3 b )
{
vec3 d = abs(p) - b;
return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}
float sdBoundingBox( vec3 p, vec3 b, float e )
{
p = abs(p )-b;
vec3 q = abs(p+e)-e;
return min(min(
length(max(vec3(p.x,q.y,q.z),0.0))+min(max(p.x,max(q.y,q.z)),0.0),
length(max(vec3(q.x,p.y,q.z),0.0))+min(max(q.x,max(p.y,q.z)),0.0)),
length(max(vec3(q.x,q.y,p.z),0.0))+min(max(q.x,max(q.y,p.z)),0.0));
}
float sdEllipsoid( in vec3 p, in vec3 r ) // approximated
{
float k0 = length(p/r);
float k1 = length(p/(r*r));
return k0*(k0-1.0)/k1;
}
float sdTorus( vec3 p, vec2 t )
{
return length( vec2(length(p.xz)-t.x,p.y) )-t.y;
}
float sdCappedTorus(in vec3 p, in vec2 sc, in float ra, in float rb)
{
p.x = abs(p.x);
float k = (sc.y*p.x>sc.x*p.y) ? dot(p.xy,sc) : length(p.xy);
return sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb;
}
float sdHexPrism( vec3 p, vec2 h )
{
vec3 q = abs(p);
const vec3 k = vec3(-0.8660254, 0.5, 0.57735);
p = abs(p);
p.xy -= 2.0*min(dot(k.xy, p.xy), 0.0)*k.xy;
vec2 d = vec2(
length(p.xy - vec2(clamp(p.x, -k.z*h.x, k.z*h.x), h.x))*sign(p.y - h.x),
p.z-h.y );
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
float sdOctogonPrism( in vec3 p, in float r, float h )
{
const vec3 k = vec3(-0.9238795325, // sqrt(2+sqrt(2))/2
0.3826834323, // sqrt(2-sqrt(2))/2
0.4142135623 ); // sqrt(2)-1
// reflections
p = abs(p);
p.xy -= 2.0*min(dot(vec2( k.x,k.y),p.xy),0.0)*vec2( k.x,k.y);
p.xy -= 2.0*min(dot(vec2(-k.x,k.y),p.xy),0.0)*vec2(-k.x,k.y);
// polygon side
p.xy -= vec2(clamp(p.x, -k.z*r, k.z*r), r);
vec2 d = vec2( length(p.xy)*sign(p.y), p.z-h );
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
float sdCapsule( vec3 p, vec3 a, vec3 b, float r )
{
vec3 pa = p-a, ba = b-a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
return length( pa - ba*h ) - r;
}
float sdRoundCone( in vec3 p, in float r1, float r2, float h )
{
vec2 q = vec2( length(p.xz), p.y );
float b = (r1-r2)/h;
float a = sqrt(1.0-b*b);
float k = dot(q,vec2(-b,a));
if( k < 0.0 ) return length(q) - r1;
if( k > a*h ) return length(q-vec2(0.0,h)) - r2;
return dot(q, vec2(a,b) ) - r1;
}
float sdRoundCone(vec3 p, vec3 a, vec3 b, float r1, float r2)
{
// sampling independent computations (only depend on shape)
vec3 ba = b - a;
float l2 = dot(ba,ba);
float rr = r1 - r2;
float a2 = l2 - rr*rr;
float il2 = 1.0/l2;
// sampling dependant computations
vec3 pa = p - a;
float y = dot(pa,ba);
float z = y - l2;
float x2 = dot2( pa*l2 - ba*y );
float y2 = y*y*l2;
float z2 = z*z*l2;
// single square root!
float k = sign(rr)*rr*rr*x2;
if( sign(z)*a2*z2 > k ) return sqrt(x2 + z2) *il2 - r2;
if( sign(y)*a2*y2 < k ) return sqrt(x2 + y2) *il2 - r1;
return (sqrt(x2*a2*il2)+y*rr)*il2 - r1;
}
float sdTriPrism( vec3 p, vec2 h )
{
const float k = sqrt(3.0);
h.x *= 0.5*k;
p.xy /= h.x;
p.x = abs(p.x) - 1.0;
p.y = p.y + 1.0/k;
if( p.x+k*p.y>0.0 ) p.xy=vec2(p.x-k*p.y,-k*p.x-p.y)/2.0;
p.x -= clamp( p.x, -2.0, 0.0 );
float d1 = length(p.xy)*sign(-p.y)*h.x;
float d2 = abs(p.z)-h.y;
return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);
}
// vertical
float sdCylinder( vec3 p, vec2 h )
{
vec2 d = abs(vec2(length(p.xz),p.y)) - h;
return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}
// arbitrary orientation
float sdCylinder(vec3 p, vec3 a, vec3 b, float r)
{
vec3 pa = p - a;
vec3 ba = b - a;
float baba = dot(ba,ba);
float paba = dot(pa,ba);
float x = length(pa*baba-ba*paba) - r*baba;
float y = abs(paba-baba*0.5)-baba*0.5;
float x2 = x*x;
float y2 = y*y*baba;
float d = (max(x,y)<0.0)?-min(x2,y2):(((x>0.0)?x2:0.0)+((y>0.0)?y2:0.0));
return sign(d)*sqrt(abs(d))/baba;
}
// vertical
float sdCone( in vec3 p, in vec2 c, float h )
{
vec2 q = h*vec2(c.x,-c.y)/c.y;
vec2 w = vec2( length(p.xz), p.y );
vec2 a = w - q*clamp( dot(w,q)/dot(q,q), 0.0, 1.0 );
vec2 b = w - q*vec2( clamp( w.x/q.x, 0.0, 1.0 ), 1.0 );
float k = sign( q.y );
float d = min(dot( a, a ),dot(b, b));
float s = max( k*(w.x*q.y-w.y*q.x),k*(w.y-q.y) );
return sqrt(d)*sign(s);
}
float sdCappedCone( in vec3 p, in float h, in float r1, in float r2 )
{
vec2 q = vec2( length(p.xz), p.y );
vec2 k1 = vec2(r2,h);
vec2 k2 = vec2(r2-r1,2.0*h);
vec2 ca = vec2(q.x-min(q.x,(q.y < 0.0)?r1:r2), abs(q.y)-h);
vec2 cb = q - k1 + k2*clamp( dot(k1-q,k2)/dot2(k2), 0.0, 1.0 );
float s = (cb.x < 0.0 && ca.y < 0.0) ? -1.0 : 1.0;
return s*sqrt( min(dot2(ca),dot2(cb)) );
}
float sdCappedCone(vec3 p, vec3 a, vec3 b, float ra, float rb)
{
float rba = rb-ra;
float baba = dot(b-a,b-a);
float papa = dot(p-a,p-a);
float paba = dot(p-a,b-a)/baba;
float x = sqrt( papa - paba*paba*baba );
float cax = max(0.0,x-((paba<0.5)?ra:rb));
float cay = abs(paba-0.5)-0.5;
float k = rba*rba + baba;
float f = clamp( (rba*(x-ra)+paba*baba)/k, 0.0, 1.0 );
float cbx = x-ra - f*rba;
float cby = paba - f;
float s = (cbx < 0.0 && cay < 0.0) ? -1.0 : 1.0;
return s*sqrt( min(cax*cax + cay*cay*baba,
cbx*cbx + cby*cby*baba) );
}
// c is the sin/cos of the desired cone angle
float sdSolidAngle(vec3 pos, vec2 c, float ra)
{
vec2 p = vec2( length(pos.xz), pos.y );
float l = length(p) - ra;
float m = length(p - c*clamp(dot(p,c),0.0,ra) );
return max(l,m*sign(c.y*p.x-c.x*p.y));
}
float sdOctahedron(vec3 p, float s)
{
p = abs(p);
float m = p.x + p.y + p.z - s;
// exact distance
#if 0
vec3 o = min(3.0*p - m, 0.0);
o = max(6.0*p - m*2.0 - o*3.0 + (o.x+o.y+o.z), 0.0);
return length(p - s*o/(o.x+o.y+o.z));
#endif
// exact distance
#if 1
vec3 q;
if( 3.0*p.x < m ) q = p.xyz;
else if( 3.0*p.y < m ) q = p.yzx;
else if( 3.0*p.z < m ) q = p.zxy;
else return m*0.57735027;
float k = clamp(0.5*(q.z-q.y+s),0.0,s);
return length(vec3(q.x,q.y-s+k,q.z-k));
#endif
// bound, not exact
#if 0
return m*0.57735027;
#endif
}
float sdPyramid( in vec3 p, in float h )
{
float m2 = h*h + 0.25;
// symmetry
p.xz = abs(p.xz);
p.xz = (p.z>p.x) ? p.zx : p.xz;
p.xz -= 0.5;
// project into face plane (2D)
vec3 q = vec3( p.z, h*p.y - 0.5*p.x, h*p.x + 0.5*p.y);
float s = max(-q.x,0.0);
float t = clamp( (q.y-0.5*p.z)/(m2+0.25), 0.0, 1.0 );
float a = m2*(q.x+s)*(q.x+s) + q.y*q.y;
float b = m2*(q.x+0.5*t)*(q.x+0.5*t) + (q.y-m2*t)*(q.y-m2*t);
float d2 = min(q.y,-q.x*m2-q.y*0.5) > 0.0 ? 0.0 : min(a,b);
// recover 3D and scale, and add sign
return sqrt( (d2+q.z*q.z)/m2 ) * sign(max(q.z,-p.y));
}
// la,lb=semi axis, h=height, ra=corner
float sdRhombus(vec3 p, float la, float lb, float h, float ra)
{
p = abs(p);
vec2 b = vec2(la,lb);
float f = clamp( (ndot(b,b-2.0*p.xz))/dot(b,b), -1.0, 1.0 );
vec2 q = vec2(length(p.xz-0.5*b*vec2(1.0-f,1.0+f))*sign(p.x*b.y+p.z*b.x-b.x*b.y)-ra, p.y-h);
return min(max(q.x,q.y),0.0) + length(max(q,0.0));
}
//------------------------------------------------------------------
vec2 opU( vec2 d1, vec2 d2 )
{
return (d1.x<d2.x) ? d1 : d2;
}
//------------------------------------------------------------------
#define ZERO (min(int(iFrame),0))
//------------------------------------------------------------------
vec2 map( in vec3 pos )
{
vec2 res = vec2( 1e10, 0.0 );
{
res = opU( res, vec2( sdSphere( pos-vec3(-2.0,0.25, 0.0), 0.25 ), 26.9 ) );
}
// bounding box
if( sdBox( pos-vec3(0.0,0.3,-1.0),vec3(0.35,0.3,2.5) )<res.x )
{
// more primitives
res = opU( res, vec2( sdBoundingBox( pos-vec3( 0.0,0.25, 0.0), vec3(0.3,0.25,0.2), 0.025 ), 16.9 ) );
res = opU( res, vec2( sdTorus( (pos-vec3( 0.0,0.30, 1.0)).xzy, vec2(0.25,0.05) ), 25.0 ) );
res = opU( res, vec2( sdCone( pos-vec3( 0.0,0.45,-1.0), vec2(0.6,0.8),0.45 ), 55.0 ) );
res = opU( res, vec2( sdCappedCone( pos-vec3( 0.0,0.25,-2.0), 0.25, 0.25, 0.1 ), 13.67 ) );
res = opU( res, vec2( sdSolidAngle( pos-vec3( 0.0,0.00,-3.0), vec2(3,4)/5.0, 0.4 ), 49.13 ) );
}
// bounding box
if( sdBox( pos-vec3(1.0,0.3,-1.0),vec3(0.35,0.3,2.5) )<res.x )
{
// more primitives
res = opU( res, vec2( sdCappedTorus((pos-vec3( 1.0,0.30, 1.0))*vec3(1,-1,1), vec2(0.866025,-0.5), 0.25, 0.05), 8.5) );
res = opU( res, vec2( sdBox( pos-vec3( 1.0,0.25, 0.0), vec3(0.3,0.25,0.1) ), 3.0 ) );
res = opU( res, vec2( sdCapsule( pos-vec3( 1.0,0.00,-1.0),vec3(-0.1,0.1,-0.1), vec3(0.2,0.4,0.2), 0.1 ), 31.9 ) );
res = opU( res, vec2( sdCylinder( pos-vec3( 1.0,0.25,-2.0), vec2(0.15,0.25) ), 8.0 ) );
res = opU( res, vec2( sdHexPrism( pos-vec3( 1.0,0.2,-3.0), vec2(0.2,0.05) ), 18.4 ) );
}
// bounding box
if( sdBox( pos-vec3(-1.0,0.35,-1.0),vec3(0.35,0.35,2.5))<res.x )
{
// more primitives
res = opU( res, vec2( sdPyramid( pos-vec3(-1.0,-0.6,-3.0), 1.0 ), 13.56 ) );
res = opU( res, vec2( sdOctahedron( pos-vec3(-1.0,0.15,-2.0), 0.35 ), 23.56 ) );
res = opU( res, vec2( sdTriPrism( pos-vec3(-1.0,0.15,-1.0), vec2(0.3,0.05) ),43.5 ) );
res = opU( res, vec2( sdEllipsoid( pos-vec3(-1.0,0.25, 0.0), vec3(0.2, 0.25, 0.05) ), 43.17 ) );
res = opU( res, vec2( sdRhombus( (pos-vec3(-1.0,0.34, 1.0)).xzy, 0.15, 0.25, 0.04, 0.08 ),17.0 ) );
}
// bounding box
if( sdBox( pos-vec3(2.0,0.3,-1.0),vec3(0.35,0.3,2.5) )<res.x )
{
// more primitives
res = opU( res, vec2( sdOctogonPrism(pos-vec3( 2.0,0.2,-3.0), 0.2, 0.05), 51.8 ) );
res = opU( res, vec2( sdCylinder( pos-vec3( 2.0,0.15,-2.0), vec3(0.1,-0.1,0.0), vec3(-0.2,0.35,0.1), 0.08), 31.2 ) );
res = opU( res, vec2( sdCappedCone( pos-vec3( 2.0,0.10,-1.0), vec3(0.1,0.0,0.0), vec3(-0.2,0.40,0.1), 0.15, 0.05), 46.1 ) );
res = opU( res, vec2( sdRoundCone( pos-vec3( 2.0,0.15, 0.0), vec3(0.1,0.0,0.0), vec3(-0.1,0.35,0.1), 0.15, 0.05), 51.7 ) );
res = opU( res, vec2( sdRoundCone( pos-vec3( 2.0,0.20, 1.0), 0.2, 0.1, 0.3 ), 37.0 ) );
}
return res;
}
// http://iquilezles.org/www/articles/boxfunctions/boxfunctions.htm
vec2 iBox( in vec3 ro, in vec3 rd, in vec3 rad )
{
vec3 m = 1.0/rd;
vec3 n = m*ro;
vec3 k = abs(m)*rad;
vec3 t1 = -n - k;
vec3 t2 = -n + k;
return vec2( max( max( t1.x, t1.y ), t1.z ),
min( min( t2.x, t2.y ), t2.z ) );
}
vec2 raycast( in vec3 ro, in vec3 rd )
{
vec2 res = vec2(-1.0,-1.0);
float tmin = 1.0;
float tmax = 20.0;
// raytrace floor plane
float tp1 = (0.0-ro.y)/rd.y;
if( tp1>0.0 )
{
tmax = min( tmax, tp1 );
res = vec2( tp1, 1.0 );
}
//else return res;
// raymarch primitives
vec2 tb = iBox( ro-vec3(0.0,0.4,-0.5), rd, vec3(2.5,0.41,3.0) );
if( tb.x<tb.y && tb.y>0.0 && tb.x<tmax)
{
//return vec2(tb.x,2.0);
tmin = max(tb.x,tmin);
tmax = min(tb.y,tmax);
float t = tmin;
for( int i=0; i<70 && t<tmax; i++ )
{
vec2 h = map( ro+rd*t );
if( abs(h.x)<(0.0001*t) )
{
res = vec2(t,h.y);
break;
}
t += h.x;
}
}
return res;
}
// http://iquilezles.org/www/articles/rmshadows/rmshadows.htm
float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax )
{
// bounding volume
float tp = (0.8-ro.y)/rd.y; if( tp>0.0 ) tmax = min( tmax, tp );
float res = 1.0;
float t = mint;
for( int i=ZERO; i<24; i++ )
{
float h = map( ro + rd*t ).x;
float s = clamp(8.0*h/t,0.0,1.0);
res = min( res, s*s*(3.0-2.0*s) );
t += clamp( h, 0.02, 0.2 );
if( res<0.004 || t>tmax ) break;
}
return clamp( res, 0.0, 1.0 );
}
// http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm
vec3 calcNormal( in vec3 pos )
{
#if 0
vec2 e = vec2(1.0,-1.0)*0.5773*0.0005;
return normalize( e.xyy*map( pos + e.xyy ).x +
e.yyx*map( pos + e.yyx ).x +
e.yxy*map( pos + e.yxy ).x +
e.xxx*map( pos + e.xxx ).x );
#else
// inspired by tdhooper and klems - a way to prevent the compiler from inlining map() 4 times
vec3 n = vec3(0.0);
for( int i=ZERO; i<4; i++ )
{
vec3 e = 0.5773*(2.0*vec3((((i+3)>>1)&1),((i>>1)&1),(i&1))-1.0);
n += e*map(pos+0.0005*e).x;
//if( n.x+n.y+n.z>100.0 ) break;
}
return normalize(n);
#endif
}
float calcAO( in vec3 pos, in vec3 nor )
{
float occ = 0.0;
float sca = 1.0;
for( int i=ZERO; i<5; i++ )
{
float h = 0.01 + 0.12*float(i)/4.0;
float d = map( pos + h*nor ).x;
occ += (h-d)*sca;
sca *= 0.95;
if( occ>0.35 ) break;
}
return clamp( 1.0 - 3.0*occ, 0.0, 1.0 ) * (0.5+0.5*nor.y);
}
// http://iquilezles.org/www/articles/checkerfiltering/checkerfiltering.htm
float checkersGradBox( in vec2 p, in vec2 dpdx, in vec2 dpdy )
{
// filter kernel
vec2 w = abs(dpdx)+abs(dpdy) + 0.001;
// analytical integral (box filter)
vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w;
// xor pattern
return 0.5 - 0.5*i.x*i.y;
}
vec3 render( in vec3 ro, in vec3 rd, in vec3 rdx, in vec3 rdy )
{
// background
vec3 col = vec3(0.7, 0.7, 0.9) - max(rd.y,0.0)*0.3;
// raycast scene
vec2 res = raycast(ro,rd);
float t = res.x;
float m = res.y;
if( m>-0.5 )
{
vec3 pos = ro + t*rd;
vec3 nor = (m<1.5) ? vec3(0.0,1.0,0.0) : calcNormal( pos );
vec3 ref = reflect( rd, nor );
// material
col = 0.2 + 0.2*sin( m*2.0 + vec3(0.0,1.0,2.0) );
float ks = 1.0;
if( m<1.5 )
{
// project pixel footprint into the plane
vec3 dpdx = ro.y*(rd/rd.y-rdx/rdx.y);
vec3 dpdy = ro.y*(rd/rd.y-rdy/rdy.y);
float f = checkersGradBox( 3.0*pos.xz, 3.0*dpdx.xz, 3.0*dpdy.xz );
col = 0.15 + f*vec3(0.05);
ks = 0.4;
}
// lighting
float occ = calcAO( pos, nor );
vec3 lin = vec3(0.0);
// sun
{
vec3 lig = normalize( vec3(-0.5, 0.4, -0.6) );
vec3 hal = normalize( lig-rd );
float dif = clamp( dot( nor, lig ), 0.0, 1.0 );
//if( dif>0.0001 )
dif *= calcSoftshadow( pos, lig, 0.02, 2.5 );
float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0);
spe *= dif;
spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0);
lin += col*2.20*dif*vec3(1.30,1.00,0.70);
lin += 5.00*spe*vec3(1.30,1.00,0.70)*ks;
}
// sky
{
float dif = sqrt(clamp( 0.5+0.5*nor.y, 0.0, 1.0 ));
dif *= occ;
float spe = smoothstep( -0.2, 0.2, ref.y );
spe *= dif;
spe *= 0.04+0.96*pow(clamp(1.0+dot(nor,rd),0.0,1.0), 5.0 );
//if( spe>0.001 )
spe *= calcSoftshadow( pos, ref, 0.02, 2.5 );
lin += col*0.60*dif*vec3(0.40,0.60,1.15);
lin += 2.00*spe*vec3(0.40,0.60,1.30)*ks;
}
// back
{
float dif = clamp( dot( nor, normalize(vec3(0.5,0.0,0.6))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0);
dif *= occ;
lin += col*0.55*dif*vec3(0.25,0.25,0.25);
}
// sss
{
float dif = pow(clamp(1.0+dot(nor,rd),0.0,1.0),2.0);
dif *= occ;
lin += col*0.25*dif*vec3(1.00,1.00,1.00);
}
col = lin;
col = mix( col, vec3(0.7,0.7,0.9), 1.0-exp( -0.0001*t*t*t ) );
}
return vec3( clamp(col,0.0,1.0) );
}
mat3 setCamera( in vec3 ro, in vec3 ta, float cr )
{
vec3 cw = normalize(ta-ro);
vec3 cp = vec3(sin(cr), cos(cr),0.0);
vec3 cu = normalize( cross(cw,cp) );
vec3 cv = ( cross(cu,cw) );
return mat3( cu, cv, cw );
}
vec4 mainImage( vec2 fragCoord )
{
vec2 mo = iMouse.xy/iResolution.xy;
float time = 32.0 + iTime*1.5;
// camera
vec3 ta = vec3( 0.5, -0.5, -0.6 );
vec3 ro = ta + vec3( 4.5*cos(0.1*time + 7.0*mo.x), 1.3 + 2.0*mo.y, 4.5*sin(0.1*time + 7.0*mo.x) );
// camera-to-world transformation
mat3 ca = setCamera( ro, ta, 0.0 );
vec3 tot = vec3(0.0);
#if AA>1
for( int m=ZERO; m<AA; m++ )
for( int n=ZERO; n<AA; n++ )
{
// pixel coordinates
vec2 o = vec2(float(m),float(n)) / float(AA) - 0.5;
vec2 p = (2.0*(fragCoord+o)-iResolution.xy)/iResolution.y;
#else
vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
#endif
// focal length
const float fl = 2.5;
// ray direction
vec3 rd = ca * normalize( vec3(p,fl) );
// ray differentials
vec2 px = (2.0*(fragCoord+vec2(1.0,0.0))-iResolution.xy)/iResolution.y;
vec2 py = (2.0*(fragCoord+vec2(0.0,1.0))-iResolution.xy)/iResolution.y;
vec3 rdx = ca * normalize( vec3(px,fl) );
vec3 rdy = ca * normalize( vec3(py,fl) );
// render
vec3 col = render( ro, rd, rdx, rdy );
// gain
// col = col*3.0/(2.5+col);
// gamma
col = pow( col, vec3(0.4545) );
tot += col;
#if AA>1
}
tot /= float(AA*AA);
#endif
//fragColor = vec4( tot, 1.0 );
return vec4( tot, 1.0 );
}
//*********************************************************
// END Ray Marching
//*********************************************************
void main() {
vec4 c = color;
vec4 txt = texture(tex, uv);
c = txt * c;
vec2 uv1 = uv * iResolution;
vec4 col_ray = mainImage(uv1);
// use this to mix the chessboart texture with the ray marching
//frag_color = clamp(c*iMouse.y/512.0,0.0,1.0) * col_ray ;
frag_color = c*0.00001 + col_ray ;
}
#pragma sokol @end
#pragma sokol @program rt_march vs_m fs_m

View File

@@ -0,0 +1,568 @@
//------------------------------------------------------------------------------
// Shader code for texcube-sapp sample.
//
// NOTE: This source file also uses the '#pragma sokol' form of the
// custom tags.
//------------------------------------------------------------------------------
//#pragma sokol @ctype mat4 hmm_mat4
#pragma sokol @vs vs_p
uniform vs_params_p {
mat4 mvp;
};
in vec4 pos;
in vec4 color0;
in vec2 texcoord0;
out vec4 color;
out vec2 uv;
void main() {
gl_Position = mvp * pos;
color = color0;
uv = texcoord0;
}
#pragma sokol @end
#pragma sokol @fs fs_p
uniform sampler2D tex;
uniform fs_params_p {
vec2 iResolution;
vec2 iMouse;
float iTime;
float iFrame;
};
in vec4 color;
in vec2 uv;
out vec4 frag_color;
// change to 0 to 4 to increment the AntiAliasing,
// increase AA will SLOW the rendering!!
#define AA 1
//*********************************************************
// Ray Marching
// original code from: https://www.shadertoy.com/view/Xds3zN
//*********************************************************
// Created by inigo quilez - iq/2019
// I share this piece (art and code) here in Shadertoy and through its Public API, only for educational purposes.
// You cannot use, share or host this piece or modifications of it as part of your own commercial or non-commercial product, website or project.
// You can share a link to it or an unmodified screenshot of it provided you attribute "by Inigo Quilez, @iquilezles and iquilezles.org".
// If you are a teacher, lecturer, educator or similar and these conditions are too restrictive for your needs, please contact me and we'll work it out.
// An animation test - a happy and blobby creature
// jumping and looking around. It gets off-model very
// often, but it looks good enough I think.
//
// Making-of with math/shader/art explanations (6 hours
// long): https://www.youtube.com/watch?v=Cfe5UQ-1L9Q
//
// Video capture: https://www.youtube.com/watch?v=s_UOFo2IULQ
//
// Buy a metal print here: https://www.redbubble.com/i/metal-print/Happy-Jumping-by-InigoQuilez/43594745.0JXQP
//------------------------------------------------------------------
// http://iquilezles.org/www/articles/smin/smin.htm
float smin( float a, float b, float k )
{
float h = max(k-abs(a-b),0.0);
return min(a, b) - h*h*0.25/k;
}
// http://iquilezles.org/www/articles/smin/smin.htm
vec2 smin( vec2 a, vec2 b, float k )
{
float h = clamp( 0.5+0.5*(b.x-a.x)/k, 0.0, 1.0 );
return mix( b, a, h ) - k*h*(1.0-h);
}
// http://iquilezles.org/www/articles/smin/smin.htm
float smax( float a, float b, float k )
{
float h = max(k-abs(a-b),0.0);
return max(a, b) + h*h*0.25/k;
}
// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdSphere( vec3 p, float s )
{
return length(p)-s;
}
// http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdEllipsoid( in vec3 p, in vec3 r ) // approximated
{
float k0 = length(p/r);
float k1 = length(p/(r*r));
return k0*(k0-1.0)/k1;
}
vec2 sdStick(vec3 p, vec3 a, vec3 b, float r1, float r2) // approximated
{
vec3 pa = p-a, ba = b-a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
return vec2( length( pa - ba*h ) - mix(r1,r2,h*h*(3.0-2.0*h)), h );
}
// http://iquilezles.org/www/articles/smin/smin.htm
vec4 opU( vec4 d1, vec4 d2 )
{
return (d1.x<d2.x) ? d1 : d2;
}
//------------------------------------------------------------------
#define ZERO (min(int(iFrame),0))
//------------------------------------------------------------------
float href;
float hsha;
vec4 map( in vec3 pos, float atime )
{
hsha = 1.0;
float t1 = fract(atime);
float t4 = abs(fract(atime*0.5)-0.5)/0.5;
float p = 4.0*t1*(1.0-t1);
float pp = 4.0*(1.0-2.0*t1); // derivative of p
vec3 cen = vec3( 0.5*(-1.0 + 2.0*t4),
pow(p,2.0-p) + 0.1,
floor(atime) + pow(t1,0.7) -1.0 );
// body
vec2 uu = normalize(vec2( 1.0, -pp ));
vec2 vv = vec2(-uu.y, uu.x);
float sy = 0.5 + 0.5*p;
float compress = 1.0-smoothstep(0.0,0.4,p);
sy = sy*(1.0-compress) + compress;
float sz = 1.0/sy;
vec3 q = pos - cen;
float rot = -0.25*(-1.0 + 2.0*t4);
float rc = cos(rot);
float rs = sin(rot);
q.xy = mat2x2(rc,rs,-rs,rc)*q.xy;
vec3 r = q;
href = q.y;
q.yz = vec2( dot(uu,q.yz), dot(vv,q.yz) );
vec4 res = vec4( sdEllipsoid( q, vec3(0.25, 0.25*sy, 0.25*sz) ), 2.0, 0.0, 1.0 );
if( res.x-1.0 < pos.y ) // bounding volume
{
float t2 = fract(atime+0.8);
float p2 = 0.5-0.5*cos(6.2831*t2);
r.z += 0.05-0.2*p2;
r.y += 0.2*sy-0.2;
vec3 sq = vec3( abs(r.x), r.yz );
// head
vec3 h = r;
float hr = sin(0.791*atime);
hr = 0.7*sign(hr)*smoothstep(0.5,0.7,abs(hr));
h.xz = mat2x2(cos(hr),sin(hr),-sin(hr),cos(hr))*h.xz;
vec3 hq = vec3( abs(h.x), h.yz );
float d = sdEllipsoid( h-vec3(0.0,0.20,0.02), vec3(0.08,0.2,0.15) );
float d2 = sdEllipsoid( h-vec3(0.0,0.21,-0.1), vec3(0.20,0.2,0.20) );
d = smin( d, d2, 0.1 );
res.x = smin( res.x, d, 0.1 );
// belly wrinkles
{
float yy = r.y-0.02-2.5*r.x*r.x;
res.x += 0.001*sin(yy*120.0)*(1.0-smoothstep(0.0,0.1,abs(yy)));
}
// arms
{
vec2 arms = sdStick( sq, vec3(0.18-0.06*hr*sign(r.x),0.2,-0.05), vec3(0.3+0.1*p2,-0.2+0.3*p2,-0.15), 0.03, 0.06 );
res.xz = smin( res.xz, arms, 0.01+0.04*(1.0-arms.y)*(1.0-arms.y)*(1.0-arms.y) );
}
// ears
{
float t3 = fract(atime+0.9);
float p3 = 4.0*t3*(1.0-t3);
vec2 ear = sdStick( hq, vec3(0.15,0.32,-0.05), vec3(0.2+0.05*p3,0.2+0.2*p3,-0.07), 0.01, 0.04 );
res.xz = smin( res.xz, ear, 0.01 );
}
// mouth
{
d = sdEllipsoid( h-vec3(0.0,0.15+4.0*hq.x*hq.x,0.15), vec3(0.1,0.04,0.2) );
res.w = 0.3+0.7*clamp( d*150.0,0.0,1.0);
res.x = smax( res.x, -d, 0.03 );
}
// legs
{
float t6 = cos(6.2831*(atime*0.5+0.25));
float ccc = cos(1.57*t6*sign(r.x));
float sss = sin(1.57*t6*sign(r.x));
vec3 base = vec3(0.12,-0.07,-0.1); base.y -= 0.1/sy;
vec2 legs = sdStick( sq, base, base + vec3(0.2,-ccc,sss)*0.2, 0.04, 0.07 );
res.xz = smin( res.xz, legs, 0.07 );
}
// eye
{
float blink = pow(0.5+0.5*sin(2.1*iTime),20.0);
float eyeball = sdSphere(hq-vec3(0.08,0.27,0.06),0.065+0.02*blink);
res.x = smin( res.x, eyeball, 0.03 );
vec3 cq = hq-vec3(0.1,0.34,0.08);
cq.xy = mat2x2(0.8,0.6,-0.6,0.8)*cq.xy;
d = sdEllipsoid( cq, vec3(0.06,0.03,0.03) );
res.x = smin( res.x, d, 0.03 );
float eo = 1.0-0.5*smoothstep(0.01,0.04,length((hq.xy-vec2(0.095,0.285))*vec2(1.0,1.1)));
res = opU( res, vec4(sdSphere(hq-vec3(0.08,0.28,0.08),0.060),3.0,0.0,eo));
res = opU( res, vec4(sdSphere(hq-vec3(0.075,0.28,0.102),0.0395),4.0,0.0,1.0));
}
}
// ground
float fh = -0.1 - 0.05*(sin(pos.x*2.0)+sin(pos.z*2.0));
float t5f = fract(atime+0.05);
float t5i = floor(atime+0.05);
float bt4 = abs(fract(t5i*0.5)-0.5)/0.5;
vec2 bcen = vec2( 0.5*(-1.0+2.0*bt4),t5i+pow(t5f,0.7)-1.0 );
float k = length(pos.xz-bcen);
float tt = t5f*15.0-6.2831 - k*3.0;
fh -= 0.1*exp(-k*k)*sin(tt)*exp(-max(tt,0.0)/2.0)*smoothstep(0.0,0.01,t5f);
float d = pos.y - fh;
// bubbles
{
vec3 vp = vec3( mod(abs(pos.x),3.0)-1.5,pos.y,mod(pos.z+1.5,3.0)-1.5);
vec2 id = vec2( floor(pos.x/3.0), floor((pos.z+1.5)/3.0) );
float fid = id.x*11.1 + id.y*31.7;
float fy = fract(fid*1.312+atime*0.1);
float y = -1.0+4.0*fy;
vec3 rad = vec3(0.7,1.0+0.5*sin(fid),0.7);
rad -= 0.1*(sin(pos.x*3.0)+sin(pos.y*4.0)+sin(pos.z*5.0));
float siz = 4.0*fy*(1.0-fy);
float d2 = sdEllipsoid( vp-vec3(0.5,y,0.0), siz*rad );
d2 -= 0.03*smoothstep(-1.0,1.0,sin(18.0*pos.x)+sin(18.0*pos.y)+sin(18.0*pos.z));
d2 *= 0.6;
d2 = min(d2,2.0);
d = smin( d, d2, 0.32 );
if( d<res.x ) { res = vec4(d,1.0,0.0,1.0); hsha=sqrt(siz); }
}
// candy
{
float fs = 5.0;
vec3 qos = fs*vec3(pos.x, pos.y-fh, pos.z );
vec2 id = vec2( floor(qos.x+0.5), floor(qos.z+0.5) );
vec3 vp = vec3( fract(qos.x+0.5)-0.5,qos.y,fract(qos.z+0.5)-0.5);
vp.xz += 0.1*cos( id.x*130.143 + id.y*120.372 + vec2(0.0,2.0) );
float den = sin(id.x*0.1+sin(id.y*0.091))+sin(id.y*0.1);
float fid = id.x*0.143 + id.y*0.372;
float ra = smoothstep(0.0,0.1,den*0.1+fract(fid)-0.95);
d = sdSphere( vp, 0.35*ra )/fs;
if( d<res.x ) res = vec4(d,5.0,qos.y,1.0);
}
return res;
}
vec4 raycast( in vec3 ro, in vec3 rd, float time )
{
vec4 res = vec4(-1.0,-1.0,0.0,1.0);
float tmin = 0.5;
float tmax = 20.0;
#if 1
// raytrace bounding plane
float tp = (3.5-ro.y)/rd.y;
if( tp>0.0 ) tmax = min( tmax, tp );
#endif
// raymarch scene
float t = tmin;
for( int i=0; i<256 && t<tmax; i++ )
{
vec4 h = map( ro+rd*t, time );
if( abs(h.x)<(0.0005*t) )
{
res = vec4(t,h.yzw);
break;
}
t += h.x;
}
return res;
}
// http://iquilezles.org/www/articles/rmshadows/rmshadows.htm
float calcSoftshadow( in vec3 ro, in vec3 rd, float time )
{
float res = 1.0;
float tmax = 12.0;
#if 1
float tp = (3.5-ro.y)/rd.y; // raytrace bounding plane
if( tp>0.0 ) tmax = min( tmax, tp );
#endif
float t = 0.02;
for( int i=0; i<50; i++ )
{
float h = map( ro + rd*t, time ).x;
res = min( res, mix(1.0,16.0*h/t, hsha) );
t += clamp( h, 0.05, 0.40 );
if( res<0.005 || t>tmax ) break;
}
return clamp( res, 0.0, 1.0 );
}
// http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm
vec3 calcNormal( in vec3 pos, float time )
{
#if 0
vec2 e = vec2(1.0,-1.0)*0.5773*0.001;
return normalize( e.xyy*map( pos + e.xyy, time ).x +
e.yyx*map( pos + e.yyx, time ).x +
e.yxy*map( pos + e.yxy, time ).x +
e.xxx*map( pos + e.xxx, time ).x );
#else
// inspired by tdhooper and klems - a way to prevent the compiler from inlining map() 4 times
vec3 n = vec3(0.0);
for( int i=ZERO; i<4; i++ )
{
vec3 e = 0.5773*(2.0*vec3((((i+3)>>1)&1),((i>>1)&1),(i&1))-1.0);
n += e*map(pos+0.001*e,time).x;
}
return normalize(n);
#endif
}
float calcOcclusion( in vec3 pos, in vec3 nor, float time )
{
float occ = 0.0;
float sca = 1.0;
for( int i=ZERO; i<5; i++ )
{
float h = 0.01 + 0.11*float(i)/4.0;
vec3 opos = pos + h*nor;
float d = map( opos, time ).x;
occ += (h-d)*sca;
sca *= 0.95;
}
return clamp( 1.0 - 2.0*occ, 0.0, 1.0 );
}
vec3 render( in vec3 ro, in vec3 rd, float time )
{
// sky dome
vec3 col = vec3(0.5, 0.8, 0.9) - max(rd.y,0.0)*0.5;
// sky clouds
vec2 uv = 1.5*rd.xz/rd.y;
float cl = 1.0*(sin(uv.x)+sin(uv.y)); uv *= mat2(0.8,0.6,-0.6,0.8)*2.1;
cl += 0.5*(sin(uv.x)+sin(uv.y));
col += 0.1*(-1.0+2.0*smoothstep(-0.1,0.1,cl-0.4));
// sky horizon
col = mix( col, vec3(0.5, 0.7, .9), exp(-10.0*max(rd.y,0.0)) );
// scene geometry
vec4 res = raycast(ro,rd, time);
if( res.y>-0.5 )
{
float t = res.x;
vec3 pos = ro + t*rd;
vec3 nor = calcNormal( pos, time );
vec3 ref = reflect( rd, nor );
float focc = res.w;
// material
col = vec3(0.2);
float ks = 1.0;
if( res.y>4.5 ) // candy
{
col = vec3(0.14,0.048,0.0);
vec2 id = floor(5.0*pos.xz+0.5);
col += 0.036*cos((id.x*11.1+id.y*37.341) + vec3(0.0,1.0,2.0) );
col = max(col,0.0);
focc = clamp(4.0*res.z,0.0,1.0);
}
else if( res.y>3.5 ) // eyeball
{
col = vec3(0.0);
}
else if( res.y>2.5 ) // iris
{
col = vec3(0.4);
}
else if( res.y>1.5 ) // body
{
col = mix(vec3(0.144,0.09,0.0036),vec3(0.36,0.1,0.04),res.z*res.z);
col = mix(col,vec3(0.14,0.09,0.06)*2.0, (1.0-res.z)*smoothstep(-0.15, 0.15, -href));
}
else // terrain
{
// base green
col = vec3(0.05,0.09,0.02);
float f = 0.2*(-1.0+2.0*smoothstep(-0.2,0.2,sin(18.0*pos.x)+sin(18.0*pos.y)+sin(18.0*pos.z)));
col += f*vec3(0.06,0.06,0.02);
ks = 0.5 + pos.y*0.15;
// footprints
vec2 mp = vec2(pos.x-0.5*(mod(floor(pos.z+0.5),2.0)*2.0-1.0), fract(pos.z+0.5)-0.5 );
float mark = 1.0-smoothstep(0.1, 0.5, length(mp));
mark *= smoothstep(0.0, 0.1, floor(time) - floor(pos.z+0.5) );
col *= mix( vec3(1.0), vec3(0.5,0.5,0.4), mark );
ks *= 1.0-0.5*mark;
}
// lighting (sun, sky, bounce, back, sss)
float occ = calcOcclusion( pos, nor, time )*focc;
float fre = clamp(1.0+dot(nor,rd),0.0,1.0);
vec3 sun_lig = normalize( vec3(0.6, 0.35, 0.5) );
float sun_dif = clamp(dot( nor, sun_lig ), 0.0, 1.0 );
vec3 sun_hal = normalize( sun_lig-rd );
float sun_sha = calcSoftshadow( pos, sun_lig, time );
float sun_spe = ks*pow(clamp(dot(nor,sun_hal),0.0,1.0),8.0)*sun_dif*(0.04+0.96*pow(clamp(1.0+dot(sun_hal,rd),0.0,1.0),5.0));
float sky_dif = sqrt(clamp( 0.5+0.5*nor.y, 0.0, 1.0 ));
float sky_spe = ks*smoothstep( 0.0, 0.5, ref.y )*(0.04+0.96*pow(fre,4.0));
float bou_dif = sqrt(clamp( 0.1-0.9*nor.y, 0.0, 1.0 ))*clamp(1.0-0.1*pos.y,0.0,1.0);
float bac_dif = clamp(0.1+0.9*dot( nor, normalize(vec3(-sun_lig.x,0.0,-sun_lig.z))), 0.0, 1.0 );
float sss_dif = fre*sky_dif*(0.25+0.75*sun_dif*sun_sha);
vec3 lin = vec3(0.0);
lin += sun_dif*vec3(8.10,6.00,4.20)*vec3(sun_sha,sun_sha*sun_sha*0.5+0.5*sun_sha,sun_sha*sun_sha);
lin += sky_dif*vec3(0.50,0.70,1.00)*occ;
lin += bou_dif*vec3(0.20,0.70,0.10)*occ;
lin += bac_dif*vec3(0.45,0.35,0.25)*occ;
lin += sss_dif*vec3(3.25,2.75,2.50)*occ;
col = col*lin;
col += sun_spe*vec3(9.90,8.10,6.30)*sun_sha;
col += sky_spe*vec3(0.20,0.30,0.65)*occ*occ;
col = pow(col,vec3(0.8,0.9,1.0) );
// fog
col = mix( col, vec3(0.5,0.7,0.9), 1.0-exp( -0.0001*t*t*t ) );
}
return col;
}
mat3 setCamera( in vec3 ro, in vec3 ta, float cr )
{
vec3 cw = normalize(ta-ro);
vec3 cp = vec3(sin(cr), cos(cr),0.0);
vec3 cu = normalize( cross(cw,cp) );
vec3 cv = ( cross(cu,cw) );
return mat3( cu, cv, cw );
}
//void mainImage( out vec4 fragColor, in vec2 fragCoord )
vec4 mainImage( vec2 fragCoord )
{
vec3 tot = vec3(0.0);
#if AA>1
for( int m=ZERO; m<AA; m++ )
for( int n=ZERO; n<AA; n++ )
{
// pixel coordinates
vec2 o = vec2(float(m),float(n)) / float(AA) - 0.5;
vec2 p = (-iResolution.xy + 2.0*(fragCoord+o))/iResolution.y;
// time coordinate (motion blurred, shutter=0.5)
float d = 0.5+0.5*sin(fragCoord.x*147.0)*sin(fragCoord.y*131.0);
float time = iTime - 0.5*(1.0/24.0)*(float(m*AA+n)+d)/float(AA*AA);
#else
vec2 p = (-iResolution.xy + 2.0*fragCoord)/iResolution.y;
float time = iTime;
#endif
time += -2.6;
time *= 0.9;
// camera
float cl = sin(0.5*time);
float an = 1.57 + 0.7*sin(0.15*time);
vec3 ta = vec3( 0.0, 0.65, -0.6+time*1.0 - 0.4*cl);
vec3 ro = ta + vec3( 1.3*cos(an), -0.250, 1.3*sin(an) );
float ti = fract(time-0.15);
ti = 4.0*ti*(1.0-ti);
ta.y += 0.15*ti*ti*(3.0-2.0*ti)*smoothstep(0.4,0.9,cl);
// camera bounce
float t4 = abs(fract(time*0.5)-0.5)/0.5;
float bou = -1.0 + 2.0*t4;
ro += 0.06*sin(time*12.0+vec3(0.0,2.0,4.0))*smoothstep( 0.85, 1.0, abs(bou) );
// camera-to-world rotation
mat3 ca = setCamera( ro, ta, 0.0 );
// ray direction
vec3 rd = ca * normalize( vec3(p,1.8) );
// render
vec3 col = render( ro, rd, time );
// color grading
col = col*vec3(1.11,0.89,0.79);
// compress
col = 1.35*col/(1.0+col);
// gamma
col = pow( col, vec3(0.4545) );
tot += col;
#if AA>1
}
tot /= float(AA*AA);
#endif
// s-surve
tot = clamp(tot,0.0,1.0);
tot = tot*tot*(3.0-2.0*tot);
// vignetting
vec2 q = fragCoord/iResolution.xy;
tot *= 0.5 + 0.5*pow(16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.25);
// output
//fragColor = vec4( tot, 1.0 );
return vec4( tot, 1.0 );
}
//*********************************************************
// END Ray Marching
//*********************************************************
void main() {
vec4 c = color;
vec4 txt = texture(tex, uv);
c = txt * c;
vec2 uv1 = uv * iResolution;
vec4 col_ray = mainImage(uv1);
// use this to mix the chessboart texture with the ray marching
//frag_color = clamp(c*iMouse.y/512.0,0.0,1.0) * col_ray ;
frag_color = c*0.00001 + col_ray ;
}
#pragma sokol @end
#pragma sokol @program rt_puppy vs_p fs_p

View File

@@ -0,0 +1,505 @@
/**********************************************************************
*
* Sokol 3d cube multishader demo
*
* Copyright (c) 2021 Dario Deledda. All rights reserved.
* Use of this source code is governed by an MIT license
* that can be found in the LICENSE file.
*
* HOW TO COMPILE SHADERS:
* - download the sokol shader convertor tool from https://github.com/floooh/sokol-tools-bin/archive/pre-feb2021-api-changes.tar.gz
* ( also look at https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md )
* - compile the .glsl shared file with:
* linux : sokol-shdc --input rt_glsl_instancing.glsl --output rt_glsl_instancing.h --slang glsl330
* windows: sokol-shdc.exe --input rt_glsl_instancing.glsl --output rt_glsl_instancing.h --slang glsl330
*
* --slang parameter can be:
* - glsl330: desktop GL
* - glsl100: GLES2 / WebGL
* - glsl300es: GLES3 / WebGL2
* - hlsl4: D3D11
* - hlsl5: D3D11
* - metal_macos: Metal on macOS
* - metal_ios: Metal on iOS device
* - metal_sim: Metal on iOS simulator
* - wgpu: WebGPU
*
* you can have multiple platforms at the same time passing parameters like this: --slang glsl330:hlsl5:metal_macos
* for further infos have a look at the sokol shader tool docs.
*
* TODO:
* - frame counter
**********************************************************************/
import gg
import gg.m4
import gx
import math
import sokol.gfx
//import sokol.sgl
import time
const (
win_width = 800
win_height = 800
bg_color = gx.white
num_inst = 16384
)
struct App {
mut:
gg &gg.Context
texture C.sg_image
init_flag bool
frame_count int
mouse_x int = -1
mouse_y int = -1
mouse_down bool
// glsl
cube_pip_glsl C.sg_pipeline
cube_bind C.sg_bindings
pipe map[string]C.sg_pipeline
bind map[string]C.sg_bindings
// time
ticks i64
// instances
inst_pos [num_inst]m4.Vec4
// camera
camera_x f32
camera_z f32
}
/******************************************************************************
* GLSL Include and functions
******************************************************************************/
#flag -I @VROOT/.
#include "rt_glsl_instancing.h" #Please use sokol-shdc to generate the necessary rt_glsl_march.h file from rt_glsl_march.glsl (see the instructions at the top of this file)
fn C.instancing_shader_desc() &C.sg_shader_desc
/******************************************************************************
* Texture functions
******************************************************************************/
fn create_texture(w int, h int, buf byteptr) C.sg_image{
sz := w * h * 4
mut img_desc := C.sg_image_desc{
width: w
height: h
num_mipmaps: 0
min_filter: .linear
mag_filter: .linear
//usage: .dynamic
wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge
label: &byte(0)
d3d11_texture: 0
}
// comment if .dynamic is enabled
img_desc.content.subimage[0][0] = C.sg_subimage_content{
ptr: buf
size: sz
}
sg_img := C.sg_make_image(&img_desc)
return sg_img
}
fn destroy_texture(sg_img C.sg_image){
C.sg_destroy_image(sg_img)
}
// Use only if usage: .dynamic is enabled
fn update_text_texture(sg_img C.sg_image, w int, h int, buf byteptr){
sz := w * h * 4
mut tmp_sbc := C.sg_image_content{}
tmp_sbc.subimage[0][0] = C.sg_subimage_content {
ptr: buf
size: sz
}
C.sg_update_image(sg_img, &tmp_sbc)
}
/******************************************************************************
* Draw functions
******************************************************************************
Cube vertex buffer with packed vertex formats for color and texture coords.
Note that a vertex format which must be portable across all
backends must only use the normalized integer formats
(BYTE4N, UBYTE4N, SHORT2N, SHORT4N), which can be converted
to floating point formats in the vertex shader inputs.
The reason is that D3D11 cannot convert from non-normalized
formats to floating point inputs (only to integer inputs),
and WebGL2 / GLES2 don't support integer vertex shader inputs.
*/
struct Vertex_t {
x f32
y f32
z f32
color u32
//u u16 // for compatibility with D3D11
//v u16 // for compatibility with D3D11
u f32
v f32
}
// march shader init
fn init_cube_glsl_i(mut app App) {
/* cube vertex buffer */
//d := u16(32767) // for compatibility with D3D11, 32767 stand for 1
d := f32(1.0)
c := u32(0xFFFFFF_FF) // color RGBA8
vertices := [
// Face 0
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, d},
Vertex_t{-1.0, 1.0, -1.0, c, 0, d},
// Face 1
Vertex_t{-1.0, -1.0, 1.0, c, 0, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, 1.0, 1.0, c, 0, d},
// Face 2
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, -1.0, c, d, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, d},
Vertex_t{-1.0, -1.0, 1.0, c, 0, d},
// Face 3
Vertex_t{ 1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{ 1.0, 1.0, -1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, 1.0, c, 0, d},
// Face 4
Vertex_t{-1.0, -1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, -1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, -1.0, 1.0, c, d, d},
Vertex_t{ 1.0, -1.0, -1.0, c, 0, d},
// Face 5
Vertex_t{-1.0, 1.0, -1.0, c, 0, 0},
Vertex_t{-1.0, 1.0, 1.0, c, d, 0},
Vertex_t{ 1.0, 1.0, 1.0, c, d, d},
Vertex_t{ 1.0, 1.0, -1.0, c, 0, d},
]
mut vert_buffer_desc := C.sg_buffer_desc{}
unsafe {C.memset(&vert_buffer_desc, 0, sizeof(vert_buffer_desc))}
vert_buffer_desc.size = vertices.len * int(sizeof(Vertex_t))
vert_buffer_desc.content = byteptr(vertices.data)
vert_buffer_desc.@type = .vertexbuffer
vert_buffer_desc.label = "cube-vertices".str
vbuf := gfx.make_buffer(&vert_buffer_desc)
/* create an instance buffer for the cube */
mut inst_buffer_desc := C.sg_buffer_desc{}
unsafe {C.memset(&inst_buffer_desc, 0, sizeof(inst_buffer_desc))}
inst_buffer_desc.size = num_inst * int(sizeof(m4.Vec4))
inst_buffer_desc.@type = .vertexbuffer
inst_buffer_desc.usage = .stream
inst_buffer_desc.label = "instance-data".str
inst_buf := gfx.make_buffer(&inst_buffer_desc)
/* create an index buffer for the cube */
indices := [
u16(0), 1, 2, 0, 2, 3,
6, 5, 4, 7, 6, 4,
8, 9, 10, 8, 10, 11,
14, 13, 12, 15, 14, 12,
16, 17, 18, 16, 18, 19,
22, 21, 20, 23, 22, 20
]
mut index_buffer_desc := C.sg_buffer_desc{}
unsafe {C.memset(&index_buffer_desc, 0, sizeof(index_buffer_desc))}
index_buffer_desc.size = indices.len * int(sizeof(u16))
index_buffer_desc.content = byteptr(indices.data)
index_buffer_desc.@type = .indexbuffer
index_buffer_desc.label = "cube-indices".str
ibuf := gfx.make_buffer(&index_buffer_desc)
/* create shader */
shader := gfx.make_shader(C.instancing_shader_desc())
mut pipdesc := C.sg_pipeline_desc{}
unsafe {C.memset(&pipdesc, 0, sizeof(pipdesc))}
pipdesc.layout.buffers[0].stride = int(sizeof(Vertex_t))
// the constants [C.ATTR_vs_m_pos, C.ATTR_vs_m_color0, C.ATTR_vs_m_texcoord0] are generated by sokol-shdc
pipdesc.layout.attrs[C.ATTR_vs_i_pos ].format = .float3 // x,y,z as f32
pipdesc.layout.attrs[C.ATTR_vs_i_pos ].buffer_index = 0
pipdesc.layout.attrs[C.ATTR_vs_i_color0 ].format = .ubyte4n // color as u32
pipdesc.layout.attrs[C.ATTR_vs_i_pos ].buffer_index = 0
pipdesc.layout.attrs[C.ATTR_vs_i_texcoord0].format = .float2 // u,v as f32
pipdesc.layout.attrs[C.ATTR_vs_i_pos ].buffer_index = 0
// instancing
// the constant ATTR_vs_i_inst_pos is generated by sokol-shdc
pipdesc.layout.buffers[1].stride = int(sizeof(m4.Vec4))
pipdesc.layout.buffers[1].step_func = .per_instance // we will pass a single parameter for each instance!!
pipdesc.layout.attrs[C.ATTR_vs_i_inst_pos ].format = .float4
pipdesc.layout.attrs[C.ATTR_vs_i_inst_pos ].buffer_index = 1
pipdesc.shader = shader
pipdesc.index_type = .uint16
pipdesc.depth_stencil = C.sg_depth_stencil_state{
depth_write_enabled: true
depth_compare_func : gfx.CompareFunc(C.SG_COMPAREFUNC_LESS_EQUAL)
}
pipdesc.rasterizer = C.sg_rasterizer_state {
cull_mode: .back
}
pipdesc.label = "glsl_shader pipeline".str
mut bind := C.sg_bindings{}
unsafe {C.memset(&bind, 0, sizeof(bind))}
bind.vertex_buffers[0] = vbuf // vertex buffer
bind.vertex_buffers[1] = inst_buf // instance buffer
bind.index_buffer = ibuf
bind.fs_images[C.SLOT_tex] = app.texture
app.bind['inst'] = bind
app.pipe['inst'] = gfx.make_pipeline(&pipdesc)
println("GLSL March init DONE!")
}
fn calc_tr_matrices(w f32, h f32, rx f32, ry f32, in_scale f32) m4.Mat4{
proj := m4.perspective(60, w/h, 0.01, 4000.0)
view := m4.look_at(m4.Vec4{e:[f32(0.0),100,6,0]!}, m4.Vec4{e:[f32(0),0,0,0]!}, m4.Vec4{e:[f32(0),1.0,0,0]!})
view_proj := view * proj
rxm := m4.rotate(m4.rad(rx), m4.Vec4{e:[f32(1),0,0,0]!})
rym := m4.rotate(m4.rad(ry), m4.Vec4{e:[f32(0),1,0,0]!})
model := rym * rxm
scale_m := m4.scale(m4.Vec4{e:[in_scale, in_scale, in_scale, 1]!})
res := (scale_m * model)* view_proj
return res
}
// triangles draw
fn draw_cube_glsl_i(mut app App){
if app.init_flag == false {
return
}
ws := gg.window_size()
//ratio := f32(ws.width) / ws.height
dw := f32(ws.width / 2)
dh := f32(ws.height / 2)
rot := [f32(app.mouse_y), f32(app.mouse_x)]
tr_matrix := calc_tr_matrices(dw, dh, rot[0], rot[1], 2.3)
gfx.apply_pipeline(app.pipe['inst'])
gfx.apply_bindings(app.bind['inst'])
//***************
// Instancing
//***************
// passing the instancing to the vs
time_ticks := f32(time.ticks() - app.ticks) / 1000
cube_size := 2
sz := 128 // field size dimension
cx := 64 // x center for the cubes
cz := 64 // z center for the cubes
//frame := (app.frame_count/4) % 100
for index in 0..num_inst {
x := f32(index % sz)
z := f32(index / sz)
// simply waves
y := f32(math.cos((x+time_ticks)/2.0)*math.sin(z/2.0))*2
// sombrero function
//r := ((x-cx)*(x-cx)+(z-cz)*(z-cz))/(sz/2)
//y := f32(math.sin(r+time_ticks)*4.0)
spare_param := f32(index % 10)
app.inst_pos[index] = m4.Vec4{e:[f32((x - cx - app.camera_x) * cube_size),y ,f32( (z - cz - app.camera_z) * cube_size),spare_param]!}
}
gfx.update_buffer(app.bind['inst'].vertex_buffers[1], &app.inst_pos , num_inst * int(sizeof(m4.Vec4)) )
// Uniforms
// *** vertex shadeer uniforms ***
// passing the view matrix as uniform
// res is a 4x4 matrix of f32 thus: 4*16 byte of size
gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_i, &tr_matrix, 4*16 )
/*
// *** fragment shader uniforms ***
time_ticks := f32(time.ticks() - app.ticks) / 1000
mut tmp_fs_params := [
f32(ws.width), ws.height * ratio, // x,y resolution to pass to FS
0,0, // dont send mouse position
//app.mouse_x, // mouse x
//ws.height - app.mouse_y*2, // mouse y scaled
time_ticks, // time as f32
app.frame_count, // frame count
0,0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
]!
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params_i, &tmp_fs_params, int(sizeof(tmp_fs_params)))
*/
// 3 vertices for triangle * 2 triangles per face * 6 faces = 36 vertices to draw for num_inst times
gfx.draw(0, (3 * 2) * 6, num_inst)
}
fn draw_start_glsl(app App){
if app.init_flag == false {
return
}
ws := gg.window_size()
//ratio := f32(ws.width) / ws.height
//dw := f32(ws.width / 2)
//dh := f32(ws.height / 2)
gfx.apply_viewport(0, 0, ws.width, ws.height, true)
}
fn draw_end_glsl(app App){
gfx.end_pass()
gfx.commit()
}
fn frame(mut app App) {
ws := gg.window_size()
// clear
mut color_action := C.sg_color_attachment_action{
action: gfx.Action(C.SG_ACTION_CLEAR)
}
color_action.val[0] = 0
color_action.val[1] = 0
color_action.val[2] = 0
color_action.val[3] = 1.0
mut pass_action := C.sg_pass_action{}
pass_action.colors[0] = color_action
gfx.begin_default_pass(&pass_action, ws.width, ws.height)
draw_start_glsl(app)
draw_cube_glsl_i(mut app)
draw_end_glsl(app)
app.frame_count++
}
/******************************************************************************
* Init / Cleanup
******************************************************************************/
fn my_init(mut app App) {
// create chessboard texture 256*256 RGBA
w := 256
h := 256
sz := w * h * 4
tmp_txt := unsafe { malloc(sz) }
mut i := 0
for i < sz {
unsafe {
y := (i >> 0x8) >> 5 // 8 cell
x := (i & 0xFF) >> 5 // 8 cell
// upper left corner
if x == 0 && y == 0 {
tmp_txt[i + 0] = byte(0xFF)
tmp_txt[i + 1] = byte(0)
tmp_txt[i + 2] = byte(0)
tmp_txt[i + 3] = byte(0xFF)
}
// low right corner
else if x == 7 && y == 7 {
tmp_txt[i + 0] = byte(0)
tmp_txt[i + 1] = byte(0xFF)
tmp_txt[i + 2] = byte(0)
tmp_txt[i + 3] = byte(0xFF)
} else {
col := if ((x + y) & 1) == 1 { 0xFF } else { 128 }
tmp_txt[i + 0] = byte(col) // red
tmp_txt[i + 1] = byte(col) // green
tmp_txt[i + 2] = byte(col) // blue
tmp_txt[i + 3] = byte(0xFF) // alpha
}
i += 4
}
}
unsafe {
app.texture = create_texture(w, h, tmp_txt)
free(tmp_txt)
}
// glsl
init_cube_glsl_i(mut app)
app.init_flag = true
}
fn cleanup(mut app App) {
gfx.shutdown()
}
/******************************************************************************
* events handling
******************************************************************************/
fn my_event_manager(mut ev gg.Event, mut app App) {
if ev.typ == .mouse_down{
app.mouse_down = true
}
if ev.typ == .mouse_up{
app.mouse_down = false
}
if app.mouse_down == true && ev.typ == .mouse_move {
app.mouse_x = int(ev.mouse_x)
app.mouse_y = int(ev.mouse_y)
}
if ev.typ == .touches_began || ev.typ == .touches_moved {
if ev.num_touches > 0 {
touch_point := ev.touches[0]
app.mouse_x = int(touch_point.pos_x)
app.mouse_y = int(touch_point.pos_y)
}
}
// keyboard
if ev.typ == .key_down {
step := f32(1.0)
match ev.key_code {
.w { app.camera_z += step }
.s { app.camera_z -= step }
.a { app.camera_x -= step }
.d { app.camera_x += step }
else{}
}
}
}
/******************************************************************************
* Main
******************************************************************************/
[console] // is needed for easier diagnostics on windows
fn main(){
// App init
mut app := &App{
gg: 0
}
app.gg = gg.new_context({
width: win_width
height: win_height
use_ortho: true // This is needed for 2D drawing
create_window: true
window_title: 'Instancing Cube'
user_data: app
bg_color: bg_color
frame_fn: frame
init_fn: my_init
cleanup_fn: cleanup
event_fn: my_event_manager
})
app.ticks = time.ticks()
app.gg.run()
}

View File

@@ -0,0 +1,64 @@
//------------------------------------------------------------------------------
// Shader code for texcube-sapp sample.
//
// NOTE: This source file also uses the '#pragma sokol' form of the
// custom tags.
//------------------------------------------------------------------------------
//#pragma sokol @ctype mat4 hmm_mat4
#pragma sokol @vs vs_i
uniform vs_params_i {
mat4 mvp;
};
in vec4 pos;
in vec4 color0;
in vec2 texcoord0;
in vec4 inst_pos;
out vec4 color;
out vec4 color_inst;
out vec2 uv;
const vec4 palette[10] = vec4[10](
vec4(1,0,0,1),
vec4(0,1,0,1),
vec4(0,0,1,1),
vec4(1,1,0,1),
vec4(0,1,1,1),
vec4(1,1,1,1),
vec4(0,0,0,1),
vec4(0.2,0.2,0.2,1),
vec4(0.3,0.3,0.3,1),
vec4(0.9,0.9,0.9,1)
);
void main() {
vec4 delta_pos = vec4(inst_pos.xyz,0);
float w = inst_pos.w;
color_inst = palette[int(w)];
gl_Position = mvp * (pos + delta_pos);
color = color0;
uv = texcoord0/4;
}
#pragma sokol @end
#pragma sokol @fs fs_i
uniform sampler2D tex;
in vec4 color;
in vec4 color_inst;
in vec2 uv;
out vec4 frag_color;
void main() {
vec4 c = color;
vec4 txt = texture(tex, uv);
c = txt * c * color_inst;
frag_color = c ;
}
#pragma sokol @end
#pragma sokol @program instancing vs_i fs_i

View File

View File

@@ -2,11 +2,13 @@ import gg
import gx
import sokol.audio
const credits = 'Based on the ByteBeat formula from: https://www.youtube.com/watch?v=V4GfkFbDojc \n "Techno" by Gabriel Miceli'
struct AppState {
mut:
gframe int // the current graphical frame
frame_0 int // offset of the current audio frames, relative to the start of the music
frames [2048]f32 // a copy of the last rendered audio frames
gframe int // the current graphical frame
frame_0 int // offset of the current audio frames, relative to the start of the music
frames [2048]f32 // a copy of the last rendered audio frames
gg &gg.Context // used for drawing
}
@@ -14,10 +16,8 @@ fn my_audio_stream_callback(buffer &f32, num_frames int, num_channels int, mut a
mut soundbuffer := buffer
for frame := 0; frame < num_frames; frame++ {
t := int(f32(acontext.frame_0 + frame) * 0.245)
// Credits for the formula below: https://www.youtube.com/watch?v=V4GfkFbDojc
// "Techno" by Gabriel Miceli
y := (t * (((t / 10 | 0) ^ ((t / 10 | 0) -
1280)) % 11) / 2 & 127) +
y := (t * (((t / 10 | 0) ^ ((t / 10 | 0) - 1280)) % 11) / 2 & 127) +
(t * (((t / 640 | 0) ^ ((t / 640 | 0) - 2)) % 13) / 2 & 127)
for ch := 0; ch < num_channels; ch++ {
idx := frame * num_channels + ch
@@ -32,14 +32,15 @@ fn my_audio_stream_callback(buffer &f32, num_frames int, num_channels int, mut a
}
fn main() {
println(credits)
mut state := &AppState{
gg: 0
}
audio.setup({
audio.setup(
stream_userdata_cb: my_audio_stream_callback
user_data: state
})
state.gg = gg.new_context({
)
state.gg = gg.new_context(
bg_color: gx.rgb(50, 50, 50)
width: 1024
height: 400
@@ -48,7 +49,7 @@ fn main() {
window_title: 'ByteBeat Music'
frame_fn: graphics_frame
user_data: state
})
)
state.gg.run()
audio.shutdown()
}

View File

@@ -19,14 +19,14 @@ fn my_audio_stream_callback(buffer &f32, num_frames int, num_channels int) {
for frame := 0; frame < num_frames; frame++ {
for ch := 0; ch < num_channels; ch++ {
idx := frame * num_channels + ch
if ms < 500 {
soundbuffer[idx] = sintone(20, frame, num_frames)
} else if ms < 1000 {
soundbuffer[idx] = sintone(25, frame, num_frames)
if ms < 250 {
soundbuffer[idx] = 0.5 * sintone(20, frame, num_frames)
} else if ms < 300 {
soundbuffer[idx] = 0.5 * sintone(25, frame, num_frames)
} else if ms < 1500 {
soundbuffer[idx] *= sintone(22, frame, num_frames)
} else {
soundbuffer[idx] = sintone(25, frame, num_frames)
soundbuffer[idx] = 0.5 * sintone(25, frame, num_frames)
}
}
}
@@ -34,9 +34,9 @@ fn my_audio_stream_callback(buffer &f32, num_frames int, num_channels int) {
}
fn main() {
audio.setup({
audio.setup(
stream_cb: my_audio_stream_callback
})
time.sleep_ms(2500)
)
time.wait(2000 * time.millisecond)
audio.shutdown()
}

View File

@@ -72,7 +72,7 @@ fn (mut p Player) play_wav_file(fpath string) ? {
p.samples << samples
p.finished = false
for !p.finished {
time.sleep_ms(16)
time.wait(16 * time.millisecond)
}
p.free()
}

View File

@@ -0,0 +1,197 @@
[
{
"name": "www_threefold_io",
"url": "https://github.com/threefoldfoundation/www_threefold_io",
"branch": "default",
"pull": false,
"cat": 2,
"alias": "tf",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/www_threefold_io",
"domains": [
"www.threefold.io",
"www.threefold.me"
],
"descr": "is our entry point for everyone, redirect to the detailed websites underneith."
},
{
"name": "www_threefold_cloud",
"url": "https://github.com/threefoldfoundation/www_threefold_cloud",
"branch": "default",
"pull": false,
"cat": 2,
"alias": "cloud",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/www_threefold_cloud",
"domains": [
"cloud.threefold.io",
"cloud.threefold.me"
],
"descr": "for people looking to deploy solutions on top of a cloud, alternative to e.g. digital ocean"
},
{
"name": "www_threefold_farming",
"url": "https://github.com/threefoldfoundation/www_threefold_farming",
"branch": "default",
"pull": false,
"cat": 2,
"alias": "farming",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/www_threefold_farming",
"domains": [
"farming.threefold.io",
"farming.threefold.me"
],
"descr": "crypto & minining enthusiasts, be the internet, know about farming & tokens."
},
{
"name": "www_threefold_twin",
"url": "https://github.com/threefoldfoundation/www_threefold_twin",
"branch": "default",
"pull": false,
"cat": 2,
"alias": "twin",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/www_threefold_twin",
"domains": [
"twin.threefold.io",
"twin.threefold.me"
],
"descr": "you digital life"
},
{
"name": "www_threefold_marketplace",
"url": "https://github.com/threefoldfoundation/www_threefold_marketplace",
"branch": "default",
"pull": false,
"cat": 2,
"alias": "marketplace",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/www_threefold_marketplace",
"domains": [
"now.threefold.io",
"marketplace.threefold.io",
"now.threefold.me",
"marketplace.threefold.me"
],
"descr": "apps for community builders, runs on top of evdc"
},
{
"name": "www_conscious_internet",
"url": "https://github.com/threefoldfoundation/www_conscious_internet",
"branch": "default",
"pull": false,
"cat": 2,
"alias": "conscious_internet",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/www_conscious_internet",
"domains": [
"www.consciousinternet.org",
"eco.threefold.io",
"community.threefold.io",
"eco.threefold.me",
"community.threefold.me"
],
"descr": "community around threefold, partners, friends, ..."
},
{
"name": "www_threefold_tech",
"url": "https://github.com/threefoldtech/www_threefold_tech",
"branch": "default",
"pull": false,
"cat": 2,
"alias": "tech",
"path_code": "/Users/despiegk/codewww/github/threefoldtech/www_threefold_tech",
"domains": [
"www.threefold.tech"
],
"descr": "cyberpandemic, use the tech to build your own solutions with, certification for TFGrid"
},
{
"name": "www_examplesite",
"url": "https://github.com/threefoldfoundation/www_examplesite",
"branch": "default",
"pull": false,
"cat": 2,
"alias": "example",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/www_examplesite",
"domains": [
"example.threefold.io"
],
"descr": ""
},
{
"name": "info_threefold",
"url": "https://github.com/threefoldfoundation/info_foundation_archive",
"branch": "default",
"pull": false,
"cat": 0,
"alias": "threefold",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/info_foundation_archive",
"domains": [
"info.threefold.io"
],
"descr": "wiki for foundation, collaborate, what if farmings, tokens"
},
{
"name": "info_sdk",
"url": "https://github.com/threefoldfoundation/info_sdk",
"branch": "default",
"pull": false,
"cat": 0,
"alias": "sdk",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/info_sdk",
"domains": [
"sdk.threefold.io",
"sdk_info.threefold.io"
],
"descr": "for IAC, devops, how to do Infrastruture As Code, 3bot, Ansible, tfgrid-sdk, ..."
},
{
"name": "info_legal",
"url": "https://github.com/threefoldfoundation/info_legal",
"branch": "default",
"pull": false,
"cat": 0,
"alias": "legal",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/info_legal",
"domains": [
"legal.threefold.io",
"legal_info.threefold.io"
],
"descr": ""
},
{
"name": "info_cloud",
"url": "https://github.com/threefoldfoundation/info_cloud",
"branch": "default",
"pull": false,
"cat": 0,
"alias": "cloud",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/info_cloud",
"domains": [
"cloud_info.threefold.io"
],
"descr": "how to use the cloud for deploying apps: evdc, kubernetes, planetary fs, ... + marketplace solutions "
},
{
"name": "info_tftech",
"url": "https://github.com/threefoldtech/info_tftech",
"branch": "default",
"pull": false,
"cat": 0,
"alias": "tftech",
"path_code": "/Users/despiegk/codewww/github/threefoldtech/info_tftech",
"domains": [
"info.threefold.tech"
],
"descr": ""
},
{
"name": "info_digitaltwin",
"url": "https://github.com/threefoldfoundation/info_digitaltwin.git",
"branch": "default",
"pull": false,
"cat": 0,
"alias": "twin",
"path_code": "/Users/despiegk/codewww/github/threefoldfoundation/info_digitaltwin",
"domains": [
"twin_info.threefold.io"
],
"descr": ""
}
]

View File

@@ -0,0 +1,14 @@
# example how to work with templates
- templates support
- if
- for loops
- even nesting of for loops
- syntax checking
- embed the template into the binary
Its a very cool way how to do also do e.g. system administration, fill in
config files, etc...
The example there is also a good demonstration of how to use json on a more
complex object and read/write to file.

View File

@@ -0,0 +1,101 @@
# WIKIs
## info.threefold.io80
- [errors]("//info.threefold.io80/errors")
### domains
- info.threefold.io
## sdk.threefold.io80
- [errors]("//sdk.threefold.io80/errors")
### domains
- sdk.threefold.io
- sdk_info.threefold.io
## legal.threefold.io80
- [errors]("//legal.threefold.io80/errors")
### domains
- legal.threefold.io
- legal_info.threefold.io
## cloud_info.threefold.io80
- [errors]("//cloud_info.threefold.io80/errors")
### domains
- cloud_info.threefold.io
## info.threefold.tech80
- [errors]("//info.threefold.tech80/errors")
### domains
- info.threefold.tech
## twin_info.threefold.io80
- [errors]("//twin_info.threefold.io80/errors")
### domains
- twin_info.threefold.io

View File

@@ -0,0 +1,16 @@
# WIKIs
@for site in sites
@if site.cat == .wiki
## @{site.domains[0]}@port_str
- [errors]("//@{site.domains[0]}@port_str/errors")
### domains
@for dom in site.domains
- @dom
@end
@end
@end

View File

@@ -0,0 +1,196 @@
module main
import os
import json
pub struct SiteConfig {
pub mut:
name string
url string
branch string = 'default' // means is the default branch
pull bool
cat SiteCat
alias string
path_code string
domains []string
descr string
}
pub enum SiteCat {
wiki
data
web
}
fn data_get() []SiteConfig {
data := [SiteConfig{
name: 'www_threefold_io'
url: 'https://github.com/threefoldfoundation/www_threefold_io'
branch: 'default'
pull: false
cat: .web
alias: 'tf'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/www_threefold_io'
domains: ['www.threefold.io', 'www.threefold.me']
descr: 'is our entry point for everyone, redirect to the detailed websites underneith.'
}, SiteConfig{
name: 'www_threefold_cloud'
url: 'https://github.com/threefoldfoundation/www_threefold_cloud'
branch: 'default'
pull: false
cat: .web
alias: 'cloud'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/www_threefold_cloud'
domains: ['cloud.threefold.io', 'cloud.threefold.me']
descr: 'for people looking to deploy solutions on top of a cloud, alternative to e.g. digital ocean'
}, SiteConfig{
name: 'www_threefold_farming'
url: 'https://github.com/threefoldfoundation/www_threefold_farming'
branch: 'default'
pull: false
cat: .web
alias: 'farming'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/www_threefold_farming'
domains: ['farming.threefold.io', 'farming.threefold.me']
descr: 'crypto & minining enthusiasts, be the internet, know about farming & tokens.'
}, SiteConfig{
name: 'www_threefold_twin'
url: 'https://github.com/threefoldfoundation/www_threefold_twin'
branch: 'default'
pull: false
cat: .web
alias: 'twin'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/www_threefold_twin'
domains: ['twin.threefold.io', 'twin.threefold.me']
descr: 'you digital life'
}, SiteConfig{
name: 'www_threefold_marketplace'
url: 'https://github.com/threefoldfoundation/www_threefold_marketplace'
branch: 'default'
pull: false
cat: .web
alias: 'marketplace'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/www_threefold_marketplace'
domains: ['now.threefold.io', 'marketplace.threefold.io', 'now.threefold.me', 'marketplace.threefold.me']
descr: 'apps for community builders, runs on top of evdc'
}, SiteConfig{
name: 'www_conscious_internet'
url: 'https://github.com/threefoldfoundation/www_conscious_internet'
branch: 'default'
pull: false
cat: .web
alias: 'conscious_internet'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/www_conscious_internet'
domains: ['www.consciousinternet.org', 'eco.threefold.io', 'community.threefold.io', 'eco.threefold.me',
'community.threefold.me',
]
descr: 'community around threefold, partners, friends, ...'
}, SiteConfig{
name: 'www_threefold_tech'
url: 'https://github.com/threefoldtech/www_threefold_tech'
branch: 'default'
pull: false
cat: .web
alias: 'tech'
path_code: '/Users/despiegk/codewww/github/threefoldtech/www_threefold_tech'
domains: ['www.threefold.tech']
descr: 'cyberpandemic, use the tech to build your own solutions with, certification for TFGrid'
}, SiteConfig{
name: 'www_examplesite'
url: 'https://github.com/threefoldfoundation/www_examplesite'
branch: 'default'
pull: false
cat: .web
alias: 'example'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/www_examplesite'
domains: ['example.threefold.io']
descr: ''
}, SiteConfig{
name: 'info_threefold'
url: 'https://github.com/threefoldfoundation/info_foundation_archive'
branch: 'default'
pull: false
cat: .wiki
alias: 'threefold'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/info_foundation_archive'
domains: ['info.threefold.io']
descr: 'wiki for foundation, collaborate, what if farmings, tokens'
}, SiteConfig{
name: 'info_sdk'
url: 'https://github.com/threefoldfoundation/info_sdk'
branch: 'default'
pull: false
cat: .wiki
alias: 'sdk'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/info_sdk'
domains: ['sdk.threefold.io', 'sdk_info.threefold.io']
descr: 'for IAC, devops, how to do Infrastruture As Code, 3bot, Ansible, tfgrid-sdk, ...'
}, SiteConfig{
name: 'info_legal'
url: 'https://github.com/threefoldfoundation/info_legal'
branch: 'default'
pull: false
cat: .wiki
alias: 'legal'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/info_legal'
domains: ['legal.threefold.io', 'legal_info.threefold.io']
descr: ''
}, SiteConfig{
name: 'info_cloud'
url: 'https://github.com/threefoldfoundation/info_cloud'
branch: 'default'
pull: false
cat: .wiki
alias: 'cloud'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/info_cloud'
domains: ['cloud_info.threefold.io']
descr: 'how to use the cloud for deploying apps: evdc, kubernetes, planetary fs, ... + marketplace solutions '
}, SiteConfig{
name: 'info_tftech'
url: 'https://github.com/threefoldtech/info_tftech'
branch: 'default'
pull: false
cat: .wiki
alias: 'tftech'
path_code: '/Users/despiegk/codewww/github/threefoldtech/info_tftech'
domains: ['info.threefold.tech']
descr: ''
}, SiteConfig{
name: 'info_digitaltwin'
url: 'https://github.com/threefoldfoundation/info_digitaltwin.git'
branch: 'default'
pull: false
cat: .wiki
alias: 'twin'
path_code: '/Users/despiegk/codewww/github/threefoldfoundation/info_digitaltwin'
domains: ['twin_info.threefold.io']
descr: ''
}]
return data
}
fn data_dump(data []SiteConfig) {
a := json.encode_pretty(data)
os.write_file(os.resource_abs_path('data.json'), a) or { panic(err) }
}
fn data_load() []SiteConfig {
data := os.read_file(os.resource_abs_path('data.json')) or { panic(err) }
a := json.decode([]SiteConfig, data) or { panic(err) }
return a
}
fn filled_in_template() string {
port_str := '80'
sites := data_load()
return $tmpl('template.md')
}
fn main() {
// A NICE test how to work with the json module
// data := data_get()
// data_dump(data)
b := filled_in_template()
println(b)
os.write_file('result.md', b) or { panic(err) }
}

View File

@@ -88,11 +88,13 @@ fn event(e &tui.Event, x voidptr) {
}
}
mut app := &App{}
app.tui = tui.init(
user_data: app
frame_fn: frame
event_fn: event
hide_cursor: true
)
app.tui.run() ?
fn main() {
mut app := &App{}
app.tui = tui.init(
user_data: app
frame_fn: frame
event_fn: event
hide_cursor: true
)
app.tui.run() ?
}

View File

@@ -12,15 +12,15 @@ fn event(e &tui.Event, x voidptr) {
app.tui.write('V term.input event viewer (press `esc` to exit)\n\n')
app.tui.write('$e')
app.tui.write('\n\nRaw event bytes: "$e.utf8.bytes().hex()" = $e.utf8.bytes()')
if e.modifiers != 0 {
if !e.modifiers.is_empty() {
app.tui.write('\nModifiers: $e.modifiers = ')
if e.modifiers & tui.ctrl != 0 {
if e.modifiers.has(.ctrl) {
app.tui.write('ctrl. ')
}
if e.modifiers & tui.shift != 0 {
if e.modifiers.has(.shift) {
app.tui.write('shift ')
}
if e.modifiers & tui.alt != 0 {
if e.modifiers.has(.alt) {
app.tui.write('alt. ')
}
}
@@ -31,15 +31,17 @@ fn event(e &tui.Event, x voidptr) {
}
}
mut app := &App{}
app.tui = tui.init(
user_data: app
event_fn: event
window_title: 'V term.ui event viewer'
hide_cursor: true
capture_events: true
frame_rate: 60
use_alternate_buffer: false
)
println('V term.ui event viewer (press `esc` to exit)\n\n')
app.tui.run() ?
fn main() {
mut app := &App{}
app.tui = tui.init(
user_data: app
event_fn: event
window_title: 'V term.ui event viewer'
hide_cursor: true
capture_events: true
frame_rate: 60
use_alternate_buffer: false
)
println('V term.ui event viewer (press `esc` to exit)\n\n')
app.tui.run() ?
}

View File

@@ -480,17 +480,18 @@ fn event(e &ui.Event, x voidptr) {
app.event(e)
}
// main
mut app := &App{}
app.tui = ui.init(
user_data: app
init_fn: init
frame_fn: frame
cleanup_fn: cleanup
event_fn: event
fail_fn: fail
capture_events: true
hide_cursor: true
frame_rate: 60
)
app.tui.run() ?
fn main() {
mut app := &App{}
app.tui = ui.init(
user_data: app
init_fn: init
frame_fn: frame
cleanup_fn: cleanup
event_fn: event
fail_fn: fail
capture_events: true
hide_cursor: true
frame_rate: 60
)
app.tui.run() ?
}

View File

@@ -84,12 +84,14 @@ fn frame(x voidptr) {
app.redraw = false
}
mut app := &App{}
app.tui = tui.init(
user_data: app
event_fn: event
frame_fn: frame
hide_cursor: true
frame_rate: 60
)
app.tui.run() ?
fn main() {
mut app := &App{}
app.tui = tui.init(
user_data: app
event_fn: event
frame_fn: frame
hide_cursor: true
frame_rate: 60
)
app.tui.run() ?
}

View File

@@ -174,8 +174,8 @@ fn event(event &ui.Event, x voidptr) {
y: event.y
}
d := event.direction == .down
if event.modifiers & ui.ctrl != 0 {
p := event.modifiers & ui.shift == 0
if event.modifiers.has(.ctrl) {
p := !event.modifiers.has(.shift)
c := if d {
if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 }
} else {
@@ -212,43 +212,53 @@ fn event(event &ui.Event, x voidptr) {
}
app.paint(nevent)
}
.space {
.space, .enter {
oevent := *event
nevent := ui.Event{
...oevent
button: ui.MouseButton.middle
button: .left
x: app.mouse_pos.x
y: app.mouse_pos.y
}
app.paint(nevent)
}
.delete, .backspace {
oevent := *event
nevent := ui.Event{
...oevent
button: .middle
x: app.mouse_pos.x
y: app.mouse_pos.y
}
app.paint(nevent)
}
.j, .down {
if event.modifiers & ui.shift != 0 {
if event.modifiers.has(.shift) {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
}
app.mouse_pos.y++
}
.k, .up {
if event.modifiers & ui.shift != 0 {
if event.modifiers.has(.shift) {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
}
app.mouse_pos.y--
}
.h, .left {
if event.modifiers & ui.shift != 0 {
if event.modifiers.has(.shift) {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
}
app.mouse_pos.x -= 2
}
.l, .right {
if event.modifiers & ui.shift != 0 {
if event.modifiers.has(.shift) {
app.set_pixel((1 + app.mouse_pos.x) / 2, app.mouse_pos.y, app.primary_color)
}
app.mouse_pos.x += 2
}
.t {
p := event.modifiers & ui.alt == 0
c := if event.modifiers & ui.shift != 0 {
p := !event.modifiers.has(.alt)
c := if event.modifiers.has(.shift) {
if p { app.primary_color_idx - 19 } else { app.secondary_color_idx - 19 }
} else {
if p { app.primary_color_idx + 19 } else { app.secondary_color_idx + 19 }
@@ -256,8 +266,8 @@ fn event(event &ui.Event, x voidptr) {
app.select_color(p, c)
}
.r {
p := event.modifiers & ui.alt == 0
c := if event.modifiers & ui.shift != 0 {
p := !event.modifiers.has(.alt)
c := if event.modifiers.has(.shift) {
if p { app.primary_color_idx - 1 } else { app.secondary_color_idx - 1 }
} else {
if p { app.primary_color_idx + 1 } else { app.secondary_color_idx + 1 }

View File

@@ -300,7 +300,7 @@ fn (mut b Buffer) free() {
eprintln(@MOD + '.' + @STRUCT + '::' + @FN)
}
for line in b.lines {
line.free()
unsafe {line.free()}
}
unsafe { b.lines.free() }
}
@@ -515,17 +515,17 @@ fn event(e &tui.Event, x voidptr) {
buffer.del(1)
}
.left {
if e.modifiers == tui.ctrl {
if e.modifiers == .ctrl {
buffer.move_to_word(.left)
} else if e.modifiers == 0 {
} else if e.modifiers.is_empty() {
buffer.move_cursor(1, .left)
}
a.magnet_x = buffer.cursor.pos_x
}
.right {
if e.modifiers == tui.ctrl {
if e.modifiers == .ctrl {
buffer.move_to_word(.right)
} else if e.modifiers == 0 {
} else if e.modifiers.is_empty() {
buffer.move_cursor(1, .right)
}
a.magnet_x = buffer.cursor.pos_x
@@ -551,16 +551,16 @@ fn event(e &tui.Event, x voidptr) {
buffer.move_cursor(1, .end)
}
48...57, 97...122 { // 0-9a-zA-Z
if e.modifiers == tui.ctrl {
if e.modifiers == .ctrl {
if e.code == .s {
a.save()
}
} else if e.modifiers in [tui.shift, 0] && e.code != .null {
} else if !(e.modifiers.has(.ctrl | .alt) || e.code == .null) {
buffer.put(e.ascii.ascii_str())
}
}
else {
if e.modifiers == tui.alt {
if e.modifiers == .alt {
if e.code == .comma {
a.visit_prev_file()
return

View File

@@ -460,13 +460,15 @@ fn (mut a App) draw_gameover() {
a.termui.draw_text(start_x, (a.height / 2) + 3 * block_size, ' ##### # # # # ###### ####### ## ###### # # ')
}
mut app := &App{}
app.termui = termui.init(
user_data: app
event_fn: event
frame_fn: frame
init_fn: init
hide_cursor: true
frame_rate: 10
)
app.termui.run() ?
fn main() {
mut app := &App{}
app.termui = termui.init(
user_data: app
event_fn: event
frame_fn: frame
init_fn: init
hide_cursor: true
frame_rate: 10
)
app.termui.run() ?
}

View File

@@ -8,10 +8,10 @@ import rand
import time
import gx
import gg
import sokol.sapp
// import sokol.sapp
const (
block_size = 20 // pixels
block_size = 20 // virtual pixels
field_height = 20 // # of blocks
field_width = 10
tetro_size = 4
@@ -61,7 +61,7 @@ const (
gx.rgb(255, 180, 31), /* orange long topleft */
gx.rgb(33, 66, 255), /* blue long topright */
gx.rgb(74, 198, 255), /* lightblue longest */
gx.rgb(0, 170, 170), /* unused ? */
gx.rgb(0, 170, 170),
]
background_color = gx.white
ui_color = gx.rgba(255, 0, 0, 210)
@@ -88,6 +88,10 @@ mut:
lines int
// State of the current game
state GameState
// Block size in screen dimensions
block_size int = block_size
// Field margin
margin int
// Position of the current tetro
pos_x int
pos_y int
@@ -119,6 +123,10 @@ mut:
second_sw time.StopWatch = time.new_stopwatch({})
}
fn remap(v f32, min f32, max f32, new_min f32, new_max f32) f32 {
return (((v - min) * (new_max - new_min)) / (max - min)) + new_min
}
[if showfps]
fn (mut game Game) showfps() {
game.frame++
@@ -135,6 +143,11 @@ fn (mut game Game) showfps() {
}
fn frame(mut game Game) {
ws := gg.window_size()
bs := remap(block_size, 0, win_height, 0, ws.height)
m := (f32(ws.width) - bs * field_width) * 0.5
game.block_size = int(bs)
game.margin = int(m)
game.frame_sw.restart()
game.gg.begin()
game.draw_scene()
@@ -205,7 +218,7 @@ fn (mut g Game) run() {
g.delete_completed_lines()
}
// glfw.post_empty_event() // force window redraw
time.sleep_ms(timer_period)
time.wait(timer_period * time.millisecond)
}
}
@@ -343,8 +356,8 @@ fn (g &Game) draw_next_tetro() {
}
fn (g &Game) draw_block_color(i int, j int, color gx.Color) {
g.gg.draw_rect(f32((j - 1) * block_size), f32((i - 1) * block_size), f32(block_size - 1),
f32(block_size - 1), color)
g.gg.draw_rect(f32((j - 1) * g.block_size) + g.margin, f32((i - 1) * g.block_size),
f32(g.block_size - 1), f32(g.block_size - 1), color)
}
fn (g &Game) draw_block(i int, j int, color_idx int) {
@@ -363,17 +376,19 @@ fn (g &Game) draw_field() {
}
fn (mut g Game) draw_ui() {
ws := gg.window_size()
textsize := int(remap(text_size, 0, win_width, 0, ws.width))
g.gg.draw_text(1, 3, g.score.str(), text_cfg)
lines := g.lines.str()
g.gg.draw_text(win_width - lines.len * text_size, 3, lines, text_cfg)
g.gg.draw_text(ws.width - lines.len * textsize, 3, lines, text_cfg)
if g.state == .gameover {
g.gg.draw_rect(0, win_height / 2 - text_size, win_width, 5 * text_size, ui_color)
g.gg.draw_text(1, win_height / 2 + 0 * text_size, 'Game Over', over_cfg)
g.gg.draw_text(1, win_height / 2 + 2 * text_size, 'Space to restart', over_cfg)
g.gg.draw_rect(0, ws.height / 2 - textsize, ws.width, 5 * textsize, ui_color)
g.gg.draw_text(1, ws.height / 2 + 0 * textsize, 'Game Over', over_cfg)
g.gg.draw_text(1, ws.height / 2 + 2 * textsize, 'Space to restart', over_cfg)
} else if g.state == .paused {
g.gg.draw_rect(0, win_height / 2 - text_size, win_width, 5 * text_size, ui_color)
g.gg.draw_text(1, win_height / 2 + 0 * text_size, 'Game Paused', text_cfg)
g.gg.draw_text(1, win_height / 2 + 2 * text_size, 'SPACE to resume', text_cfg)
g.gg.draw_rect(0, ws.height / 2 - textsize, ws.width, 5 * textsize, ui_color)
g.gg.draw_text(1, ws.height / 2 + 0 * textsize, 'Game Paused', text_cfg)
g.gg.draw_text(1, ws.height / 2 + 2 * textsize, 'SPACE to resume', text_cfg)
}
// g.gg.draw_rect(0, block_size, win_width, limit_thickness, ui_color)
}
@@ -411,14 +426,36 @@ fn parse_binary_tetro(t_ int) []Block {
return res
}
fn on_event(e &sapp.Event, mut game Game) {
fn on_event(e &gg.Event, mut game Game) {
// println('code=$e.char_code')
if e.typ == .key_down {
game.key_down(e.key_code)
}
if e.typ == .touches_began || e.typ == .touches_moved {
if e.num_touches > 0 {
touch_point := e.touches[0]
game.touch_event(touch_point)
}
}
}
fn (mut game Game) key_down(key sapp.KeyCode) {
fn (mut game Game) rotate_tetro() {
old_rotation_idx := game.rotation_idx
game.rotation_idx++
if game.rotation_idx == tetro_size {
game.rotation_idx = 0
}
game.get_tetro()
if !game.move_right(0) {
game.rotation_idx = old_rotation_idx
game.get_tetro()
}
if game.pos_x < 0 {
// game.pos_x = 1
}
}
fn (mut game Game) key_down(key gg.KeyCode) {
// global keys
match key {
.escape {
@@ -443,19 +480,7 @@ fn (mut game Game) key_down(key sapp.KeyCode) {
match key {
.up {
// Rotate the tetro
old_rotation_idx := game.rotation_idx
game.rotation_idx++
if game.rotation_idx == tetro_size {
game.rotation_idx = 0
}
game.get_tetro()
if !game.move_right(0) {
game.rotation_idx = old_rotation_idx
game.get_tetro()
}
if game.pos_x < 0 {
// game.pos_x = 1
}
game.rotate_tetro()
}
.left {
game.move_right(-1)
@@ -476,3 +501,18 @@ fn (mut game Game) key_down(key sapp.KeyCode) {
else {}
}
}
fn (mut game Game) touch_event(touch_point C.sapp_touchpoint) {
ws := gg.window_size()
tx := touch_point.pos_x
ty := touch_point.pos_y
if ty < f32(ws.height) * 0.5 {
game.rotate_tetro()
} else {
if tx <= f32(ws.width) * 0.5 {
game.move_right(-1)
} else {
game.move_right(1)
}
}
}

Some files were not shown because too many files have changed in this diff Show More