/* EXTRA CREDITS (bottom of README.md on github) * https://bitwise.handmade.network/ - series by Per Vognsen where he actually creates a C like language, very helpful, very hands on! * https://hero.handmade.network/episode/code/day206/ - this episode of handmade hero started me on the entire compiler journey a long, long time ago. * https://www.youtube.com/watch?v=TH9VCN6UkyQ&list=PLmV5I2fxaiCKfxMBrNsU1kgKJXD3PkyxO - I have rewatched this playlist many this, searching for keywords and ideas. Jonathan Blow's compiler was a big inspiration of mine when learning programming languages. * A Retargetable C Compiler: Design and Implementation by Christopher W. Fraser and David R. Hanson - sometimes looked at this as a reference to figure stuff out. Very helpful resource on compiler construction, the way it's written reads more like documentation but you use what you have. * https://github.com/JoshuaManton/sif - looked at this as a reference from time to time, author seems like a Jonathan Blow fan so it was a good resource informed by similar resources as I used. * https://github.com/c3lang/c3c - I sometimes looked at C3 compiler as a reference, the author also let me use his big int library he wrote sometime in the past! Thanks a lot! * https://go.dev/blog/constants - article on golang type system, untyped types, constants that kind of stuff. * https://github.com/gingerbill/odin - I sometimes peeked at the compiler to figure stuff out when I was confused about stuff. Also we get a free code indexing and syntax highlighting using odin sublime text plugin ! :D */ // // #1 // // * Inspired by: Per Vognsen(Ion), Jonathan Blow(Jai) // * Standard programming constructs // * No forward declarations needed // * Named function arguments // * Enum values are nicely namespaced #import "Multimedia.core" main :: (): int StartMultimedia(title = "Hello people!") DrawYellowFill() DrawCoolGradient() DrawCircleWithGradient() AnimateTransmorphingCircle() RaymarchSphere() DrawYellowFill :: () for y := 0, y < Mu.window.y, y+=1 for x := 0, x < Mu.window.x, x+=1 Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00 for UpdateMultimedia() if Mu.key[Key.Escape].down Mu.key[Key.Escape].down = false break // // #2 // // * Modules // * User names the imports // * Aliasing // * Operator overloads F :: #import "MathF32.core" V3 :: #import "MathVec3.core" V2 :: #import "MathVec2.core" Vec3 :: V3.Vec3 DrawCoolGradient :: () for y := 0, y < Mu.window.y, y+=1 for x := 0, x < Mu.window.x, x+=1 // Normalize to range {0, 1} uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef // Move to range {-1, 1} uv = uv*2->F32 - 1->F32 Assert(uv.x >= -1 && uv.x <= 1) Assert(uv.y >= -1 && uv.y <= 1) color := Vec3{uv.x, uv.y, 1} Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color) for UpdateMultimedia() if Mu.key[Key.Escape].down Mu.key[Key.Escape].down = false break // // #3 // // * The ';;' operator // * The ';' operator // * Compound expressions, named parameters! DrawCircleWithGradient :: () default_color := V3.ConvertToARGB({x = 1, y = 1, z = 1}) ratio := Mu.window.sizef.x / Mu.window.sizef.y for y := 0, y < Mu.window.y, y+=1 for x := 0, x < Mu.window.x, x+=1 // Normalize to range {0, 1} uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef // Move to range {-1, 1} uv = uv*2->F32 - 1->F32 uv.x *= ratio if uv.x*uv.x + uv.y*uv.y < 0.5 color := Vec3{uv.x, uv.y, 1} Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color) else;; Mu.screen[x + y*Mu.window.x] = default_color for UpdateMultimedia() if Mu.key[Key.Escape].down Mu.key[Key.Escape].down = false break // // #4 // AnimateTransmorphingCircle :: () for UpdateMultimedia() if Mu.key[Key.Escape].down Mu.key[Key.Escape].down = false break default_color := V3.ConvertToARGB({x = 1, y = 1, z = 1}) ratio := Mu.window.sizef.x / Mu.window.sizef.y for y := 0, y < Mu.window.y, y+=1 for x := 0, x < Mu.window.x, x+=1 // Normalize to range {0, 1} uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef // Move to range {-1, 1} uv = uv*2->F32 - 1->F32 uv.x *= ratio if F.Cos(Mu.time.total->F32)*uv.x*uv.x + F.Sin(Mu.time.total->F32)*uv.y*uv.y < 0.5 color := Vec3{uv.x, uv.y, 1} Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color) else ;; Mu.screen[x + y*Mu.window.x] = default_color // // #5 // Epsilon :: 0.00001 SphereSDF :: (pos: Vec3): F32 result := V3.Length(pos) - 1.0 return result RaymarchSphere :: () for UpdateMultimedia() if Mu.key[Key.Escape].down Mu.key[Key.Escape].down = false break up := Vec3{0, 1, 0} forward := Vec3{0, 0, -1} side := V3.Normalize(V3.Cross(forward, up)) LightPos := Vec3{2,4,2} LightPos.x = F.Cos(Mu.time.total->F32)*4 LightPos.y = F.Sin(Mu.time.total->F32)*4 ambient_color := Vec3{0.2,0.2,0.2} diffuse_color := Vec3{0.7,0.2,0.2} eye := Vec3{0, 0, 2} light_intensity :: 1.2->F32 Xf := 1 / Mu.window.sizef.x Yf := 1 / Mu.window.sizef.y ratio := Mu.window.sizef.x / Mu.window.sizef.y for y := 0, y < Mu.window.y, y+=1 for x := 0, x < Mu.window.x, x+=1 uv := Vec3{x->F32 * Xf * 2 - 1, y->F32 * Yf * 2 - 1, 1.0} uv.x *= ratio dir := V3.Normalize(Vec3{V3.Dot(side, uv), V3.Dot(up, uv), V3.Dot(forward, uv)}) t: F32 end: F32 = 100.0 hit := true p: Vec3 for i := 0, i < 255, i+=1 p = eye + dir*t distance := SphereSDF(p) if distance < Epsilon break t += distance if distance >= end hit = false break if hit normal := V3.Normalize(Vec3{ SphereSDF({p.x + Epsilon, p.y, p.z}) - SphereSDF({p.x - Epsilon, p.y, p.z}), SphereSDF({p.x, p.y + Epsilon, p.z}) - SphereSDF({p.x, p.y - Epsilon, p.z}), SphereSDF({p.x, p.y, p.z + Epsilon}) - SphereSDF({p.x, p.y, p.z - Epsilon}), }) light_to_point := V3.Normalize(LightPos - p) ambient :: 0.2->F32 diffuse := V3.Dot(normal, light_to_point) color := ambient_color*ambient->F32 if diffuse > Epsilon color = color + diffuse_color*diffuse color = color * light_intensity // Gamma correction color.x = F.SquareRoot(color.x) color.y = F.SquareRoot(color.y) color.z = F.SquareRoot(color.z) Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color) else;; Mu.screen[x + y*Mu.window.x] = 0