// egl_base_context.h
/*
 * FRT - A Godot platform targeting single board computers
 * Copyright (c) 2017-2019  Emanuele Fornara
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "dl/egl.gen.h"

namespace frt {

class EGLBaseContext {
private:
	void build_attr_list(EGLint *attr_list) {
		App *app = App::instance();
		int n = 0;
		const int color_size = app->get_int_param("color_size");
		attr_list[n++] = EGL_RED_SIZE;
		attr_list[n++] = color_size;
		attr_list[n++] = EGL_GREEN_SIZE;
		attr_list[n++] = color_size;
		attr_list[n++] = EGL_BLUE_SIZE;
		attr_list[n++] = color_size;
		const int alpha_size = app->get_int_param("alpha_size");
		attr_list[n++] = EGL_ALPHA_SIZE;
		attr_list[n++] = alpha_size >= 0 ? alpha_size : EGL_DONT_CARE;
		const int depth_size = app->get_int_param("depth_size");
		attr_list[n++] = EGL_DEPTH_SIZE;
		attr_list[n++] = depth_size >= 0 ? depth_size : EGL_DONT_CARE;
		if (app->get_bool_param("multisample")) {
			attr_list[n++] = EGL_SAMPLE_BUFFERS;
			attr_list[n++] = 1;
		}
		attr_list[n++] = EGL_SURFACE_TYPE;
		attr_list[n++] = EGL_WINDOW_BIT;
		attr_list[n++] = EGL_NONE;
	}

protected:
	EGLDisplay display;
	EGLContext context;
	EGLSurface surface;
	EGLConfig config;

public:
	void init(int version, EGLNativeDisplayType display_id = EGL_DEFAULT_DISPLAY) {
		static EGLint attr_list[32];
		static const EGLint ctx_attrs[] = {
			EGL_CONTEXT_CLIENT_VERSION, version,
			EGL_NONE
		};
		EGLBoolean result;
		EGLint num_config;
		display = eglGetDisplay(display_id);
		if (display == EGL_NO_DISPLAY)
			fatal("eglGetDisplay failed.");
		result = eglInitialize(display, 0, 0);
		if (result == EGL_FALSE)
			fatal("eglInitialize failed.");
		build_attr_list(attr_list);
		result = eglChooseConfig(display, attr_list, &config, 1, &num_config);
		if (result == EGL_FALSE)
			fatal("eglChooseConfig failed.");
		result = eglBindAPI(EGL_OPENGL_ES_API);
		if (result == EGL_FALSE)
			fatal("eglBindAPI failed.");
		context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attrs);
		if (context == EGL_NO_CONTEXT)
			fatal("eglCreateContext failed.");
	};
	void create_simple_surface(EGLNativeWindowType window_id) {
		surface = eglCreateWindowSurface(display, config, window_id, 0);
		if (surface == EGL_NO_SURFACE)
			fatal("eglCreateWindowSurface failed.");
	}
	void cleanup() {
		eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
		eglDestroyContext(display, context);
		eglTerminate(display);
	}
	void destroy_surface() {
		eglDestroySurface(display, surface);
	}
	void make_current() {
		eglMakeCurrent(display, surface, surface, context);
	}
	void release_current() {
		eglMakeCurrent(display, 0, 0, 0);
	}
	void swap_buffers() {
		eglSwapBuffers(display, surface);
	}
	void swap_interval(int interval) {
		eglSwapInterval(display, interval);
	}
};

} // namespace frt
