package main


import "core:log"
import "core:math"
import "core:math/linalg"
import "core:math/rand"
import rl "vendor:raylib"


Buddy :: struct {
	pos:       [3]f32,
	gothit:    bool,
	hit_timer: f32,
}


Light :: struct {
	enabled:         i32,
	distanceNear:    f32,
	distanceFar:     f32,
	power:           f32,
	position:        [3]f32,
	color:           [4]f32,
	enabledLoc:      i32,
	distanceNearLoc: i32,
	distanceFarLoc:  i32,
	powerLoc:        i32,
	positionLoc:     i32,
	colorLoc:        i32,
}

MAX_LIGHTS :: 12

lights := [MAX_LIGHTS]Light{}

main :: proc() {
	rl.SetConfigFlags({.WINDOW_RESIZABLE, .MSAA_4X_HINT})
	rl.InitWindow(900, 600, "flash")

	checker := rl.GenImageChecked(128, 128, 32, 32, {128, 128, 128, 255}, {150, 150, 150, 255})
	defer rl.UnloadImage(checker)
	checktex := rl.LoadTextureFromImage(checker)
	defer rl.UnloadTexture(checktex)
	checkmtl := rl.LoadMaterialDefault()
	rl.SetMaterialTexture(&checkmtl, .ALBEDO, checktex)
	checkplane := rl.GenMeshPlane(30, 30, 1, 1)
	rl.GenMeshTangents(&checkplane)


	w, h := rl.GetScreenWidth(), rl.GetScreenHeight()
	pixelize: i32 = 2
	target := rl.LoadRenderTexture(w / pixelize, h / pixelize)

	palette := rl.LoadTexture("assets/gfx/blood-crow-1x.png")
	rl.SetTextureFilter(palette, .POINT)


	texture := rl.LoadTexture("assets/gfx/buddy.png")
	defer rl.UnloadTexture(texture)


	buddies := [dynamic]Buddy{}
	defer delete(buddies)
	for i := 0; i < 1000; i += 1 {
		buddy := Buddy {
			pos       = {rand.float32_range(-10, 10), 1, rand.float32_range(-10, 10)},
			gothit    = false,
			hit_timer = rand.float32_range(1, 15),
		}
		append(&buddies, buddy)
	}

	shader := rl.LoadShaderFromMemory(vshader, fshader)
	posterizer := rl.LoadShaderFromMemory(nil, postprocess)
	poster_palette := rl.GetShaderLocation(posterizer, "texture1")
	checkmtl.shader = shader

	for &light, i in lights {
		light.enabled = 1
		color := rl.ColorFromHSV(f32(i) / f32(MAX_LIGHTS) * 360, 1, 1)
		light.color = [4]f32 {
			f32(color.r) / 255,
			f32(color.g) / 255,
			f32(color.b) / 255,
			f32(color.a) / 255,
		}
		light.position = {rand.float32_range(-20, 20), 3, rand.float32_range(-20, 20)}
		light.power = rand.float32_range(0.9, 1.5)
		light.distanceFar = rand.float32_range(7, 11)

		light.enabledLoc = rl.GetShaderLocation(shader, rl.TextFormat("lights[%i].enabled", i))
		light.distanceNearLoc = rl.GetShaderLocation(
			shader,
			rl.TextFormat("lights[%i].distanceNear", i),
		)
		light.distanceFarLoc = rl.GetShaderLocation(
			shader,
			rl.TextFormat("lights[%i].distanceFar", i),
		)
		light.powerLoc = rl.GetShaderLocation(shader, rl.TextFormat("lights[%i].power", i))
		light.positionLoc = rl.GetShaderLocation(shader, rl.TextFormat("lights[%i].position", i))
		light.colorLoc = rl.GetShaderLocation(shader, rl.TextFormat("lights[%i].color", i))

		rl.SetShaderValue(shader, light.enabledLoc, &(light.enabled), .INT)
		rl.SetShaderValue(shader, light.distanceNearLoc, &(light.distanceNear), .FLOAT)
		rl.SetShaderValue(shader, light.distanceFarLoc, &(light.distanceFar), .FLOAT)
		rl.SetShaderValue(shader, light.powerLoc, &(light.power), .FLOAT)
		rl.SetShaderValue(shader, light.enabledLoc, &(light.enabled), .INT)
		rl.SetShaderValue(shader, light.enabledLoc, &(light.enabled), .INT)
		rl.SetShaderValue(shader, light.positionLoc, &(light.position), .VEC3)
		rl.SetShaderValue(shader, light.colorLoc, &(light.color), .VEC4)

	}


	cam := rl.Camera3D {
		position   = {20, 20, 20},
		target     = {0, 0, 0},
		up         = {0, 1, 0},
		fovy       = 25,
		projection = .PERSPECTIVE,
	}


	log.info("Buddies: ", len(buddies))
	rotation: f32 = 0.0

	for !rl.WindowShouldClose() {
		if rl.IsWindowResized() {
			w, h = rl.GetScreenWidth(), rl.GetScreenHeight()
			rl.UnloadRenderTexture(target)
			target = rl.LoadRenderTexture(w / pixelize, h / pixelize)
		}
		delta := rl.GetFrameTime()
		rotation += delta
		rl.BeginTextureMode(target)
		rl.ClearBackground(rl.BLACK)
		rl.BeginMode3D(cam)
		// rl.DrawPlane({0, 0, 0}, {30, 30}, rl.WHITE)
		for &light, i in lights {
			color: [4]u8 = {
				u8(light.color.r * 255),
				u8(light.color.g * 255),
				u8(light.color.b * 255),
				u8(light.color.a * 255),
			}
			light.position.xz = [2]f32 {
				math.cos_f32(rotation + (f32(i) / f32(MAX_LIGHTS)) * math.PI * 2) * 8,
				math.sin_f32(rotation + (f32(i) / f32(MAX_LIGHTS)) * math.PI * 2) * 8,
			}
			rl.SetShaderValue(shader, light.positionLoc, &(light.position), .VEC3)
			rl.DrawSphere(light.position, 1, transmute(rl.Color)color)
			// rl.DrawModel(sponza, {}, 1, rl.WHITE)
		}
		rl.BeginShaderMode(shader)
		rl.DrawMesh(checkplane, checkmtl, rl.Matrix(1))

		// rl.DrawPlane({}, 100, rl.GREEN)
		for &buddy in buddies {
			buddy.hit_timer -= delta
			if buddy.hit_timer < 0.2 {
				buddy.gothit = true
				if buddy.hit_timer < 0 {
					buddy.gothit = false
					buddy.hit_timer = rand.float32_range(1, 5)
				}
			}
			color := rl.WHITE
			if buddy.gothit do color = rl.RED
			rl.DrawBillboard(cam, texture, buddy.pos, 1, color)
		}

		// for &buddy in buddies {
		// 	color := rl.WHITE
		// 	if buddy.gothit do color = rl.RED
		// 	rl.DrawCubeV(buddy.pos, {0.3, 0.5, 0.3}, color)
		// }

		rl.EndShaderMode()
		rl.EndMode3D()
		rl.EndTextureMode()
		rl.BeginDrawing()
		rl.BeginShaderMode(posterizer)
		rl.SetShaderValueTexture(posterizer, poster_palette, palette)
		rl.DrawTexturePro(
			target.texture,
			rl.Rectangle{0, f32(h / pixelize), f32(w / pixelize), -f32(h / pixelize)},
			{0, 0, f32(w), f32(h)},
			{},
			0,
			rl.WHITE,
		)
		rl.EndShaderMode()
		rl.DrawTexture(palette, 0, 0, rl.WHITE)
		rl.EndDrawing()
	}
}


vshader: cstring = #load("../assets/shaders/vshader.glsl", cstring)
fshader: cstring = #load("../assets/shaders/fshader.glsl", cstring)
postprocess: cstring = #load("../assets/shaders/postprocess.glsl", cstring)

