/*
 * Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */

package net.lax1dude.eaglercraft.v1_8.opengl;

import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL._wglBufferData;
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL._wglCompileShader;
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL._wglCreateShader;
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL._wglDeleteBuffers;
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL._wglGenBuffers;
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL._wglGetShaderInfoLog;
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL._wglGetShaderi;
import static net.lax1dude.eaglercraft.v1_8.internal.PlatformOpenGL._wglShaderSource;
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.GL_ARRAY_BUFFER;
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.GL_COMPILE_STATUS;
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.GL_FLOAT;
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.GL_STATIC_DRAW;
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.GL_TRIANGLES;
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.GL_TRUE;
import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.GL_VERTEX_SHADER;

import java.util.List;

import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.internal.IBufferGL;
import net.lax1dude.eaglercraft.v1_8.internal.IShaderGL;
import net.lax1dude.eaglercraft.v1_8.internal.IVertexArrayGL;
import net.lax1dude.eaglercraft.v1_8.internal.buffer.FloatBuffer;

public class DrawUtils {

	public static final String vertexShaderPath = "/assets/eagler/glsl/local.vsh";
	public static final String vertexShaderPrecision = "precision highp float;\n";

	public static IVertexArrayGL standardQuad2DVAO = null;
	public static IVertexArrayGL standardQuad3DVAO = null;
	public static IBufferGL standardQuadVBO = null;

	public static IShaderGL vshLocal = null;
	public static List<VSHInputLayoutParser.ShaderInput> vshLocalLayout = null;

	public static void destroy() {
		if (standardQuad2DVAO != null) {
			EaglercraftGPU.destroyGLVertexArray(standardQuad2DVAO);
			standardQuad2DVAO = null;
		}
		if (standardQuad3DVAO != null) {
			EaglercraftGPU.destroyGLVertexArray(standardQuad3DVAO);
			standardQuad3DVAO = null;
		}
		if (standardQuadVBO != null) {
			_wglDeleteBuffers(standardQuadVBO);
			standardQuadVBO = null;
		}
		if (vshLocal != null) {
			vshLocal.free();
			vshLocal = null;
			vshLocalLayout = null;
		}
	}

	public static void drawStandardQuad2D() {
		EaglercraftGPU.bindGLVertexArray(standardQuad2DVAO);
		EaglercraftGPU.drawArrays(GL_TRIANGLES, 0, 6);
	}

	public static void drawStandardQuad3D() {
		EaglercraftGPU.bindGLVertexArray(standardQuad3DVAO);
		EaglercraftGPU.drawArrays(GL_TRIANGLES, 0, 6);
	}

	static void init() {
		if (standardQuad2DVAO == null) {
			standardQuad2DVAO = EaglercraftGPU.createGLVertexArray();
			standardQuad3DVAO = EaglercraftGPU.createGLVertexArray();
			standardQuadVBO = _wglGenBuffers();

			FloatBuffer verts = EagRuntime.allocateFloatBuffer(18);
			verts.put(new float[] { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f,
					1.0f, 0.0f, -1.0f, 1.0f, 0.0f });
			verts.flip();

			EaglercraftGPU.bindVAOGLArrayBufferNow(standardQuadVBO);
			_wglBufferData(GL_ARRAY_BUFFER, verts, GL_STATIC_DRAW);
			EagRuntime.freeFloatBuffer(verts);

			EaglercraftGPU.bindGLVertexArray(standardQuad2DVAO);

			EaglercraftGPU.enableVertexAttribArray(0);
			EaglercraftGPU.vertexAttribPointer(0, 2, GL_FLOAT, false, 12, 0);

			EaglercraftGPU.bindGLVertexArray(standardQuad3DVAO);

			EaglercraftGPU.enableVertexAttribArray(0);
			EaglercraftGPU.vertexAttribPointer(0, 3, GL_FLOAT, false, 12, 0);
		}

		if (vshLocal == null) {
			String vertexSource = EagRuntime.getRequiredResourceString(vertexShaderPath);

			vshLocalLayout = VSHInputLayoutParser.getShaderInputs(vertexSource);

			vshLocal = _wglCreateShader(GL_VERTEX_SHADER);

			_wglShaderSource(vshLocal, GLSLHeader.getVertexHeaderCompat(vertexSource, vertexShaderPrecision));
			_wglCompileShader(vshLocal);

			if (_wglGetShaderi(vshLocal, GL_COMPILE_STATUS) != GL_TRUE) {
				EaglercraftGPU.logger.error("Failed to compile GL_VERTEX_SHADER \"" + vertexShaderPath + "\"!");
				String log = _wglGetShaderInfoLog(vshLocal);
				if (log != null) {
					String[] lines = log.split("(\\r\\n|\\r|\\n)");
					for (int i = 0; i < lines.length; ++i) {
						EaglercraftGPU.logger.error("[VERT] {}", lines[i]);
					}
				}
				throw new IllegalStateException("Vertex shader \"" + vertexShaderPath + "\" could not be compiled!");
			}
		}
	}

}