nandi/vflutter_ffipublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/nandi/vflutter_ffi.git
git clone ssh://git@rickub.com/nandi/vflutter_ffi.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

nimflutter.nim · 113 lines · 3.9 KBNim Blame HistoryRaw
Replace V with Nim 472eb49 nandithebull 8h ago1## C-ABI surface consumed by Dart FFI.
2##
3## Rules for everything below:
4## * only C-compatible types cross the boundary (cint, cdouble, cstring,
5## pointer) — never a Nim string, seq, ref or object
6## * anything Nim allocates and hands out is released by nf_free
7## * allocations that cross the boundary use the *shared* heap, because Dart
8## calls in from many isolates and each one is its own OS thread
9
10import std/math
11
12var initialized {.global.} = false
13
14proc NimMain() {.importc.}
15
16proc nf_init() {.exportc: "nf_init", dynlib, cdecl.} =
17 ## Initialises the Nim runtime. Idempotent and cheap.
18 ##
19 ## Shared builds run NimMain from a library constructor on ELF/Mach-O, but
20 ## static archives (iOS) have no such hook, so the caller needs a guaranteed
21 ## entry point.
22 if not initialized:
23 NimMain()
24 initialized = true
25
26proc nf_add(a, b: cint): cint {.exportc: "nf_add", dynlib, cdecl.} =
27 a + b
28
29proc nf_greet(name: cstring): cstring {.exportc: "nf_greet", dynlib, cdecl.} =
30 ## Returns a shared-heap C string. Caller releases it with nf_free.
31 let greeting = "Hello, " & $name & ", from Nim!"
32 # allocShared0, not alloc0: the Dart side may free this from a different
33 # isolate than the one that allocated it, and Nim's default heap is
34 # thread-local.
35 let buf = cast[cstring](allocShared0(greeting.len + 1))
36 copyMem(buf, greeting.cstring, greeting.len)
37 buf
38
39proc nf_free(p: pointer) {.exportc: "nf_free", dynlib, cdecl.} =
40 if p != nil:
41 deallocShared(p)
42
43proc nf_mandelbrot(buf: ptr UncheckedArray[uint8], bufLen: csize_t,
44 w, h: cint, cx, cy, scale: cdouble, maxIter, y0, y1: cint)
45 {.exportc: "nf_mandelbrot", dynlib, cdecl.} =
46 ## Fills rows [y0, y1) of a w x h image as RGBA8888, packed from the start
47 ## of `buf`.
48 ##
49 ## The buffer belongs to the *caller*: nothing is allocated here, so there is
50 ## nothing to nf_free, and each call touches only its own rows — which is
51 ## what makes concurrent calls from several isolates safe.
52 ##
53 ## `bufLen` is the caller's own statement of how many bytes `buf` holds, and
54 ## every rejection below is all-or-nothing: a short buffer writes *nothing*
55 ## rather than filling what fits. Partial output would be indistinguishable
56 ## from a rendered frame.
57 if buf == nil or w <= 0 or h <= 0 or maxIter <= 0 or y0 < 0 or y1 <= y0:
58 return
59
60 # Widen before multiplying. The required size is computed in 64-bit because
61 # (y1 - y0) * w * 4 overflows int32 for perfectly ordinary-looking geometry
62 # — w = 2^30 wraps to exactly 0, which a length check alone would accept.
63 let needed = (y1 - y0).int64 * w.int64 * 4'i64
64 if needed <= 0 or needed > bufLen.int64:
65 return
66
67 let
68 aspect = w.float64 / h.float64
69 invW = 1.0 / w.float64
70 invH = 1.0 / h.float64
71
72 for y in y0 ..< y1:
73 let
74 im = cy + (y.float64 * invH - 0.5) * scale
75 row = (y - y0) * w * 4
76 for x in 0 ..< w:
77 let re = cx + (x.float64 * invW - 0.5) * scale * aspect
78
79 var
80 zr = 0.0
81 zi = 0.0
82 zr2 = 0.0
83 zi2 = 0.0
84 i: cint = 0
85 while i < maxIter:
86 zr2 = zr * zr
87 zi2 = zi * zi
88 if zr2 + zi2 > 4.0:
89 break
90 zi = 2.0 * zr * zi + im
91 zr = zr2 - zi2 + re
92 inc i
93
94 let idx = row + x * 4
95 if i >= maxIter:
96 # Inside the set.
97 buf[idx] = 0'u8
98 buf[idx + 1] = 0'u8
99 buf[idx + 2] = 0'u8
100 buf[idx + 3] = 255'u8
101 continue
102
103 # Smooth (fractional) escape count, so bands don't posterise.
104 let mag = sqrt(zr2 + zi2)
105 var nu = i.float64
106 if mag > 1.0:
107 nu = i.float64 + 1.0 - ln(ln(mag) / ln(2.0)) / ln(2.0)
108 let t = nu / maxIter.float64
109
110 buf[idx] = uint8(255.0 * (0.5 + 0.5 * sin(3.0 + t * 18.0)))
111 buf[idx + 1] = uint8(255.0 * (0.5 + 0.5 * sin(3.6 + t * 18.0)))
112 buf[idx + 2] = uint8(255.0 * (0.5 + 0.5 * sin(4.2 + t * 18.0)))
113 buf[idx + 3] = 255'u8