From b0a8bb642f919eaa0c36b9d861c47e0cc4a99440 Mon Sep 17 00:00:00 2001
From: davidovski <david@davidovski.xyz>
Date: Mon, 22 Apr 2024 17:32:17 +0100
Subject: use grass

---
 assets/tiles.png      | Bin 1416 -> 4259 bytes
 level.go              |  46 +++++++++++++++++++++-------------------
 main.go               |  57 ++++++++++++++++++++++++++++++++++----------------
 objects.go            |   5 ++++-
 shaders/bloom.kage    |  43 +++++++++++++++++++++++++++++++++++++
 shaders/clouds.kage   |  11 ++++++----
 shaders/none.kage     |   4 ++--
 shaders/vcr_lite.kage |  33 +++++++++++++++++++++++++++++
 8 files changed, 153 insertions(+), 46 deletions(-)
 create mode 100644 shaders/bloom.kage
 create mode 100644 shaders/vcr_lite.kage

diff --git a/assets/tiles.png b/assets/tiles.png
index 5c3ce91..4ee5ff8 100644
Binary files a/assets/tiles.png and b/assets/tiles.png differ
diff --git a/level.go b/level.go
index 3e7ca2a..0f18085 100644
--- a/level.go
+++ b/level.go
@@ -30,6 +30,10 @@ func levelStart(g *Game) {
     }
 }
 
+func StartGame(g *Game) {
+    StartLevel4(g)
+}
+
 func StartLevel1(g *Game ) {
     g.SetInGame()
 
@@ -46,11 +50,11 @@ func StartLevel1(g *Game ) {
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0,
-                0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0,
-                0, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 51, 36, 34, 35, 36, 34, 35, 36, 34, 35, 36, 34, 35, 36, 34, 35, 36, 34, 35, 36, 34, 67, 0,
+                0, 50, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 0,
+                0, 53, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 0,
+                0, 69, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 0,
+                0, 69, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 0,
 			},
 		}, 25)
 
@@ -102,22 +106,22 @@ func StartLevel4(g *Game) {
     g.ClearAll()
     tilemap := NewTilemap([][]int{
             {
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0,
-                0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0,
-                0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0,
-                0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  35, 36, 34, 35, 36, 34, 35, 36, 34, 67, 0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 0,
+                0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 0,
+                0, 0,  51, 36, 34, 35, 36, 34, 35, 36, 34, 35, 36, 34, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 0,
+                0, 50, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 0,
+                0, 53, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 0,
+                0, 69, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39,
 			},
 		}, 25)
 
diff --git a/main.go b/main.go
index a05d2ec..dea148d 100644
--- a/main.go
+++ b/main.go
@@ -43,9 +43,10 @@ var (
 	noneShader_src []byte
 	//go:embed shaders/vcr.kage
 	vcrShader_src []byte
-
 	//go:embed shaders/clouds.kage
 	cloudShader_src []byte
+	//go:embed shaders/bloom.kage
+	bloomShader_src []byte
 
 	//go:embed assets/tiles.png
 	tilesPng_src []byte
@@ -217,7 +218,7 @@ func (g *Game) Init() {
     g.objects = append(g.objects, g.exit)
 
     g.ResetAll()
-    StartLevel1(g)
+    StartGame(g)
     g.audioPlayer.ambientAudio.SetVolume(0)
 
 
@@ -377,24 +378,46 @@ func DrawBackground(screen *ebiten.Image, time int)  {
 	screen.DrawRectShader(screenWidth, screenHeight, shaders["sky"], shop)
 }
 
+func PostProcess(screen *ebiten.Image, shaderName string, time int) {
+    w, h := screen.Bounds().Dx(), screen.Bounds().Dy()
+    for _, shader := range []string{shaderName} {
+        out := ebiten.NewImage(w, h)
+        shop := &ebiten.DrawRectShaderOptions{}
+
+        shop.Uniforms = map[string]any{
+            "Time":   float32(time) / 60,
+            "NoiseOffset":   float32(time) / 60,
+        }
+        shop.Images[0] = screen
+        shop.Images[1] = screen
+        shop.Images[2] = screen
+        shop.Images[3] = screen
+        out.DrawRectShader(w, h, shaders[shader], shop)
+
+        op := &ebiten.DrawImageOptions{}
+        screen.DrawImage(out, op)
+    }
+
+}
+
 func (g *Game) Draw(screen *ebiten.Image) {
 
     g.surface.Fill(color.Alpha16{0x9ccf})
     DrawBackground(g.surface, g.time)
 
     op := &ebiten.DrawImageOptions{}
-    op.GeoM.Translate(float64(g.offsetX), float64(g.offsetY))
+    op.GeoM.Translate(float64(g.offsetX), float64(g.offsetY-2))
 
     g.surface.DrawImage(g.tilemap.surface, op)
 
     for i := len(g.objects)-1; i >= 0; i-- {
         obj := g.objects[i]
-        obj.Draw(g.surface, *g.tilemap)
+        obj.Draw(obj, g.surface, *g.tilemap)
     }
 
     if g.state == PLACING {
         if len(g.toPlace) > 0 {
-            g.toPlace[0].Draw(g.surface, *g.tilemap)
+            g.toPlace[0].Draw(g.toPlace[0], g.surface, *g.tilemap)
         }
     }
 
@@ -409,19 +432,13 @@ func (g *Game) Draw(screen *ebiten.Image) {
         }
     }
 
-	shop := &ebiten.DrawRectShaderOptions{}
-	shop.Uniforms = map[string]any{
-        "Time":   float32(g.time) / 60,
-        "NoiseOffset":   float32(g.time) / 60,
-	}
-	shop.Images[0] = g.surface
-	shop.Images[1] = g.surface
-	shop.Images[2] = g.surface
-	shop.Images[3] = g.surface
-	screen.DrawRectShader(screenWidth, screenHeight, shaders[g.shaderName], shop)
-
-    ebitenutil.DebugPrint(screen, fmt.Sprintf("shader: %s", g.shaderName))
-    //screen.DrawImage(surface, &ebiten.DrawImageOptions{})
+
+    op = &ebiten.DrawImageOptions{}
+    PostProcess(g.surface, g.shaderName, g.time)
+
+    op = &ebiten.DrawImageOptions{}
+    screen.DrawImage(g.surface, &ebiten.DrawImageOptions{})
+    ebitenutil.DebugPrint(screen, fmt.Sprintf("tps: %.4f", ebiten.ActualFPS()))
 }
 
 func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int){
@@ -443,6 +460,10 @@ func LoadShaders() error {
     if err != nil {
         return err
     }
+    shaders["bloom"], err = ebiten.NewShader([]byte(bloomShader_src))
+    if err != nil {
+        return err
+    }
 
     shaders["sky"], err = ebiten.NewShader([]byte(cloudShader_src))
     if err != nil {
diff --git a/objects.go b/objects.go
index d1ccfeb..2d14855 100644
--- a/objects.go
+++ b/objects.go
@@ -40,6 +40,7 @@ type GameObject struct {
     onCollideDown func(this, other *GameObject) bool
     onCollideLeft func(this, other *GameObject) bool
     onCollideRight func(this, other *GameObject) bool
+    Draw func (o * GameObject, screen *ebiten.Image, tilemap Tilemap)
     movable bool
 }
 
@@ -132,7 +133,7 @@ func (o * GameObject) HasCollision(tilemap Tilemap, others []*GameObject, dir Di
     return false
 }
 
-func (o * GameObject) Draw(screen *ebiten.Image, tilemap Tilemap) {
+func DrawObject(o * GameObject, screen *ebiten.Image, tilemap Tilemap) {
     op := &ebiten.DrawImageOptions{}
     op.ColorScale.ScaleAlpha(o.alpha)
     op.GeoM.Translate(float64(o.x), float64(o.y))
@@ -199,6 +200,7 @@ func NewObject(game *Game, x, y float32) *GameObject{
         x: x,
         y: y,
         movable: true,
+        Draw: DrawObject,
     }
 }
 
@@ -208,6 +210,7 @@ func NewPlayer(game *Game, x, y float32) *GameObject{
     playerImage := ebiten.NewImageFromImage(characterImage)
 
     player.image = playerImage.SubImage(image.Rect(4, 8, 27, 32)).(*ebiten.Image)
+    player.Draw = DrawObject
 
     player.movable = false
     return player
diff --git a/shaders/bloom.kage b/shaders/bloom.kage
new file mode 100644
index 0000000..fc987b1
--- /dev/null
+++ b/shaders/bloom.kage
@@ -0,0 +1,43 @@
+//go:build ignore
+//kage:unit pixels
+
+package main
+
+const THRESHOLD = .9
+const DIRECTIONS = 30.0  // BLUR DIRECTIONS (Default 16.0 - More is better but slower)
+const QUALITY = 12.0      // BLUR QUALITY (Default 4.0 - More is better but slower)
+const SIZE = 5.0         // BLUR SIZE (Radius)
+const PI = 6.28318530718 // Pi*2
+const OPACITY = 0.21
+
+
+var Time float
+var NoiseOffset float
+
+func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
+    uv := srcPos
+    
+    average := vec3(0.0)
+    radius := SIZE / 2
+    
+    amount := 0.0
+    for d:=0.0; d<PI; d+=PI/DIRECTIONS{
+		for i:=1.0/QUALITY; i<=1.0; i+=1.0/QUALITY{
+            t := imageSrc0UnsafeAt(uv + vec2(cos(d),sin(d))*radius*log(i)).rgb
+
+            brightness := dot(t.rgb, vec3(0.2126, 0.7152, 0.0722))
+            if brightness > THRESHOLD {
+                average += t
+                amount += 1.0
+            }
+        }
+    } 
+    
+    col :=  imageSrc0UnsafeAt(uv).rgb
+    if amount > 0 {
+        col += (average / amount) * OPACITY
+    }
+    
+    return vec4(col,1.0)
+}
+
diff --git a/shaders/clouds.kage b/shaders/clouds.kage
index 26597e5..62a0ae0 100644
--- a/shaders/clouds.kage
+++ b/shaders/clouds.kage
@@ -13,6 +13,7 @@ const cloudlight = 0.3
 const cloudcover = 0.2
 const cloudalpha = 8.0
 const skytint = 0.5
+const colorDepth = 64
 
 func rand(co vec2) float {
     return fract(sin(dot(co.xy, vec2(12.9898,-78.233))) * 43758.5453)
@@ -59,10 +60,11 @@ func fbm(n vec2) float {
 
 func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
     m := mat2(1.6,  1.2, -1.2,  1.6)
-    skycolour1 := vec3(0.45, 0.57, 0.66)
-    skycolour2 := vec3(0.55, 0.77, 0.86)
+    skycolour := vec3(0.68, 0.81, 0.86)
+    //skycolour2 := vec3(0.55, 0.77, 0.86)
+
+    p := floor(srcPos.xy) / imageSrc0Size().xy;
 
-    p := srcPos.xy / imageSrc0Size().xy;
 	uv := p*vec2(imageSrc0Size().x/imageSrc0Size().y,1.0);    
     time := Time * speed
     q := fbm(uv * cloudscale * 0.5)
@@ -120,12 +122,13 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
 	
     c += c1
 
-    skycolour := mix(skycolour2, skycolour1, p.y);
+    //skycolour := mix(skycolour2, skycolour1, 0);
     cloudcolour := vec3(1.1, 1.1, 0.9) * clamp((clouddark + cloudlight*c), 0.0, 1.0);
    
     f = cloudcover + cloudalpha*f*r;
     
     result := mix(skycolour, clamp(skytint * skycolour + cloudcolour, 0.0, 1.0), clamp(f + c, 0.0, 1.0));
+    result = floor(result*colorDepth)/colorDepth
     
 	return vec4( result, 1.0 );
 }
diff --git a/shaders/none.kage b/shaders/none.kage
index 3eccc50..941070d 100644
--- a/shaders/none.kage
+++ b/shaders/none.kage
@@ -5,8 +5,8 @@
 package main
 
 var Time float
-var Cursor vec2
+var NoiseOffset float
 
 func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
-    return imageSrc2UnsafeAt(srcPos);
+    return imageSrc0UnsafeAt(srcPos)
 }
diff --git a/shaders/vcr_lite.kage b/shaders/vcr_lite.kage
new file mode 100644
index 0000000..405195c
--- /dev/null
+++ b/shaders/vcr_lite.kage
@@ -0,0 +1,33 @@
+//go:build ignore
+
+//kage:unit pixels
+
+package main
+
+var Time float
+var NoiseOffset float
+
+const noiseX = 840.0
+const noiseY = 840.0
+const speed = 0.01
+
+const colorOffsetIntensity = 0.1
+
+func rand(co vec2) float {
+    return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453)
+}
+
+
+func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
+    time := Time * speed
+    uv := srcPos / imageSrc0Size()
+
+    uv.x = uv.x + (rand(vec2(time,srcPos.y)) - 0.5) / (noiseX); 
+    uv.y = uv.y + (rand(vec2(time))-0.5) / (noiseY)
+    offsetR := vec2(0.006 * sin(time), 0.0) * colorOffsetIntensity
+    offsetG := vec2(0.0073 * (cos(time * 0.97)), 0.0) * colorOffsetIntensity
+    r := imageSrc0UnsafeAt((uv+offsetR) * imageSrc0Size()).r
+    g := imageSrc0UnsafeAt((uv+offsetG) * imageSrc0Size()).g
+    b := imageSrc0UnsafeAt(uv * imageSrc0Size()).b
+    return vec4(r, g, b, 1.0)
+}
-- 
cgit v1.2.1