All Downloads are FREE. Search and download functionalities are using the official Maven repository.

desktopMain.textures.TextureImageSourceBuilder.kt Maven / Gradle / Ivy

/*
 * Copyright 2020-2021 Slawomir Czerwinski
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package graphics.glimpse.textures

import com.jogamp.opengl.GL2ES2
import com.jogamp.opengl.GLProfile
import com.jogamp.opengl.util.texture.TextureData
import com.jogamp.opengl.util.texture.TextureIO
import graphics.glimpse.GlimpseAdapter
import graphics.glimpse.logging.GlimpseLogger
import java.util.*

/**
 * A builder for a [TextureImageSource].
 */
actual class TextureImageSourceBuilder {

    private val logger: GlimpseLogger = GlimpseLogger.create(this)

    private var filename: String = ""
    private var inputStreamProvider: InputStreamProvider = InputStreamProvider { null }

    /**
     * Will build a texture source with a given [filename].
     */
    fun withFilename(filename: String): TextureImageSourceBuilder {
        this.filename = filename
        return this
    }

    /**
     * Will build a texture source from an input stream provided by [inputStreamProvider].
     */
    fun fromInputStream(inputStreamProvider: InputStreamProvider): TextureImageSourceBuilder {
        this.inputStreamProvider = inputStreamProvider
        return this
    }

    /**
     * Builds a [TextureImageSource] with the provided parameters.
     */
    actual fun build(): TextureImageSource {
        check(value = filename.isNotBlank()) {
            "Filename cannot be blank. Must call withFilename()."
        }
        logger.debug(message = "Building image source from: '$filename'")
        return TextureImageSourceImpl(filename, inputStreamProvider)
    }

    /**
     * Builds a prepared [TextureImageSource] with the provided parameters and
     * a given OpenGL [profile].
     *
     * _Note: The resulting [TextureImageSource] will be quicker in setting
     * a texture image, but it will also consume more memory._
     */
    fun buildPrepared(profile: GLProfile): TextureImageSource {
        check(value = filename.isNotBlank()) {
            "Filename cannot be blank. Must call withFilename()."
        }
        logger.debug(message = "Building image source from: '$filename'")
        val inputStream = checkNotNull(inputStreamProvider.createInputStream()) {
            "Texture input stream cannot be null"
        }
        logger.debug(message = "Decoding texture data: '$filename'")
        val fileType = filename.split('.').last().toLowerCase(Locale.ENGLISH)
        val textureData = TextureIO.newTextureData(profile, inputStream, false, fileType)
        logger.debug(message = "Decoded texture data: $textureData")
        return PreparedTextureImageSourceImpl(textureData)
    }

    private abstract class BaseTextureImageSourceImpl : TextureImageSource {

        final override fun glTexImage2D(gl: GlimpseAdapter, withMipmaps: Boolean) {
            glTexImage2D(gl, TextureType.TEXTURE_2D, GL2ES2.GL_TEXTURE_2D, withMipmaps)
        }

        final override fun glTexImage2D(gl: GlimpseAdapter, side: CubemapSide, withMipmaps: Boolean) {
            glTexImage2D(gl, TextureType.TEXTURE_CUBE_MAP, side.toInt(), withMipmaps)
        }

        private fun CubemapSide.toInt(): Int = when (this) {
            CubemapSide.RIGHT -> GL2ES2.GL_TEXTURE_CUBE_MAP_POSITIVE_X
            CubemapSide.LEFT -> GL2ES2.GL_TEXTURE_CUBE_MAP_NEGATIVE_X
            CubemapSide.TOP -> GL2ES2.GL_TEXTURE_CUBE_MAP_POSITIVE_Y
            CubemapSide.BOTTOM -> GL2ES2.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
            CubemapSide.FAR -> GL2ES2.GL_TEXTURE_CUBE_MAP_POSITIVE_Z
            CubemapSide.NEAR -> GL2ES2.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
        }

        protected abstract fun glTexImage2D(
            gl: GlimpseAdapter,
            textureType: TextureType,
            target: Int,
            withMipmaps: Boolean
        )
    }

    private class TextureImageSourceImpl(
        private val filename: String,
        private val inputStreamProvider: InputStreamProvider
    ) : BaseTextureImageSourceImpl() {

        private val logger: GlimpseLogger = GlimpseLogger.create(this)

        override fun glTexImage2D(
            gl: GlimpseAdapter,
            textureType: TextureType,
            target: Int,
            withMipmaps: Boolean
        ) {
            val inputStream = checkNotNull(inputStreamProvider.createInputStream()) {
                "Texture input stream cannot be null"
            }
            logger.debug(message = "Creating texture: '$filename'")
            val fileType = filename.split('.').last().toLowerCase(Locale.ENGLISH)
            val textureData = TextureIO.newTextureData(
                gl.gles.glProfile, inputStream, false, fileType
            )
            logger.debug(message = "Decoded texture data: $textureData")
            gl.gles.glTexImage2D(
                target, 0, textureData.internalFormat,
                textureData.width, textureData.height, 0,
                textureData.pixelFormat, textureData.pixelType, textureData.buffer
            )
            textureData.destroy()
            if (withMipmaps) {
                gl.glGenerateMipmap(textureType)
            }
        }

        override fun dispose() = Unit
    }

    private class PreparedTextureImageSourceImpl(
        private val textureData: TextureData
    ) : BaseTextureImageSourceImpl() {

        override fun glTexImage2D(
            gl: GlimpseAdapter,
            textureType: TextureType,
            target: Int,
            withMipmaps: Boolean
        ) {
            gl.gles.glTexImage2D(
                target, 0, textureData.internalFormat,
                textureData.width, textureData.height, 0,
                textureData.pixelFormat, textureData.pixelType, textureData.buffer
            )
            if (withMipmaps) {
                gl.glGenerateMipmap(textureType)
            }
        }

        override fun dispose() {
            textureData.destroy()
        }
    }

    actual companion object {

        /**
         * Creates a new texture image source builder.
         */
        actual fun getInstance(): TextureImageSourceBuilder = TextureImageSourceBuilder()
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy