package me.eater.threedom.gl.texture

import me.eater.threedom.gl.GL.stack
import org.lwjgl.opengl.GL30.*
import org.lwjgl.stb.STBImage.stbi_load_from_memory
import org.lwjgl.stb.STBImage.stbi_set_flip_vertically_on_load
import org.lwjgl.system.MemoryUtil
import java.lang.ref.WeakReference
import java.nio.ByteBuffer

class Texture {
    var id: Int = run {
        val pTexture = stack.mallocInt(1)
        glGenTextures(pTexture)
        pTexture.get(0).also {
            textures[it] = WeakReference(this)
        }
    }

    fun load(image: ByteArray, flipped: Boolean = true, mipmapLevel: Int = 0) {
        val mem = MemoryUtil.memAlloc(image.size)
        mem.put(image)
        mem.rewind()
        load(mem, flipped, mipmapLevel)
        MemoryUtil.memFree(mem)
    }

    fun load(image: ByteBuffer, flipped: Boolean = true, mipmapLevel: Int = 0) {
        stbi_set_flip_vertically_on_load(flipped)
        val pWidth = stack.mallocInt(1)
        val pHeight = stack.mallocInt(1)
        val pChannels = stack.mallocInt(1)
        val imagePixelData = stbi_load_from_memory(image, pWidth, pHeight, pChannels, 4)
        glBindTexture(GL_TEXTURE_2D, id)
        glTexImage2D(
            GL_TEXTURE_2D,
            mipmapLevel,
            GL_RGBA8,
            pWidth.get(0),
            pHeight.get(0),
            0,
            GL_RGBA,
            GL_UNSIGNED_BYTE,
            imagePixelData
        )
        glGenerateMipmap(GL_TEXTURE_2D)
        glBindTexture(GL_TEXTURE_2D, 0)
    }

    companion object {
        private val textures = mutableMapOf<Int, WeakReference<Texture>>()

        fun getTexture(id: Int): Texture? = textures[id]?.get()
    }
}
