<commit_before>/*
 * Copyright 2019 Poly Forest, LLC
 *
 * 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 com.acornui.gl.core

import com.acornui.Disposable
import com.acornui.di.DKey
import com.acornui.di.Scoped
import com.acornui.di.inject
import com.acornui.graphic.*
import com.acornui.math.*
import com.acornui.reflect.observable
import kotlin.math.ceil
import kotlin.math.floor

/**
 * The gl state contains a [ShaderBatch] and a set of gl state properties. When properties are changed, the batch is
 * flushed.
 *
 */
interface GlState {

	/**
	 * The shader batch, used by gl backend acorn components.
	 */
	var batch: ShaderBatch

	/**
	 * Sets the shader program.  If this is being changed, it should be set before [setCamera].
	 */
	var shader: ShaderProgram?

	val uniforms: Uniforms
		get() = shader?.uniforms ?: EmptyUniforms

	/**
	 * A global override to disable blending. Useful if the shader doesn't support blending.
	 */
	var blendingEnabled: Boolean

	val blendMode: BlendMode

	val premultipliedAlpha: Boolean

	/**
	 * Returns whether scissoring is currently enabled.
	 * @see useScissor
	 */
	var scissorEnabled: Boolean

	/**
	 * To reduce batch flushing from switching back and forth from a texture to a single white pixel, as is the case
	 * in mesh drawings, a texture can declare that its 0,0 pixel is white.
	 * The acorn texture packer will optionally add this white pixel.
	 */
	val whitePixel: TextureRo

	/**
	 * @see Gl20.activeTexture
	 */
	fun activeTexture(value: Int)

	fun getTexture(unit: Int): TextureRo?
	fun setTexture(texture: TextureRo? = null, unit: Int = 0)

	/**
	 * For any unit where this texture is bound, unbind it.
	 */
	fun unsetTexture(texture: TextureRo)

	fun blendMode(blendMode: BlendMode, premultipliedAlpha: Boolean)

	/**
	 * The current scissor rectangle.
	 */
	val scissor: IntRectangleRo

	@Deprecated("use out.set(scissor)", ReplaceWith("out.set(scissor)"))
	fun getScissor(out: IntRectangle): IntRectangle = out.set(scissor)

	/**
	 * @see Gl20.scissor
	 */
	fun setScissor(x: Int, y: Int, width: Int, height: Int)

	/**
	 * The current viewport rectangle, in gl window coordinates.
	 * (0,0 is bottom left, width, height includes dpi scaling)
	 */
	val viewport: IntRectangleRo

	/**
	 * Gets the current viewport in gl window coordinates. (0,0 is bottom left, width, height includes dpi scaling)
	 * This is not to be confused with UiComponent.viewport, which is in canvas coordinates.
	 *
	 * @param out Sets this rectangle to the current viewport.
	 * @return Returns the [out] parameter.
	 */
	@Deprecated("use out.set(viewport)", ReplaceWith("out.set(viewport)"))
	fun getViewport(out: IntRectangle): IntRectangle = out.set(viewport)

	/**
	 * @see Gl20.viewport
	 */
	fun setViewport(x: Int, y: Int, width: Int, height: Int)

	/**
	 * The current framebuffer.
	 */
	val framebuffer: FramebufferInfoRo

	/**
	 * Sets the current framebuffer and some information about it.
	 */
	fun setFramebuffer(framebuffer: GlFramebufferRef?,
					   width: Int,
					   height: Int,
					   scaleX: Float,
					   scaleY: Float)

	companion object : DKey<GlState>
}

val Scoped.uniforms: Uniforms
	get() = inject(GlState).uniforms

/**
 * GlState stores OpenGl state information necessary for knowing whether basic draw calls can be batched.
 *
 * @author nbilyk
 */
class GlStateImpl(
		private val gl: Gl20,
		window: Window
) : GlState, Disposable {

	/**
	 * The default shader for this application.
	 */
	private val defaultShader: ShaderProgram = DefaultShaderProgram(gl)

	private var _activeTexture: Int = -1

	private val _boundTextures: Array<TextureRo?> = Array(Gl20.MAX_COMBINED_TEXTURE_IMAGE_UNITS) { null }

	override var batch: ShaderBatch = ShaderBatchImpl(gl, this, uiVertexAttributes)
		set(value) {
			if (field == value) return
			field.flush()
			field = value
		}

	private val defaultWhitePixel by lazy {
		rgbTexture(gl, this, rgbData(1, 1, hasAlpha = true) { setPixel(0, 0, Color.WHITE) }) {
			filterMin = TextureMinFilter.NEAREST
			filterMag = TextureMagFilter.NEAREST
			refInc()
		}
	}

	private var _whitePixel: TextureRo? = null

	override val whitePixel: TextureRo
		get() = _whitePixel ?: defaultWhitePixel

	override fun activeTexture(value: Int) {
		if (value < 0 || value >= Gl20.MAX_COMBINED_TEXTURE_IMAGE_UNITS) throw IllegalArgumentException("Texture index must be between 0 and ${Gl20.MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1}")
		if (_activeTexture == value) return
		batch.flush()
		_activeTexture = value
		gl.activeTexture(Gl20.TEXTURE0 + value)
	}

	override fun getTexture(unit: Int): TextureRo? {
		return _boundTextures[unit]
	}

	override fun setTexture(texture: TextureRo?, unit: Int) {
		val previous = _boundTextures[unit]
		if (previous == texture && _activeTexture == unit) return
		batch.flush()<commit_msg>Fix active texture MAX_COMBINED_TEXTURE_IMAGE_UNITS check<commit_after>/*
 * Copyright 2019 Poly Forest, LLC
 *
 * 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 com.acornui.gl.core

import com.acornui.Disposable
import com.acornui.di.DKey
import com.acornui.di.Scoped
import com.acornui.di.inject
import com.acornui.graphic.*
import com.acornui.math.*
import com.acornui.reflect.observable
import kotlin.math.ceil
import kotlin.math.floor

/**
 * The gl state contains a [ShaderBatch] and a set of gl state properties. When properties are changed, the batch is
 * flushed.
 *
 */
interface GlState {

	/**
	 * The shader batch, used by gl backend acorn components.
	 */
	var batch: ShaderBatch

	/**
	 * Sets the shader program.  If this is being changed, it should be set before [setCamera].
	 */
	var shader: ShaderProgram?

	val uniforms: Uniforms
		get() = shader?.uniforms ?: EmptyUniforms

	/**
	 * A global override to disable blending. Useful if the shader doesn't support blending.
	 */
	var blendingEnabled: Boolean

	val blendMode: BlendMode

	val premultipliedAlpha: Boolean

	/**
	 * Returns whether scissoring is currently enabled.
	 * @see useScissor
	 */
	var scissorEnabled: Boolean

	/**
	 * To reduce batch flushing from switching back and forth from a texture to a single white pixel, as is the case
	 * in mesh drawings, a texture can declare that its 0,0 pixel is white.
	 * The acorn texture packer will optionally add this white pixel.
	 */
	val whitePixel: TextureRo

	/**
	 * @see Gl20.activeTexture
	 */
	fun activeTexture(value: Int)

	fun getTexture(unit: Int): TextureRo?
	fun setTexture(texture: TextureRo? = null, unit: Int = 0)

	/**
	 * For any unit where this texture is bound, unbind it.
	 */
	fun unsetTexture(texture: TextureRo)

	fun blendMode(blendMode: BlendMode, premultipliedAlpha: Boolean)

	/**
	 * The current scissor rectangle.
	 */
	val scissor: IntRectangleRo

	@Deprecated("use out.set(scissor)", ReplaceWith("out.set(scissor)"))
	fun getScissor(out: IntRectangle): IntRectangle = out.set(scissor)

	/**
	 * @see Gl20.scissor
	 */
	fun setScissor(x: Int, y: Int, width: Int, height: Int)

	/**
	 * The current viewport rectangle, in gl window coordinates.
	 * (0,0 is bottom left, width, height includes dpi scaling)
	 */
	val viewport: IntRectangleRo

	/**
	 * Gets the current viewport in gl window coordinates. (0,0 is bottom left, width, height includes dpi scaling)
	 * This is not to be confused with UiComponent.viewport, which is in canvas coordinates.
	 *
	 * @param out Sets this rectangle to the current viewport.
	 * @return Returns the [out] parameter.
	 */
	@Deprecated("use out.set(viewport)", ReplaceWith("out.set(viewport)"))
	fun getViewport(out: IntRectangle): IntRectangle = out.set(viewport)

	/**
	 * @see Gl20.viewport
	 */
	fun setViewport(x: Int, y: Int, width: Int, height: Int)

	/**
	 * The current framebuffer.
	 */
	val framebuffer: FramebufferInfoRo

	/**
	 * Sets the current framebuffer and some information about it.
	 */
	fun setFramebuffer(framebuffer: GlFramebufferRef?,
					   width: Int,
					   height: Int,
					   scaleX: Float,
					   scaleY: Float)

	companion object : DKey<GlState>
}

val Scoped.uniforms: Uniforms
	get() = inject(GlState).uniforms

/**
 * GlState stores OpenGl state information necessary for knowing whether basic draw calls can be batched.
 *
 * @author nbilyk
 */
class GlStateImpl(
		private val gl: Gl20,
		window: Window
) : GlState, Disposable {

	private val maxTextureImageUnits = gl.getParameteri(Gl20.MAX_COMBINED_TEXTURE_IMAGE_UNITS)

	/**
	 * The default shader for this application.
	 */
	private val defaultShader: ShaderProgram = DefaultShaderProgram(gl)

	private var _activeTexture: Int = -1

	private val _boundTextures: Array<TextureRo?> = Array(Gl20.MAX_COMBINED_TEXTURE_IMAGE_UNITS) { null }

	override var batch: ShaderBatch = ShaderBatchImpl(gl, this, uiVertexAttributes)
		set(value) {
			if (field == value) return
			field.flush()
			field = value
		}

	private val defaultWhitePixel by lazy {
		rgbTexture(gl, this, rgbData(1, 1, hasAlpha = true) { setPixel(0, 0, Color.WHITE) }) {
			filterMin = TextureMinFilter.NEAREST
			filterMag = TextureMagFilter.NEAREST
			refInc()
		}
	}

	private var _whitePixel: TextureRo? = null

	override val whitePixel: TextureRo
		get() = _whitePixel ?: defaultWhitePixel

	override fun activeTexture(value: Int) {
		if (value < 0 || value >= maxTextureImageUnits) throw IllegalArgumentException("Texture index must be between 0 and ${maxTextureImageUnits - 1}")
		if (_activeTexture == value) return
		batch.flush()
		_activeTexture = value
		gl.activeTexture(Gl20.TEXTURE0 + value)
	}

	override fun getTexture(unit: Int): TextureRo? {
		return _boundTextures[unit]
	}

	override fun setTexture(texture: TextureRo?, unit: Int) {
		val previous = _boundTextures[unit]
		if (previous == texture && _activeTexture == unit) return
		batch.flush()
{'fraction_non_alphanumeric': 0.09731886074775026, 'fraction_numerical': 0.007236292791539103, 'mean_word_length': 3.9134001823154057, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '1218248', 'n_tokens_mistral': 3583, 'n_tokens_neox': 3249, 'n_words': 1139}