<commit_before>﻿namespace Foom.Renderer

open System
open System.Drawing
open System.Numerics
open System.Collections.Generic
open System.IO

open Foom.Collections

// *****************************************
// *****************************************
// Shader
// *****************************************
// *****************************************

type Shader<'Input, 'Output> = Shader of 'Input * 'Output * ShaderProgram

type Pipeline<'a> = private Pipeline of (unit -> 'a)

type PipelineBuilder () =

    member this.Bind (Pipeline x : Pipeline<'a>, f: 'a -> Pipeline<'b>) : Pipeline<'b> = 
        f (x ())

    member this.Delay (f: unit -> Pipeline<'a>) : Pipeline<'a> = 
        Pipeline (fun _ -> match f () with | Pipeline x -> x ())

    member this.Return (x: 'a) : Pipeline<'a> =
        Pipeline (fun _ -> x)

    member this.Zero () : Pipeline<unit> =
        Pipeline (fun _ -> ())

type Shader<'Input, 'Output> with

    member this.Run f =
        match this with
        | Shader (input, output, program) ->

            Pipeline (
                fun () ->
                    f input
                    program.Draw ()
                    output
            )

module Pipeline =

    let pipeline = PipelineBuilder ()

open Pipeline

// *****************************************
// *****************************************
// Texture
// *****************************************
// *****************************************

type Texture =
    {
        Buffer: Texture2DBuffer
    }

// *****************************************
// *****************************************
// Cache
// *****************************************
// *****************************************

type ShaderCache () =
    let cache = Dictionary<string, ShaderProgram> ()

    member this.GetOrCreateShader (name: string) =
        let name = name.ToUpper()

        match cache.TryGetValue (name) with
        | true, shader -> shader
        | _ ->
            let shaderProgram = ShaderProgram.Load (name)

            cache.[name] <- shaderProgram

            shaderProgram

    member this.Remove (shader) =
        cache.Remove (shader.name)

type TextureCache () =
    let cache = Dictionary<string, Texture> ()

    member this.GetOrCreateTexture (fileName: string) =
        let fileName = fileName.ToUpper ()

        match cache.TryGetValue (fileName) with
        | true, texture -> texture
        | _ ->
            let bmp = new Bitmap(fileName)

            let buffer = Texture2DBuffer ([||], 0, 0)

            // TODO: we should extract the bmp logic from Texture2DBuffer and put it here.
            buffer.Set bmp

            buffer.TryBufferData () |> ignore

            {
                Buffer = buffer
            }

// *****************************************
// *****************************************
// Mesh
// *****************************************
// *****************************************

[<Sealed>]
type Mesh (position, uv, color) =

    member val Position = Buffer.createVector3 position
<commit_msg>Trying to create the fullscreen/final shader in the pipeline<commit_after>﻿namespace Foom.Renderer

open System
open System.Drawing
open System.Numerics
open System.Collections.Generic
open System.IO

open Foom.Collections

// *****************************************
// *****************************************
// Texture
// *****************************************
// *****************************************

type Texture =
    {
        Buffer: Texture2DBuffer
    }

// *****************************************
// *****************************************
// Cache
// *****************************************
// *****************************************

type ShaderProgramCache () =
    let cache = Dictionary<string, ShaderProgram> ()

    member this.GetOrCreateShader (name: string) =
        let name = name.ToUpper()

        match cache.TryGetValue (name) with
        | true, shader -> shader
        | _ ->
            let shaderProgram = ShaderProgram.Load (name)

            cache.[name] <- shaderProgram

            shaderProgram

    member this.Remove (shader) =
        cache.Remove (shader.name)

type TextureCache () =
    let cache = Dictionary<string, Texture> ()

    member this.GetOrCreateTexture (fileName: string) =
        let fileName = fileName.ToUpper ()

        match cache.TryGetValue (fileName) with
        | true, texture -> texture
        | _ ->
            let bmp = new Bitmap(fileName)

            let buffer = Texture2DBuffer ([||], 0, 0)

            // TODO: we should extract the bmp logic from Texture2DBuffer and put it here.
            buffer.Set bmp

            buffer.TryBufferData () |> ignore

            {
                Buffer = buffer
            }

// *****************************************
// *****************************************
// Shader
// *****************************************
// *****************************************

type Shader<'Input, 'Output> = Shader of 'Input * 'Output * ShaderProgram

[<Sealed>]
type PipelineContext (shaderProgramCache: ShaderProgramCache) =
    
    let releases = ResizeArray<unit -> unit> ()
    let actions = ResizeArray<unit -> unit> ()

    member this.AddRelease release =
        releases.Add release

    member this.AddAction action =
        actions.Add action

type Pipeline<'a> = private Pipeline of (PipelineContext -> 'a)

type PipelineBuilder () =

    member this.Bind (Pipeline x : Pipeline<'a>, f: 'a -> Pipeline<'b>) : Pipeline<'b> = 
        Pipeline (
            fun context ->
                match f (x context) with
                | Pipeline g -> g context
        )

    member this.Delay (f: unit -> Pipeline<'a>) : Pipeline<'a> = 
        Pipeline (fun context -> match f () with | Pipeline x -> x context)

    member this.Return (x: 'a) : Pipeline<'a> =
        Pipeline (fun _ -> x)

    member this.Zero () : Pipeline<unit> =
        Pipeline (fun _ -> ())

type Shader<'Input, 'Output> with

    member this.Run f =
        match this with
        | Shader (input, output, program) ->

            Pipeline (
                fun _ ->
                    f input program.Draw
                    output
            )

module Pipeline =

    let pipeline = PipelineBuilder ()

    let run context p =
        match p with
        | Pipeline f -> f context

    let clear =
        Pipeline (
            fun _ ->
                Backend.clear ()
        )

    let captureFrame p =
        let renderTexture (context: PipelineContext) =
            lazy
                let renderTexture = RenderTexture (1280, 720)
                context.AddRelease renderTexture.Release
                renderTexture

        Pipeline (
            fun context ->
                let renderTexture = (renderTexture context).Force()
                
                match p with
                | Pipeline f -> f context

                renderTexture
        )

open Pipeline

// *****************************************
// *****************************************
// Final Output Program
// *****************************************
// *****************************************

module Final =

    [<Sealed>]
    type FinalInput (shaderProgram: ShaderProgram) =

        member val Time = shaderProgram.CreateUniformFloat ("time")

        member val RenderTexture = shaderProgram.CreateUniformRenderTexture ("uni_texture")

        member val Position = shaderProgram.CreateVertexAttributeVector3 ("position")

    let finalPipeline worldPipeline (getTime: unit -> float32) (getPosition: unit -> Vector3Buffer) =
        pipeline {
            let finalShader = Unchecked.defaultof<Shader<FinalInput, unit>>

            let! renderTexture = captureFrame worldPipeline

            do! finalShader.Run (fun input draw ->
                input.Time.Set (getTime ())
                input.Position.Set (getPosition ())
                input.RenderTexture.Set renderTexture

                draw ()
            )
        }

// *****************************************
// *****************************************
// Mesh
// *****************************************
// *****************************************

[<Sealed>]
type Mesh (position, uv, color) =

    member val Position = Buffer.createVector3 position

{'fraction_non_alphanumeric': 0.2645572666025024, 'fraction_numerical': 0.0027670837343599613, 'mean_word_length': 2.3944467129440588, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 74, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6620109', 'n_tokens_mistral': 2150, 'n_tokens_neox': 2027, 'n_words': 535}