<commit_before>#include "Framebuffer.hpp"

#include "Error.hpp"
#include "InvalidObject.hpp"
#include "Renderbuffer.hpp"
#include "Texture.hpp"

PyObject * MGLFramebuffer_tp_new(PyTypeObject * type, PyObject * args, PyObject * kwargs) {
	MGLFramebuffer * self = (MGLFramebuffer *)type->tp_alloc(type, 0);

	#ifdef MGL_VERBOSE
	printf("MGLFramebuffer_tp_new %p\n", self);
	#endif

	if (self) {
	}

	return (PyObject *)self;
}

void MGLFramebuffer_tp_dealloc(MGLFramebuffer * self) {

	#ifdef MGL_VERBOSE
	printf("MGLFramebuffer_tp_dealloc %p\n", self);
	#endif

	MGLFramebuffer_Type.tp_free((PyObject *)self);
}

int MGLFramebuffer_tp_init(MGLFramebuffer * self, PyObject * args, PyObject * kwargs) {
	MGLError_Set("cannot create mgl.Framebuffer manually");
	return -1;
}

PyObject * MGLFramebuffer_release(MGLFramebuffer * self) {
	MGLFramebuffer_Invalidate(self);
	Py_RETURN_NONE;
}

PyObject * MGLFramebuffer_clear(MGLFramebuffer * self, PyObject * args) {
	float r, g, b, a;
	PyObject * viewport;

	int args_ok = PyArg_ParseTuple(
		args,
		"ffffO",
		&r,
		&g,
		&b,
		&a,
		&viewport
	);

	if (!args_ok) {
		return 0;
	}

	int x = 0;
	int y = 0;
	int width = self->width;
	int height = self->height;

	if (viewport != Py_None) {
		if (Py_TYPE(viewport) != &PyTuple_Type) {
			MGLError_Set("the viewport must be a tuple not %s", Py_TYPE(viewport)->tp_name);
			return 0;
		}

		if (PyTuple_GET_SIZE(viewport) == 4) {

			x = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 0));
			y = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 1));
			width = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 2));
			height = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 3));

		} else if (PyTuple_GET_SIZE(viewport) == 2) {

			width = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 0));
			height = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 1));

		} else {

			MGLError_Set("the viewport size %d is invalid", PyTuple_GET_SIZE(viewport));
			return 0;

		}

		if (PyErr_Occurred()) {
			MGLError_Set("wrong values in the viewport");
			return 0;
		}

	}

	const GLMethods & gl = self->context->gl;

	gl.BindFramebuffer(GL_FRAMEBUFFER, self->framebuffer_obj);

	gl.ClearColor(r, g, b, a);

	if (viewport != Py_None) {
		gl.Enable(GL_SCISSOR_TEST);
		gl.Scissor(x, y, width, height);
		gl.Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
		gl.Disable(GL_SCISSOR_TEST);
	} else {
		gl.Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
	}

	Py_RETURN_NONE;
}

PyObject * MGLFramebuffer_use(MGLFramebuffer * self) {
	self->context->gl.BindFramebuffer(GL_FRAMEBUFFER, self->framebuffer_obj);
	Py_RETURN_NONE;
}

PyObject * MGLFramebuffer_read(MGLFramebuffer * self, PyObject * args) {
	PyObject * viewport;
	int components;
	int alignment;
	int floats;

	int args_ok = PyArg_ParseTuple(
		args,
		"OIIp",
		&viewport,
		&components,
		&alignment,
		&floats
	);

	if (!args_ok) {
		return 0;
	}

	if (alignment != 1 && alignment != 2 && alignment != 4 && alignment != 8) {
		MGLError_Set("the alignment must be 1, 2, 4 or 8");
		return 0;
	}

	int x = 0;
	int y = 0;
	int width = self->width;
	int height = self->height;

	if (viewport != Py_None) {
		if (Py_TYPE(viewport) != &PyTuple_Type) {
			MGLError_Set("the viewport must be a tuple not %s", Py_TYPE(viewport)->tp_name);
			return 0;
		}

		if (PyTuple_GET_SIZE(viewport) == 4) {

			x = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 0));
			y = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 1));
			width = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 2));
			height = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 3));

		} else if (PyTuple_GET_SIZE(viewport) == 2) {

			width = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 0));
			height = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 1));

		} else {

			MGLError_Set("the viewport size %d is invalid", PyTuple_GET_SIZE(viewport));
			return 0;

		}

		if (PyErr_Occurred()) {
			MGLError_Set("wrong values in the viewport");
			return 0;
		}

	}

	int size = floats ? (width * height * components * 4) : (height * ((width * components + 3) & ~3));
	int type = floats ? GL_FLOAT : GL_UNSIGNED_BYTE;

	const int formats[] = {0, GL_RED, GL_RG, GL_RGB, GL_RGBA};
	int format = formats[components];

	PyObject * result = PyBytes_FromStringAndSize(0, size);
	char * data = PyBytes_AS_STRING(result);

	const GLMethods & gl = self->context->gl;

	gl.BindFramebuffer(GL_FRAMEBUFFER, self->framebuffer_obj);

	gl.PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
	gl.ReadPixels(x, y, width, height, format, type, data);

	return result;
}

PyMethodDef MGLFramebuffer_tp_methods[] = {
	{"clear", (PyCFunction)MGLFramebuffer_clear, METH_NOARGS, 0},
	{"use", (PyCFunction)MGLFramebuffer_use, METH_NOARGS, 0},
	{"read", (PyCFunction)MGLFramebuffer_read, METH_VARARGS, 0},
	{"release", (PyCFunction)MGLFramebuffer_release, METH_NOARGS, 0},
	{0},
};

PyObject * MGLFramebuffer_get_width(MGLFramebuffer * self, void * closure) {
	return PyLong_FromLong(self->width);
}

PyObject * MGLFramebuffer_get_height(MGLFramebuffer * self, void * closure) {
	return PyLong_FromLong(self->height);
}

PyObject * MGLFramebuffer_get_samples(MGLFramebuffer * self, void * closure) {
	return PyLong_FromLong(self->samples);
}

PyObject * MGLFramebuffer_get_color_attachments(MGLFramebuffer * self, void * closure) {
	Py_INCREF(self->color_attachments);
	return self->color_attachments;
}

PyObject * MGLFramebuffer_get_depth_attachment(MGLFramebuffer * self, void * closure) {
	Py_INCREF(self->depth_attachment);
	return self->depth_attachment;
}

MGLContext * MGLFramebuffer_get_context(MGLFramebuffer * self, void * closure) {
	Py_INCREF(self->context);
	return self->context;
}

PyObject * MGLFramebuffer_get_glo(MGLFramebuffer * self, void * closure) {
	return PyLong_FromLong(self->framebuffer_obj);
}

PyGetSetDef MGLFramebuffer_tp_getseters[] = {
	{(char *)"width", (getter)MGLFramebuffer_get_width, 0, 0, 0},
	{(char *)"height", (getter)MGLFramebuffer_get_height, 0, 0, 0},
	{(char *)"samples", (getter)MGLFramebuffer_get_samples, 0, 0, 0},
	{(char *)"color_attachments", (getter)MGLFramebuffer_get_color_attachments, 0, 0, 0},
	{(char *)"depth_attachment", (getter)MGLFramebuffer_get_depth_attachment, 0, 0, 0},
	{(char *)"context", (getter)MGLFramebuffer_get_context, 0, 0, 0},
	{(char *)"glo", (getter)MGLFramebuffer_get_glo, 0, 0, 0},
	{0},
};

PyTypeObject MGLFramebuffer_Type = {
	PyVarObject_HEAD_INIT(0, 0)
	"mgl.Framebuffer",                                      // tp_name
	sizeof(MGLFramebuffer),                                 // tp_basicsize
	0,                                                      // tp_itemsize
	(destructor)MGLFramebuffer_tp_dealloc,                  // tp_dealloc
	0,                                                      // tp_print
	0,                                                      // tp_getattr
	0,                                                      // tp_setattr
	0,                                                      // tp_reserved
	0,                                                      // tp_repr
	0,                                                      // tp_as_number
	0,                                                      // tp_as_sequence
	0,                                                      // tp_as_mapping
	0,                                                      // tp_hash
	0,                                                      // tp_call
	0,                                                      // tp_str
	0,                                                      // tp_getattro
	0,                                                      // tp_setattro
	0,                                                      // tp_as_buffer
	Py_TPFLAGS_DEFAULT,                                     // tp_flags
	0,                                                      // tp_doc
	0,                                                      // tp_traverse
	0,                                                      // tp_clear
	0,                                                      // tp_richcompare
	0,                                                      // tp_weaklistoffset
	0,                                                      // tp_iter
	0,                                                      // tp_iternext
	MGLFramebuffer_tp_methods,                              // tp_methods
	0,                                                      // tp_members
	MGLFramebuffer_tp_getseters,                            // tp_getset
	0,                                                      // tp_base
	0,                                                      // tp_dict
	0,                                                      // tp_descr_get
	0,                                                      // tp_descr_set
	0,                                                      // tp_dictoffset
	(initproc)MGLFramebuffer_tp_init,                       // tp_init
	0,                                                      // tp_alloc
	MGLFramebuffer_tp_new,                                  // tp_new
};

MGLFramebuffer * MGLFramebuffer_New() {
	MGLFramebuffer * self = (MGLFramebuffer *)MGLFramebuffer_tp_new(&MGLFramebuffer_Type, 0, 0);
	return self;
}

void MGLFramebuffer_Invalidate(MGLFramebuffer * framebuffer) {
	if (Py_TYPE(framebuffer) == &MGLInvalidObject_Type) {

		#ifdef MGL_VERBOSE
		printf("MGLFramebuffer_Invalidate %p already released\n", framebuffer);
		#endif

		return;
	}

	#ifdef MGL_VERBOSE
	printf("MGLFramebuffer_Invalidate %p\n", framebuffer);
	#endif

	if (framebuffer->framebuffer_obj) {
		framebuffer->context->gl.DeleteFramebuffers(1, (GLuint *)&framebuffer->framebuffer_obj);

		if (framebuffer->color_attachments) {
			int color_attachments_len = (int)PyTuple_GET_SIZE(framebuffer->color_attachments);

			for (int i = 0; i < color_attachments_len; ++i) {
				PyObject * attachment = PyTuple_GET_ITEM(framebuffer->color_attachments, i);

				if (Py_TYPE(attachment) == &MGLTexture_Type) {
					MGLTexture * texture = (MGLTexture *)attachment;
					if (Py_REFCNT(texture) == 2) {
						MGLTexture_Invalidate(texture);
					}
				} else if (Py_TYPE(attachment) == &MGLRenderbuffer_Type) {
					MGLRenderbuffer * renderbuffer = (MGLRenderbuffer *)attachment;
					if (Py_REFCNT(renderbuffer) == 2) {
						MGLRenderbuffer_Invalidate(renderbuffer);
					}
				}
			}

			Py_DECREF(framebuffer->color_attachments);
		}

		if (framebuffer->depth_attachment) {
			if (Py_TYPE(framebuffer->depth_attachment) == &MGLTexture_Type) {
				MGLTexture * texture = (MGLTexture *)framebuffer->depth_attachment;
				if (Py_REFCNT(texture) == 2) {
					MGLTexture_Invalidate(texture);
				}
			} else if (Py_TYPE(framebuffer->depth_attachment) == &MGLRenderbuffer_Type) {
				MGLRenderbuffer * renderbuffer = (MGLRenderbuffer *)framebuffer->depth_attachment;
				if (Py_REFCNT(renderbuffer) == 2) {
					MGLRenderbuffer_Invalidate(renderbuffer);
				}
			}

			Py_DECREF(framebuffer->depth_attachment);
		}

		Py_DECREF(framebuffer->context);
	}

	Py_TYPE(framebuffer) = &MGLInvalidObject_Type;

	Py_DECREF(framebuffer);
}
<commit_msg>fix framebuffer alignment on read<commit_after>#include "Framebuffer.hpp"

#include "Error.hpp"
#include "InvalidObject.hpp"
#include "Renderbuffer.hpp"
#include "Texture.hpp"

PyObject * MGLFramebuffer_tp_new(PyTypeObject * type, PyObject * args, PyObject * kwargs) {
	MGLFramebuffer * self = (MGLFramebuffer *)type->tp_alloc(type, 0);

	#ifdef MGL_VERBOSE
	printf("MGLFramebuffer_tp_new %p\n", self);
	#endif

	if (self) {
	}

	return (PyObject *)self;
}

void MGLFramebuffer_tp_dealloc(MGLFramebuffer * self) {

	#ifdef MGL_VERBOSE
	printf("MGLFramebuffer_tp_dealloc %p\n", self);
	#endif

	MGLFramebuffer_Type.tp_free((PyObject *)self);
}

int MGLFramebuffer_tp_init(MGLFramebuffer * self, PyObject * args, PyObject * kwargs) {
	MGLError_Set("cannot create mgl.Framebuffer manually");
	return -1;
}

PyObject * MGLFramebuffer_release(MGLFramebuffer * self) {
	MGLFramebuffer_Invalidate(self);
	Py_RETURN_NONE;
}

PyObject * MGLFramebuffer_clear(MGLFramebuffer * self, PyObject * args) {
	float r, g, b, a;
	PyObject * viewport;

	int args_ok = PyArg_ParseTuple(
		args,
		"ffffO",
		&r,
		&g,
		&b,
		&a,
		&viewport
	);

	if (!args_ok) {
		return 0;
	}

	int x = 0;
	int y = 0;
	int width = self->width;
	int height = self->height;

	if (viewport != Py_None) {
		if (Py_TYPE(viewport) != &PyTuple_Type) {
			MGLError_Set("the viewport must be a tuple not %s", Py_TYPE(viewport)->tp_name);
			return 0;
		}

		if (PyTuple_GET_SIZE(viewport) == 4) {

			x = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 0));
			y = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 1));
			width = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 2));
			height = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 3));

		} else if (PyTuple_GET_SIZE(viewport) == 2) {

			width = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 0));
			height = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 1));

		} else {

			MGLError_Set("the viewport size %d is invalid", PyTuple_GET_SIZE(viewport));
			return 0;

		}

		if (PyErr_Occurred()) {
			MGLError_Set("wrong values in the viewport");
			return 0;
		}

	}

	const GLMethods & gl = self->context->gl;

	gl.BindFramebuffer(GL_FRAMEBUFFER, self->framebuffer_obj);

	gl.ClearColor(r, g, b, a);

	if (viewport != Py_None) {
		gl.Enable(GL_SCISSOR_TEST);
		gl.Scissor(x, y, width, height);
		gl.Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
		gl.Disable(GL_SCISSOR_TEST);
	} else {
		gl.Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
	}

	Py_RETURN_NONE;
}

PyObject * MGLFramebuffer_use(MGLFramebuffer * self) {
	self->context->gl.BindFramebuffer(GL_FRAMEBUFFER, self->framebuffer_obj);
	Py_RETURN_NONE;
}

PyObject * MGLFramebuffer_read(MGLFramebuffer * self, PyObject * args) {
	PyObject * viewport;
	int components;
	int alignment;
	int floats;

	int args_ok = PyArg_ParseTuple(
		args,
		"OIIp",
		&viewport,
		&components,
		&alignment,
		&floats
	);

	if (!args_ok) {
		return 0;
	}

	if (alignment != 1 && alignment != 2 && alignment != 4 && alignment != 8) {
		MGLError_Set("the alignment must be 1, 2, 4 or 8");
		return 0;
	}

	int x = 0;
	int y = 0;
	int width = self->width;
	int height = self->height;

	if (viewport != Py_None) {
		if (Py_TYPE(viewport) != &PyTuple_Type) {
			MGLError_Set("the viewport must be a tuple not %s", Py_TYPE(viewport)->tp_name);
			return 0;
		}

		if (PyTuple_GET_SIZE(viewport) == 4) {

			x = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 0));
			y = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 1));
			width = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 2));
			height = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 3));

		} else if (PyTuple_GET_SIZE(viewport) == 2) {

			width = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 0));
			height = PyLong_AsLong(PyTuple_GET_ITEM(viewport, 1));

		} else {

			MGLError_Set("the viewport size %d is invalid", PyTuple_GET_SIZE(viewport));
			return 0;

		}

		if (PyErr_Occurred()) {
			MGLError_Set("wrong values in the viewport");
			return 0;
		}

	}

	int expected_size = width * components * (floats ?  4 : 1);
	expected_size = (expected_size + alignment - 1) / alignment * alignment;
	expected_size = expected_size * height;

	int type = floats ? GL_FLOAT : GL_UNSIGNED_BYTE;

	const int formats[] = {0, GL_RED, GL_RG, GL_RGB, GL_RGBA};
	int format = formats[components];

	PyObject * result = PyBytes_FromStringAndSize(0, expected_size);
	char * data = PyBytes_AS_STRING(result);

	const GLMethods & gl = self->context->gl;

	gl.BindFramebuffer(GL_FRAMEBUFFER, self->framebuffer_obj);

	gl.PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
	gl.ReadPixels(x, y, width, height, format, type, data);

	return result;
}

PyMethodDef MGLFramebuffer_tp_methods[] = {
	{"clear", (PyCFunction)MGLFramebuffer_clear, METH_NOARGS, 0},
	{"use", (PyCFunction)MGLFramebuffer_use, METH_NOARGS, 0},
	{"read", (PyCFunction)MGLFramebuffer_read, METH_VARARGS, 0},
	{"release", (PyCFunction)MGLFramebuffer_release, METH_NOARGS, 0},
	{0},
};

PyObject * MGLFramebuffer_get_width(MGLFramebuffer * self, void * closure) {
	return PyLong_FromLong(self->width);
}

PyObject * MGLFramebuffer_get_height(MGLFramebuffer * self, void * closure) {
	return PyLong_FromLong(self->height);
}

PyObject * MGLFramebuffer_get_samples(MGLFramebuffer * self, void * closure) {
	return PyLong_FromLong(self->samples);
}

PyObject * MGLFramebuffer_get_color_attachments(MGLFramebuffer * self, void * closure) {
	Py_INCREF(self->color_attachments);
	return self->color_attachments;
}

PyObject * MGLFramebuffer_get_depth_attachment(MGLFramebuffer * self, void * closure) {
	Py_INCREF(self->depth_attachment);
	return self->depth_attachment;
}

MGLContext * MGLFramebuffer_get_context(MGLFramebuffer * self, void * closure) {
	Py_INCREF(self->context);
	return self->context;
}

PyObject * MGLFramebuffer_get_glo(MGLFramebuffer * self, void * closure) {
	return PyLong_FromLong(self->framebuffer_obj);
}

PyGetSetDef MGLFramebuffer_tp_getseters[] = {
	{(char *)"width", (getter)MGLFramebuffer_get_width, 0, 0, 0},
	{(char *)"height", (getter)MGLFramebuffer_get_height, 0, 0, 0},
	{(char *)"samples", (getter)MGLFramebuffer_get_samples, 0, 0, 0},
	{(char *)"color_attachments", (getter)MGLFramebuffer_get_color_attachments, 0, 0, 0},
	{(char *)"depth_attachment", (getter)MGLFramebuffer_get_depth_attachment, 0, 0, 0},
	{(char *)"context", (getter)MGLFramebuffer_get_context, 0, 0, 0},
	{(char *)"glo", (getter)MGLFramebuffer_get_glo, 0, 0, 0},
	{0},
};

PyTypeObject MGLFramebuffer_Type = {
	PyVarObject_HEAD_INIT(0, 0)
	"mgl.Framebuffer",                                      // tp_name
	sizeof(MGLFramebuffer),                                 // tp_basicsize
	0,                                                      // tp_itemsize
	(destructor)MGLFramebuffer_tp_dealloc,                  // tp_dealloc
	0,                                                      // tp_print
	0,                                                      // tp_getattr
	0,                                                      // tp_setattr
	0,                                                      // tp_reserved
	0,                                                      // tp_repr
	0,                                                      // tp_as_number
	0,                                                      // tp_as_sequence
	0,                                                      // tp_as_mapping
	0,                                                      // tp_hash
	0,                                                      // tp_call
	0,                                                      // tp_str
	0,                                                      // tp_getattro
	0,                                                      // tp_setattro
	0,                                                      // tp_as_buffer
	Py_TPFLAGS_DEFAULT,                                     // tp_flags
	0,                                                      // tp_doc
	0,                                                      // tp_traverse
	0,                                                      // tp_clear
	0,                                                      // tp_richcompare
	0,                                                      // tp_weaklistoffset
	0,                                                      // tp_iter
	0,                                                      // tp_iternext
	MGLFramebuffer_tp_methods,                              // tp_methods
	0,                                                      // tp_members
	MGLFramebuffer_tp_getseters,                            // tp_getset
	0,                                                      // tp_base
	0,                                                      // tp_dict
	0,                                                      // tp_descr_get
	0,                                                      // tp_descr_set
	0,                                                      // tp_dictoffset
	(initproc)MGLFramebuffer_tp_init,                       // tp_init
	0,                                                      // tp_alloc
	MGLFramebuffer_tp_new,                                  // tp_new
};

MGLFramebuffer * MGLFramebuffer_New() {
	MGLFramebuffer * self = (MGLFramebuffer *)MGLFramebuffer_tp_new(&MGLFramebuffer_Type, 0, 0);
	return self;
}

void MGLFramebuffer_Invalidate(MGLFramebuffer * framebuffer) {
	if (Py_TYPE(framebuffer) == &MGLInvalidObject_Type) {

		#ifdef MGL_VERBOSE
		printf("MGLFramebuffer_Invalidate %p already released\n", framebuffer);
		#endif

		return;
	}

	#ifdef MGL_VERBOSE
	printf("MGLFramebuffer_Invalidate %p\n", framebuffer);
	#endif

	if (framebuffer->framebuffer_obj) {
		framebuffer->context->gl.DeleteFramebuffers(1, (GLuint *)&framebuffer->framebuffer_obj);

		if (framebuffer->color_attachments) {
			int color_attachments_len = (int)PyTuple_GET_SIZE(framebuffer->color_attachments);

			for (int i = 0; i < color_attachments_len; ++i) {
				PyObject * attachment = PyTuple_GET_ITEM(framebuffer->color_attachments, i);

				if (Py_TYPE(attachment) == &MGLTexture_Type) {
					MGLTexture * texture = (MGLTexture *)attachment;
					if (Py_REFCNT(texture) == 2) {
						MGLTexture_Invalidate(texture);
					}
				} else if (Py_TYPE(attachment) == &MGLRenderbuffer_Type) {
					MGLRenderbuffer * renderbuffer = (MGLRenderbuffer *)attachment;
					if (Py_REFCNT(renderbuffer) == 2) {
						MGLRenderbuffer_Invalidate(renderbuffer);
					}
				}
			}

			Py_DECREF(framebuffer->color_attachments);
		}

		if (framebuffer->depth_attachment) {
			if (Py_TYPE(framebuffer->depth_attachment) == &MGLTexture_Type) {
				MGLTexture * texture = (MGLTexture *)framebuffer->depth_attachment;
				if (Py_REFCNT(texture) == 2) {
					MGLTexture_Invalidate(texture);
				}
			} else if (Py_TYPE(framebuffer->depth_attachment) == &MGLRenderbuffer_Type) {
				MGLRenderbuffer * renderbuffer = (MGLRenderbuffer *)framebuffer->depth_attachment;
				if (Py_REFCNT(renderbuffer) == 2) {
					MGLRenderbuffer_Invalidate(renderbuffer);
				}
			}

			Py_DECREF(framebuffer->depth_attachment);
		}

		Py_DECREF(framebuffer->context);
	}

	Py_TYPE(framebuffer) = &MGLInvalidObject_Type;

	Py_DECREF(framebuffer);
}
<|endoftext|>


<commit_before><commit_msg>gtk3: caveats on using g_main_prepare for older glibs; needs re-work<commit_after><|endoftext|>


<commit_before>#include "Game/Square.h"

#include <cstddef>
#include <string>
#include <cassert>
#include <cmath>

#include "Game/Color.h"

#include "Utility/Math.h"

//! Reverse the direction of a square offset.
Square_Difference Square_Difference::operator-() const
{
    return {-file_change, -rank_change};
}

//! Returns a single-step version of the offset--i.e., (-3, 3) --> (-1, 1)

//! Note: Only valid for straight (rook- or bishop-type) moves
Square_Difference Square_Difference::step() const
{
    return {Math::sign(file_change), Math::sign(rank_change)};
}

//! Return the first square when iterating all squares
Square Square_Iterator::begin() const{ return Square{'a', 1}; }

//! Return an invalid Square to end iteration
Square Square_Iterator::end() const { return Square{}; }

unsigned int Square::invalid_index = 64;

//! The default constructor creates an invalid square location.
Square::Square() : square_index(invalid_index)
{
}

//! This constructor creates a user-defined square.

//! \param file The file (column) of the square (a-h).
//! \param rank The rank (row) of the square (1-8).
//!
//! The validity of the square coordinates is not checked in release builds.
//! In debug builds, invalid square coordinates (e.g., "i9") trigger an assertion failure.
Square::Square(char file, int rank) : square_index(8*(file - 'a') + (rank - 1))
{
    assert(inside_board());
}

//! The file of the square.

//! \returns The letter label of the square file.
char Square::file() const
{
    return char('a' + index()/8);
}

//! The rank of the square.

//! \returns The numerical label of the rank.
int Square::rank() const
{
    return 1 + index()%8;
}

//! The index of the square.

//! \returns An unsigned integer index.
size_t Square::index() const
{
    return square_index;
}

//! String representation of square.
std::string Square::string() const
{
    return file() + std::to_string(rank());
}

//! Returns the color of the square.

//! This function is useful for Board::enough_material_to_checkmate() since one
//! condition is that bishops on opposite color squares are sufficient to checkmate,
//! while bishops on the same color square are not.
//! \returns Color of square on board ("a1" --> BLACK; "h1" --> WHITE)
Color Square::color() const
{
    //return (file() - 'a')%2 == (rank() - 1)%2 ? BLACK : WHITE;
    return (index()/8)%2 == (index()%8)%2 ? BLACK : WHITE;
}

//! Check if the square is a valid Board position.

//! \returns Whether the square is on the Board ("i10" returns false).
bool Square::inside_board() const
{
    return index() < invalid_index;
}

//! Check whether a square has been set with a valid coordinate.

//! This is a synonym for Square::inside_board().
bool Square::is_set() const
{
    return inside_board();
}

//! Apply an offset to a square.

//! \param diff A pair of integers representing the change in file and rank
//! \returns A reference to the now-modified square. This may create a square that is off
//!          the board ("h8" + (1,1), for example).
Square& Square::operator+=(const Square_Difference& diff)
{
    assert(std::abs(diff.file_change) < 8 && std::abs(diff.rank_change) < 8);
    auto new_rank_index = square_index + diff.rank_change;
    if(new_rank_index/8 != square_index/8) // make sure file did not change (happens if new square is off the board vertically)
    {
        square_index = invalid_index;
        return *this;
    }

    square_index = new_rank_index + 8*(diff.file_change);
    return *this;
}

//! Apply an offset to a square in the opposite direction.

//! \param diff A pair of integers representing the change in file and rank
//! \returns A reference to the now-modified square.
Square& Square::operator-=(const Square_Difference& diff)
{
    return *this += -diff;
}

Square& Square::operator++()
{
    ++square_index;
    return *this;
}

Square Square::operator*() const
{
    return *this;
}

//! Check that a square file is a valid value.

//! \param file Square file to check ('a' <= file <= 'h')
//! \returns Whether the file meets the condition according to the parameter specification above.
bool Square::inside_board(char file)
{
    return 'a' <= file && file <= 'h';
}

//! Check that a square rank is a valid value.

//! \param rank Square rank to check (1 <= file <= 8)
//! \returns Whether the rank meets the condition according to the parameter specification above.
bool Square::inside_board(int rank)
{
    return 1 <= rank && rank <= 8;
}

//! Check that a square file and rank is a valid value.

//! \param file Square file to check ('a' <= file <= 'h')
//! \param rank Square rank to check (1 <= file <= 8)
//! \returns Whether the rank meets the condition according to the parameter specification above.
bool Square::inside_board(char file, int rank)
{
    return inside_board(file) && inside_board(rank);
}

Square_Iterator Square::all_squares()
{
    return {};
}

//! Check if two squares are the same.

//! \returns Whether two squares have the same file and rank or are both outside the board.
bool operator==(Square a, Square b)
{
    return (a.index() == b.index()) || ( ! a.inside_board() && ! b.inside_board());
}

//! Check if two squares are not the same.

//! \returns Whether two squares differ in their file or rank.
bool operator!=(Square a, Square b)
{
    return !(a == b);
}

//! Add an offset to a square, returning a new Square.

//! \param square The original square.
//! \param diff A pair of integers representing the change in file and rank.
Square operator+(Square square, const Square_Difference& diff)
{
    return square += diff;
}

//! Add an offset to a square in the opposite direction, returning a new Square.

//! \param square The original square.
//! \param diff A pair of integers representing the change in file and rank.
Square operator-(Square square, const Square_Difference& diff)
{
    return square -= diff;
}

//! Find the 2-dimensional distance offset between two squares.

//! \param a The first square.
//! \param b The second square.
//! \returns A pair of integers representing the signed difference in file and rank.
//!
//! For all valid squares on a board, a + (b - a) == b.
Square_Difference operator-(Square a, Square b)
{
    assert(a.inside_board() && b.inside_board());
    return {a.file() - b.file(), a.rank() - b.rank()};
}
<commit_msg>Consistent code formatting<commit_after>#include "Game/Square.h"

#include <cstddef>
#include <string>
#include <cassert>
#include <cmath>

#include "Game/Color.h"

#include "Utility/Math.h"

//! Reverse the direction of a square offset.
Square_Difference Square_Difference::operator-() const
{
    return {-file_change, -rank_change};
}

//! Returns a single-step version of the offset--i.e., (-3, 3) --> (-1, 1)

//! Note: Only valid for straight (rook- or bishop-type) moves
Square_Difference Square_Difference::step() const
{
    return {Math::sign(file_change), Math::sign(rank_change)};
}

//! Return the first square when iterating all squares
Square Square_Iterator::begin() const
{
    return Square{'a', 1};
}

//! Return an invalid Square to end iteration
Square Square_Iterator::end() const
{
    return Square{};
}

unsigned int Square::invalid_index = 64;

//! The default constructor creates an invalid square location.
Square::Square() : square_index(invalid_index)
{
}

//! This constructor creates a user-defined square.

//! \param file The file (column) of the square (a-h).
//! \param rank The rank (row) of the square (1-8).
//!
//! The validity of the square coordinates is not checked in release builds.
//! In debug builds, invalid square coordinates (e.g., "i9") trigger an assertion failure.
Square::Square(char file, int rank) : square_index(8*(file - 'a') + (rank - 1))
{
    assert(inside_board());
}

//! The file of the square.

//! \returns The letter label of the square file.
char Square::file() const
{
    return char('a' + index()/8);
}

//! The rank of the square.

//! \returns The numerical label of the rank.
int Square::rank() const
{
    return 1 + index()%8;
}

//! The index of the square.

//! \returns An unsigned integer index.
size_t Square::index() const
{
    return square_index;
}

//! String representation of square.
std::string Square::string() const
{
    return file() + std::to_string(rank());
}

//! Returns the color of the square.

//! This function is useful for Board::enough_material_to_checkmate() since one
//! condition is that bishops on opposite color squares are sufficient to checkmate,
//! while bishops on the same color square are not.
//! \returns Color of square on board ("a1" --> BLACK; "h1" --> WHITE)
Color Square::color() const
{
    //return (file() - 'a')%2 == (rank() - 1)%2 ? BLACK : WHITE;
    return (index()/8)%2 == (index()%8)%2 ? BLACK : WHITE;
}

//! Check if the square is a valid Board position.

//! \returns Whether the square is on the Board ("i10" returns false).
bool Square::inside_board() const
{
    return index() < invalid_index;
}

//! Check whether a square has been set with a valid coordinate.

//! This is a synonym for Square::inside_board().
bool Square::is_set() const
{
    return inside_board();
}

//! Apply an offset to a square.

//! \param diff A pair of integers representing the change in file and rank
//! \returns A reference to the now-modified square. This may create a square that is off
//!          the board ("h8" + (1,1), for example).
Square& Square::operator+=(const Square_Difference& diff)
{
    assert(std::abs(diff.file_change) < 8 && std::abs(diff.rank_change) < 8);
    auto new_rank_index = square_index + diff.rank_change;
    if(new_rank_index/8 != square_index/8) // make sure file did not change (happens if new square is off the board vertically)
    {
        square_index = invalid_index;
        return *this;
    }

    square_index = new_rank_index + 8*(diff.file_change);
    return *this;
}

//! Apply an offset to a square in the opposite direction.

//! \param diff A pair of integers representing the change in file and rank
//! \returns A reference to the now-modified square.
Square& Square::operator-=(const Square_Difference& diff)
{
    return *this += -diff;
}

Square& Square::operator++()
{
    ++square_index;
    return *this;
}

Square Square::operator*() const
{
    return *this;
}

//! Check that a square file is a valid value.

//! \param file Square file to check ('a' <= file <= 'h')
//! \returns Whether the file meets the condition according to the parameter specification above.
bool Square::inside_board(char file)
{
    return 'a' <= file && file <= 'h';
}

//! Check that a square rank is a valid value.

//! \param rank Square rank to check (1 <= file <= 8)
//! \returns Whether the rank meets the condition according to the parameter specification above.
bool Square::inside_board(int rank)
{
    return 1 <= rank && rank <= 8;
}

//! Check that a square file and rank is a valid value.

//! \param file Square file to check ('a' <= file <= 'h')
//! \param rank Square rank to check (1 <= file <= 8)
//! \returns Whether the rank meets the condition according to the parameter specification above.
bool Square::inside_board(char file, int rank)
{
    return inside_board(file) && inside_board(rank);
}

Square_Iterator Square::all_squares()
{
    return {};
}

//! Check if two squares are the same.

//! \returns Whether two squares have the same file and rank or are both outside the board.
bool operator==(Square a, Square b)
{
    return (a.index() == b.index()) || ( ! a.inside_board() && ! b.inside_board());
}

//! Check if two squares are not the same.

//! \returns Whether two squares differ in their file or rank.
bool operator!=(Square a, Square b)
{
    return !(a == b);
}

//! Add an offset to a square, returning a new Square.

//! \param square The original square.
//! \param diff A pair of integers representing the change in file and rank.
Square operator+(Square square, const Square_Difference& diff)
{
    return square += diff;
}

//! Add an offset to a square in the opposite direction, returning a new Square.

//! \param square The original square.
//! \param diff A pair of integers representing the change in file and rank.
Square operator-(Square square, const Square_Difference& diff)
{
    return square -= diff;
}

//! Find the 2-dimensional distance offset between two squares.

//! \param a The first square.
//! \param b The second square.
//! \returns A pair of integers representing the signed difference in file and rank.
//!
//! For all valid squares on a board, a + (b - a) == b.
Square_Difference operator-(Square a, Square b)
{
    assert(a.inside_board() && b.inside_board());
    return {a.file() - b.file(), a.rank() - b.rank()};
}
<|endoftext|>


<commit_before>#include <iostream>
#include <time.h>
#include <array>
#include "Brick.h"
#include "GameManager.h"
#include "Log.h"
#include "Menu.h"
#include "Timer.h"
#include "levelLoader.h"

GameManager::GameManager(Window* window):
    window(window)
{
    currentState = STATE_MENU;
    _quit = false;
    srand(time(NULL));

    bgTexture = window->loadTexture("bg.bmp");
    gameBgTexture = window->loadTexture("bgNoTitle.bmp");
    htpTexture = window->loadTexture("HowToPlay.bmp");

    paddle = new Entity(window, "paddle.bmp", 305, 490);

    currentLevel = 1;
    bricksLeft = 0;
    maxBricks = 0;
    totalBricksDestroyed = 0;

    std::string resPath = "res";
    std::string collidePath = "";
    collidePath = resPath + PATH_SEP + "collide.wav";
    ballHitSound = Mix_LoadWAV(collidePath.c_str());
    if (!ballHitSound)
        Log::error("Couldn't open collide.wav");

    std::string brickBreakSoundPath = resPath + PATH_SEP + "breakBrick.wav";
    brickBreakSound = Mix_LoadWAV(brickBreakSoundPath.c_str());
    if (!ballHitSound)
        Log::error("Couldn't open brickBreak.wav");

    showMessage = false;
    message = "";
    uint32_t messageDisplayStart;
}

void GameManager::initGame(bool fresh)
{
    paddle->setMoveRate(8);
    paddle->setTexture("paddle.bmp");
    paddle->setX(305);
    paddle->setY(490);
    paddle->stopMoving(MOVE_LEFT);
    paddle->stopMoving(MOVE_RIGHT);

    ball = new Ball(window, "ball.png", window->getWidth() / 2, window->getHeight() / 2, paddle);
    ball->setOnPaddle(true);

    //used for random powerup spwaning
    randNum = rand() % 4;
    mod = new Mods(window, "PowerUP.bmp", window->getWidth() / 2, 0 );//makes a new power down object

    upNum = rand() % 2;
    downNum = rand() % 2;

    entities = std::vector<Entity*>();

    if (fresh)
    {
        currentLevel = 1;
        totalBricksDestroyed = 0;
    }

    LevelLoader* loader = new LevelLoader(this);
    switch (currentLevel)
    {
        case 1:
            loader->openMap("lvl1.txt", maxBricks);
            break;
        case 2:
            loader->openMap("lvl2.txt", maxBricks);
            break;
        default:
            currentState = STATE_WINNER;
            break;
    }

    if (currentState == STATE_PLAYING)
    {
        Log::info("Loaded level " + std::to_string(currentLevel) + " with " + std::to_string(maxBricks) + " blocks.");

        bricksLeft = maxBricks;
        levelOver = false;
    }
}

void GameManager::runGame()
{
    Menu mainMenu(this);
    mainMenu.addEntry("Play");
    mainMenu.addEntry("How to Play");
    mainMenu.addEntry("Credits");
    mainMenu.addEntry("Exit");

    Timer fpsTimer;
    Timer capTimer;

    uint32_t frameCount = 0;
    fpsTimer.start();

    while (!_quit)
    {
        window->clear();

        capTimer.start();

        switch (currentState)
        {
        case STATE_MENU:
        {
            window->renderTexture(bgTexture, 0, 0);
            mainMenu.tick();
            break;
        }
        case STATE_HOWTOPLAY:
        {
            window->renderTexture(htpTexture, 0, 0);
            listenForQuit();
            break;
        }
        case STATE_CREDITS:
        {
            window->renderTexture(bgTexture, 0, 0);
            printCredits();
            listenForQuit();
            break;
        }
        case STATE_PLAYING:
            window->renderTexture(gameBgTexture, 0, 0);
            gameTick();
            break;
        case STATE_WINNER:
        {
            window->renderTexture(bgTexture, 0, 0);
            window->renderCenteredText("YOU WON!", 100, { 0, 0, 0 }, 75, FONT_RENDER_BLENDED, { 0, 0, 0 });
            window->renderCenteredText("Final Score: " + std::to_string(calcScore()), 180, { 0, 0, 0 }, 75, FONT_RENDER_BLENDED, { 0, 0, 0 });
            listenForQuit();
            break;
        }

        default:
            Log::warn("Recieved unhandled gamestate: " + std::to_string(currentState));
            break;
        }

        // divide the amount of frames displayed by the runtime in seconds to get the average fps
        float avgFps = frameCount / (fpsTimer.getTicks() / 1000.f);
        if (avgFps > 2000000)
            avgFps = 0;

        window->renderText(std::to_string((int)avgFps), window->getWidth()-30, 0, { 0, 0, 0 }, 25, FONT_RENDER_BLENDED, { 0, 0, 0 });

        window->render();

        frameCount++;

        // if our fps it too high, wait here until we're back to ~60fps
        if (capTimer.getTicks() < (1000 / window->getMaxFps()))
        {
            int waitTime = (1000 / window->getMaxFps()) - capTimer.getTicks();
            SDL_Delay(waitTime);
        }
    }
}

void GameManager::gameTick()
{
    bool repeatKey = SDL_PollEvent(&event) == 1;

    if (levelOver)
    {
        totalBricksDestroyed += maxBricks;
        currentLevel++;
        initGame(false);
        levelOver = false;
        return;
    }

    if(ball->getLives() < 1)
    {
        totalBricksDestroyed += maxBricks - bricksLeft;

        window->renderCenteredText("GAME OVER", window->getHeight()/4, {0,0,0}, 50, FONT_RENDER_BLENDED, {255,255,255});
        window->renderCenteredText("Score: " + std::to_string(calcScore()), window->getHeight()/2, {0,0,0}, 50, FONT_RENDER_BLENDED, {255,255,255});
        listenForQuit();
        return;
    }

    switch (event.type)
    {
    // if user clicks the red X
    case SDL_QUIT:
        _quit = true;
        break;

    case SDL_KEYDOWN:
        switch (event.key.keysym.sym)
        {
        case SDLK_LEFT:
            paddle->startMoving(MOVE_LEFT);
            break;
        case SDLK_RIGHT:
            paddle->startMoving(MOVE_RIGHT);
            break;
        case SDLK_SPACE:
            if (ball->isOnPaddle())
                ball->detach();
            isPressed = true;
            break;
        case SDLK_ESCAPE:
            if (repeatKey)
            {
                setState(STATE_MENU);
                return;
            }
        }
        break;

    case SDL_KEYUP:
        switch (event.key.keysym.sym)
        {
        case SDLK_LEFT:
            paddle->stopMoving(MOVE_LEFT);
            break;
        case SDLK_RIGHT:
            paddle->stopMoving(MOVE_RIGHT);
            break;
        }
        break;
    }

	bool collidedThisTick = false;
    for (Entity* e : entities)
    {
        bool playedSound = false;
        if (e->isActive())
        {
            // don't think this is that cpu intensive but I guess it could be
            if ((ball->collidedWith(e)) && (e->isActive()) && !collidedThisTick)
            {
                collidedThisTick = true;
                ball->handleCollision(e);
                if (e->getTypeId() == TYPEID_BRICK)
                {
                    if (!((Brick*)e)->dealDamage(1))
                    {
                        bricksLeft--;
                        Mix_PlayChannel(-1, brickBreakSound, 0);
                        playedSound = true;
                    }
                    Log::info(std::to_string(bricksLeft) + " / " + std::to_string(maxBricks) + " bricks remaining");
                }

                if (!playedSound)
                    Mix_PlayChannel(-1, ballHitSound, 0);
            }
            e->update();
        }
    }

    if (ball->collidedWith(paddle))
    {
        Mix_PlayChannel(-1, ballHitSound, 0);
        ball->handleCollision(paddle);
    }
    paddle->update();

    /************** Code segment used for powerup implementation ***************/
    if(randNum == 0 && isPressed == true)
    {
        mod->update();
        if(mod->collidedWith(paddle))
        {
            mod->fastPaddle();
            paddle->setMoveRate(7);
            mod->remove();
        }
    }

    if(randNum == 1 && isPressed == true)
    {
        mod->update();
        if(mod->collidedWith(paddle))
        {
            paddle->setTexture("paddle_big.bmp");
            mod->largePaddle();
            mod->remove();
        }
    }

    if(randNum == 2 && isPressed == true)
    {
        mod->update();
        if(mod->collidedWith(paddle))
        {
            paddle->setTexture("paddle_big.bmp");
            mod->largePaddle();
            mod->remove();
        }
    }

    if(randNum == 3 && isPressed == true)
    {
        mod->update();
        if(mod->collidedWith(paddle))
        {
            paddle->setTexture("paddle_small.bmp");
            mod->smallPaddle();
            mod->remove();
        }
    }
    /***************************************************************************/

    ball->update();
    window->renderText("Lives: " + std::to_string(ball->getLives()), 0, 0, { 0, 0, 0 }, 25, FONT_RENDER_BLENDED, { 0, 0, 0 });

    if (bricksLeft == 0)
    {
        levelOver = true;
        totalBricksDestroyed += maxBricks;
    }

    /*if (showMessage)
    {
        window->renderCenteredText(message, 200, { 0, 0, 0 }, 60, FONT_RENDER_BLENDED, { 0, 0, 0 });
        if (timePassed > 5 * 1000)
            showMessage = false;
    }*/
}

void GameManager::addEntity(Entity* e)
{
	entities.push_back(e);
}

void GameManager::setState(int state)
{
    Log::info("Set state to " + std::to_string(state));
    currentState = state;
}

void GameManager::printCredits()
{
    window->renderCenteredText("Henry Gordon", 100, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
    window->renderCenteredText("Anthony Brugal", 150, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
    window->renderCenteredText("Iden Sessani", 200, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
    window->renderCenteredText("Erik Higginbotham", 250, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
    window->renderCenteredText("Aaron Hanuschak", 300, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
    window->renderCenteredText("Kurt Weber", 350, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
}

void GameManager::listenForQuit()
{
    SDL_Event currEvent;
    bool repeatKey = SDL_PollEvent(&currEvent) == 1;

    switch (currEvent.type)
    {
    // if user clicks the red X
    case SDL_QUIT:
        _quit = true;
        return;
    case SDL_KEYDOWN:
        if (repeatKey)
        {
            switch (currEvent.key.keysym.sym)
            {
            case SDLK_SPACE:
            case SDLK_RETURN:
            case SDLK_ESCAPE:
                setState(STATE_MENU);
            }
        }
    }
}

int GameManager::calcScore()
{
    return (ball->getLives() + 1) * (totalBricksDestroyed);
}
<commit_msg>All 5 levels are now playable<commit_after>#include <iostream>
#include <time.h>
#include <array>
#include "Brick.h"
#include "GameManager.h"
#include "Log.h"
#include "Menu.h"
#include "Timer.h"
#include "levelLoader.h"

GameManager::GameManager(Window* window):
    window(window)
{
    currentState = STATE_MENU;
    _quit = false;
    srand(time(NULL));

    bgTexture = window->loadTexture("bg.bmp");
    gameBgTexture = window->loadTexture("bgNoTitle.bmp");
    htpTexture = window->loadTexture("HowToPlay.bmp");

    paddle = new Entity(window, "paddle.bmp", 305, 490);

    currentLevel = 1;
    bricksLeft = 0;
    maxBricks = 0;
    totalBricksDestroyed = 0;

    std::string resPath = "res";
    std::string collidePath = "";
    collidePath = resPath + PATH_SEP + "collide.wav";
    ballHitSound = Mix_LoadWAV(collidePath.c_str());
    if (!ballHitSound)
        Log::error("Couldn't open collide.wav");

    std::string brickBreakSoundPath = resPath + PATH_SEP + "breakBrick.wav";
    brickBreakSound = Mix_LoadWAV(brickBreakSoundPath.c_str());
    if (!ballHitSound)
        Log::error("Couldn't open brickBreak.wav");

    showMessage = false;
    message = "";
}

void GameManager::initGame(bool fresh)
{
    paddle->setMoveRate(8);
    paddle->setTexture("paddle.bmp");
    paddle->setX(305);
    paddle->setY(490);
    paddle->stopMoving(MOVE_LEFT);
    paddle->stopMoving(MOVE_RIGHT);

    ball = new Ball(window, "ball.png", window->getWidth() / 2, window->getHeight() / 2, paddle);
    ball->setOnPaddle(true);

    //used for random powerup spwaning
    randNum = rand() % 4;
    mod = new Mods(window, "PowerUP.bmp", window->getWidth() / 2, 0 );//makes a new power down object

    upNum = rand() % 2;
    downNum = rand() % 2;

    entities = std::vector<Entity*>();

    if (fresh)
    {
        currentLevel = 1;
        totalBricksDestroyed = 0;
    }

    LevelLoader* loader = new LevelLoader(this);
    switch (currentLevel)
    {
        case 1:
            loader->openMap("lvl1.txt", maxBricks);
            break;
        case 2:
            loader->openMap("lvl2.txt", maxBricks);
            break;
        case 3:
            loader->openMap("lvl3.txt", maxBricks);
            break;
        case 4:
            loader->openMap("lvl4.txt", maxBricks);
            break;
        case 5:
            loader->openMap("lvl5.txt", maxBricks);
            break;
        default:
            currentState = STATE_WINNER;
            break;
    }

    if (currentState == STATE_PLAYING)
    {
        Log::info("Loaded level " + std::to_string(currentLevel) + " with " + std::to_string(maxBricks) + " blocks.");

        bricksLeft = maxBricks;
        levelOver = false;
    }
}

void GameManager::runGame()
{
    Menu mainMenu(this);
    mainMenu.addEntry("Play");
    mainMenu.addEntry("How to Play");
    mainMenu.addEntry("Credits");
    mainMenu.addEntry("Exit");

    Timer fpsTimer;
    Timer capTimer;

    uint32_t frameCount = 0;
    fpsTimer.start();

    while (!_quit)
    {
        window->clear();

        capTimer.start();

        switch (currentState)
        {
        case STATE_MENU:
        {
            window->renderTexture(bgTexture, 0, 0);
            mainMenu.tick();
            break;
        }
        case STATE_HOWTOPLAY:
        {
            window->renderTexture(htpTexture, 0, 0);
            listenForQuit();
            break;
        }
        case STATE_CREDITS:
        {
            window->renderTexture(bgTexture, 0, 0);
            printCredits();
            listenForQuit();
            break;
        }
        case STATE_PLAYING:
            window->renderTexture(gameBgTexture, 0, 0);
            gameTick();
            break;
        case STATE_WINNER:
        {
            window->renderTexture(bgTexture, 0, 0);
            window->renderCenteredText("YOU WON!", 100, { 0, 0, 0 }, 75, FONT_RENDER_BLENDED, { 0, 0, 0 });
            window->renderCenteredText("Final Score: " + std::to_string(calcScore()), 180, { 0, 0, 0 }, 75, FONT_RENDER_BLENDED, { 0, 0, 0 });
            listenForQuit();
            break;
        }

        default:
            Log::warn("Recieved unhandled gamestate: " + std::to_string(currentState));
            break;
        }

        // divide the amount of frames displayed by the runtime in seconds to get the average fps
        float avgFps = frameCount / (fpsTimer.getTicks() / 1000.f);
        if (avgFps > 2000000)
            avgFps = 0;

        window->renderText(std::to_string((int)avgFps), window->getWidth()-30, 0, { 0, 0, 0 }, 25, FONT_RENDER_BLENDED, { 0, 0, 0 });

        window->render();

        frameCount++;

        // if our fps it too high, wait here until we're back to ~60fps
        if (capTimer.getTicks() < (1000 / window->getMaxFps()))
        {
            int waitTime = (1000 / window->getMaxFps()) - capTimer.getTicks();
            SDL_Delay(waitTime);
        }
    }
}

void GameManager::gameTick()
{
    bool repeatKey = SDL_PollEvent(&event) == 1;

    if (levelOver)
    {
        totalBricksDestroyed += maxBricks;
        currentLevel++;
        initGame(false);
        levelOver = false;
        return;
    }

    if(ball->getLives() < 1)
    {
        totalBricksDestroyed += maxBricks - bricksLeft;

        window->renderCenteredText("GAME OVER", window->getHeight()/4, {0,0,0}, 50, FONT_RENDER_BLENDED, {255,255,255});
        window->renderCenteredText("Score: " + std::to_string(calcScore()), window->getHeight()/2, {0,0,0}, 50, FONT_RENDER_BLENDED, {255,255,255});
        listenForQuit();
        return;
    }

    switch (event.type)
    {
    // if user clicks the red X
    case SDL_QUIT:
        _quit = true;
        break;

    case SDL_KEYDOWN:
        switch (event.key.keysym.sym)
        {
        case SDLK_LEFT:
            paddle->startMoving(MOVE_LEFT);
            break;
        case SDLK_RIGHT:
            paddle->startMoving(MOVE_RIGHT);
            break;
        case SDLK_SPACE:
            if (ball->isOnPaddle())
                ball->detach();
            isPressed = true;
            break;
        case SDLK_ESCAPE:
            if (repeatKey)
            {
                setState(STATE_MENU);
                return;
            }
        }
        break;

    case SDL_KEYUP:
        switch (event.key.keysym.sym)
        {
        case SDLK_LEFT:
            paddle->stopMoving(MOVE_LEFT);
            break;
        case SDLK_RIGHT:
            paddle->stopMoving(MOVE_RIGHT);
            break;
        }
        break;
    }

	bool collidedThisTick = false;
    for (Entity* e : entities)
    {
        bool playedSound = false;
        if (e->isActive())
        {
            // don't think this is that cpu intensive but I guess it could be
            if ((ball->collidedWith(e)) && (e->isActive()) && !collidedThisTick)
            {
                collidedThisTick = true;
                ball->handleCollision(e);
                if (e->getTypeId() == TYPEID_BRICK)
                {
                    if (!((Brick*)e)->dealDamage(1))
                    {
                        bricksLeft--;
                        Mix_PlayChannel(-1, brickBreakSound, 0);
                        playedSound = true;
                    }
                    Log::info(std::to_string(bricksLeft) + " / " + std::to_string(maxBricks) + " bricks remaining");
                }

                if (!playedSound)
                    Mix_PlayChannel(-1, ballHitSound, 0);
            }
            e->update();
        }
    }

    if (ball->collidedWith(paddle))
    {
        Mix_PlayChannel(-1, ballHitSound, 0);
        ball->handleCollision(paddle);
    }
    paddle->update();

    /************** Code segment used for powerup implementation ***************/
    if(randNum == 0 && isPressed == true)
    {
        mod->update();
        if(mod->collidedWith(paddle))
        {
            mod->fastPaddle();
            paddle->setMoveRate(7);
            mod->remove();
        }
    }

    if(randNum == 1 && isPressed == true)
    {
        mod->update();
        if(mod->collidedWith(paddle))
        {
            paddle->setTexture("paddle_big.bmp");
            mod->largePaddle();
            mod->remove();
        }
    }

    if(randNum == 2 && isPressed == true)
    {
        mod->update();
        if(mod->collidedWith(paddle))
        {
            paddle->setTexture("paddle_big.bmp");
            mod->largePaddle();
            mod->remove();
        }
    }

    if(randNum == 3 && isPressed == true)
    {
        mod->update();
        if(mod->collidedWith(paddle))
        {
            paddle->setTexture("paddle_small.bmp");
            mod->smallPaddle();
            mod->remove();
        }
    }
    /***************************************************************************/

    ball->update();
    window->renderText("Lives: " + std::to_string(ball->getLives()), 0, 0, { 0, 0, 0 }, 25, FONT_RENDER_BLENDED, { 0, 0, 0 });

    if (bricksLeft == 0)
    {
        levelOver = true;
        totalBricksDestroyed += maxBricks;
    }

    /*if (showMessage)
    {
        window->renderCenteredText(message, 200, { 0, 0, 0 }, 60, FONT_RENDER_BLENDED, { 0, 0, 0 });
        if (timePassed > 5 * 1000)
            showMessage = false;
    }*/
}

void GameManager::addEntity(Entity* e)
{
	entities.push_back(e);
}

void GameManager::setState(int state)
{
    Log::info("Set state to " + std::to_string(state));
    currentState = state;
}

void GameManager::printCredits()
{
    window->renderCenteredText("Henry Gordon", 100, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
    window->renderCenteredText("Anthony Brugal", 150, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
    window->renderCenteredText("Iden Sessani", 200, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
    window->renderCenteredText("Erik Higginbotham", 250, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
    window->renderCenteredText("Aaron Hanuschak", 300, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
    window->renderCenteredText("Kurt Weber", 350, { 0, 0, 0 }, 45, FONT_RENDER_BLENDED, { 0, 0, 0 });
}

void GameManager::listenForQuit()
{
    SDL_Event currEvent;
    bool repeatKey = SDL_PollEvent(&currEvent) == 1;

    switch (currEvent.type)
    {
    // if user clicks the red X
    case SDL_QUIT:
        _quit = true;
        return;
    case SDL_KEYDOWN:
        if (repeatKey)
        {
            switch (currEvent.key.keysym.sym)
            {
            case SDLK_SPACE:
            case SDLK_RETURN:
            case SDLK_ESCAPE:
                setState(STATE_MENU);
            }
        }
    }
}

int GameManager::calcScore()
{
    return (ball->getLives() + 1) * (totalBricksDestroyed);
}
<|endoftext|>


<commit_before>#include "GameManager.h"
#include "menu/PauseMenu.h"
#include "menu/Player.h"

#include <Indie.h>

namespace Symp {

GameManager::GameManager(const char *title, int width, int height, int bpp, bool vsync, bool fs, bool dBuffer){
	//Initialize the engine
	IndieLib::init(IND_DEBUG_MODE);
	m_pWindow = new Window();
	m_pRender = new Render();
	m_pWindow->setWindow(m_pRender->init(title, width, height, bpp, vsync, fs, dBuffer));
	m_pWindow->setCursor(true);
	m_pInputManager = new InputManager(m_pRender);
	m_pParser = new Parser("../assets/data.xml");
	//m_pSoundManager = new SoundManager();
	//m_pSoundManager->loadSound("../assets/audio/test.wav"); //test sound

	//Initialize the game elements to null and start the menu
	m_pMenuManager =  nullptr;
	m_pLevelManager = nullptr;
	switchToMenu();
}

GameManager::~GameManager(){
	IndieLib::end();
	delete m_pWindow;
	delete m_pRender;
	delete m_pInputManager;
	delete m_pMenuManager;
}

/**
* @brief Displays the game when it needs to be
* This function displays the game, usually called from a menu.
* @see MenuManager
* @see updateGame()
* @see switchToMenu()
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::switchToGame(){
	//Reset the menuManager attribut
	m_pMenuManager->setLevelChoosen(false);

	EntityManager::getInstance();
	EntityManager::initRender(m_pRender);

	if (m_pLevelManager == nullptr) {
		//If no game have been created before then create a new one (from the main menu)
		m_pLevelManager = new LevelManager(EntityManager::getInstance());
		loadLevel(m_pMenuManager->getLevelToLoad().c_str());
	 	m_bIsInGame = true;
	}
	else{
		m_bIsInGame = true;
	}
}

/**
* @brief Clear the game entities and attributes for displaying the main menu
* @see MenuManager
* @see EntityManager
* @see LevelManager
* @see updateMenu()
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::clear(){
	EntityManager::getInstance()->deleteAllEntities();
	delete m_pLevelManager;
	delete m_pMenuManager;
	EntityManager::removeInstance();
	m_pMenuManager = nullptr;
	m_pLevelManager = nullptr;
}

/**
* @brief Displays the menus when it needs to be
* This function displays wether the main menu, or the PauseMenu. This function can be called in game for displaying
* again the main menus, in this case, the #GameManager needs to be cleared using the #clear() function. To display the
* game, see #switchToGame().
* @see MenuManager
* @see updateMenu()
* @see switchToGame()
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::switchToMenu(){
	//If the MenuManager doesn't exists, means at the first launch or when the user quit the game, then create it.
	if (m_pMenuManager == nullptr){

		//Retrive data from the player data file
		std::pair<Player*, std::vector<Player*>> playerData = m_pParser->loadPlayerData();

		//Start the menus
		m_pMenuManager = new MenuManager(m_pRender, playerData);
 		m_bIsInGame = false;
 		//manage Camera
		m_pRender->setCamera();
 		m_pRender->setCameraPosition(m_pWindow->getIND_Window()->getWidth()*0.5, m_pWindow->getIND_Window()->getHeight()*0.5);

 	}else {

 		//Pause menu
 		RenderEntity* pDino = EntityManager::getEntityManagerInstance()->getRenderDino();
 		PauseMenu* pPauseMenu = new PauseMenu(m_pMenuManager, pDino->getPosX(), pDino->getPosY());
 		m_pMenuManager->setState(pPauseMenu);
 		m_bIsInGame = false;
 	}
}

/**
* @brief The main loop of the game responsible the application to run
* @see updateMenu()
* @see updateGame()
* @see switchToGame()
* @see switchToMenu()
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::startMainLoop(){
	//If the user didn't closed the window or didn't clicked a "quit" button, then update
	while (!m_pMenuManager->isAboutToQuit() && !m_pInputManager->quit())
	{
		m_pInputManager->update();
 		if(m_bIsInGame) {
			updateGame();
		}
		else {
			updateMenu();
		}
	}
}

/**
* @brief Update the game part of the application each loop
* @see updateMenu()
* @see InputManager
* @see switchToGame()
* @see switchToMenu()
* @see EntityManager
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::updateGame() {
	//move dino
	RenderEntity* pDino = EntityManager::getInstance()->getRenderDino();
	if (m_pInputManager->isKeyPressed(IND_KEYLEFT)){
		pDino->setPosition(pDino->getPosX()-10, pDino->getPosY());
	}
	if (m_pInputManager->isKeyPressed(IND_KEYRIGHT)){
		pDino->setPosition(pDino->getPosX()+10, pDino->getPosY());
	}
	if (m_pInputManager->isKeyPressed(IND_KEYUP)){
		pDino->setPosition(pDino->getPosX(), pDino->getPosY()-10);
	}
	if (m_pInputManager->isKeyPressed(IND_KEYDOWN)){
		pDino->setPosition(pDino->getPosX(), pDino->getPosY()+10);
	}

	//manage Camera
	m_pRender->setCamera();
	m_pRender->setCameraPosition(pDino->getPosX(), pDino->getPosY());

	//update all list of entities
	EntityManager::getInstance()->updateEntities();

	//sound
	if (m_pInputManager->isKeyPressed(IND_SPACE)){
		//m_pSoundManager->play(0); //seg fault : still no song !
	}

	//render openGL
	m_pRender->clearViewPort(60, 60, 60);
	m_pRender->beginScene();
	EntityManager::getInstance()->renderEntities();
	m_pRender->endScene();

	//Pause
	if (m_pInputManager->onKeyPress(IND_ESCAPE)){
		switchToMenu();
	}
}

/**
* @brief Update the menu part of the application each loop
* @see updateGame()
* @see InputManager
* @see switchToGame()
* @see switchToMenu()
* @see EntityManager
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::updateMenu() {
	//manage camera
	m_pRender->setCamera();

	//Forward inputs
	if (m_pInputManager->onKeyPress(IND_KEYDOWN)){
		m_pMenuManager->handleKeyPressed("KEYDOWN");
	}
	else if (m_pInputManager->onKeyPress(IND_KEYUP)){
		m_pMenuManager->handleKeyPressed("KEYUP");
	}
	else if (m_pInputManager->isMouseMotion()){
		// Mouse hover
		m_pMenuManager->handleMouseHover(m_pInputManager->getMouseX(), m_pInputManager->getMouseY());
	}
	else if(m_pInputManager->onMouseButtonPress(IND_MBUTTON_LEFT)){
		// Clic
		m_pMenuManager->handleMouseClic(m_pInputManager->getMouseX(), m_pInputManager->getMouseY());
	}
	else if (m_pInputManager->onKeyPress(IND_ESCAPE) && m_pMenuManager->isDisplayingPauseState()){
		// Hidding the Pause menu
		m_pMenuManager->setLevelChoosen(false);
		m_bIsInGame = true;
	}

	// The PauseMenu need not to refresh the window in order to displayed upon the game view
	if(!m_pMenuManager->isDisplayingPauseState()){
		m_pRender->clearViewPort(60, 60, 60);
	}
	// Otherwise, all the menus needs to refresh the window
	m_pRender->beginScene();
	m_pMenuManager->renderEntities();
	m_pRender->endScene();

	//Manage user decisions
	if(m_pMenuManager->isLevelChoosen()){
		// If the game part needs to be launch
		switchToGame();
		m_pMenuManager->clear();
	}else if (m_pMenuManager->isGoingBackToMenu() && m_pMenuManager->isDisplayingPauseState()){
		// If the user wants to go back to the main menu from the pause menu
		m_pRender->setCameraPosition(m_pWindow->getIND_Window()->getWidth()*0.5, m_pWindow->getIND_Window()->getHeight()*0.5);
		clear();
		switchToMenu();
	}
}

void GameManager::loadLevel(const char* mapFile) {
	EntityManager::getInstance()->deleteAllEntities();
	EntityManager::getInstance()->addDino();
	m_pLevelManager->loadLevel(mapFile);
}

}
<commit_msg>minor change in GameManager<commit_after>#include "GameManager.h"
#include "menu/PauseMenu.h"
#include "menu/Player.h"

#include <Indie.h>

namespace Symp {

GameManager::GameManager(const char *title, int width, int height, int bpp, bool vsync, bool fs, bool dBuffer){
	//Initialize the engine
	IndieLib::init(IND_DEBUG_MODE);
	m_pWindow = new Window();
	m_pRender = new Render();
	m_pWindow->setWindow(m_pRender->init(title, width, height, bpp, vsync, fs, dBuffer));
	m_pWindow->setCursor(true);
	m_pInputManager = new InputManager(m_pRender);
	m_pParser = new Parser("../assets/data.xml");
	//m_pSoundManager = new SoundManager();
	//m_pSoundManager->loadSound("../assets/audio/test.wav"); //test sound

	//Initialize the game elements to null and start the menu
	m_pMenuManager =  nullptr;
	m_pLevelManager = nullptr;
	switchToMenu();
}

GameManager::~GameManager(){
	IndieLib::end();
	delete m_pWindow;
	delete m_pRender;
	delete m_pInputManager;
	delete m_pMenuManager;
}

/**
* @brief Displays the game when it needs to be
* This function displays the game, usually called from a menu.
* @see MenuManager
* @see updateGame()
* @see switchToMenu()
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::switchToGame(){
	//Reset the menuManager attribut
	m_pMenuManager->setLevelChoosen(false);

	EntityManager::getInstance();
	EntityManager::initRender(m_pRender);

	if (m_pLevelManager == nullptr) {
		//If no game have been created before then create a new one (from the main menu)
		m_pLevelManager = new LevelManager(EntityManager::getInstance());
		loadLevel(m_pMenuManager->getLevelToLoad().c_str());
	 	m_bIsInGame = true;
	}
	else{
		m_bIsInGame = true;
	}
}

/**
* @brief Clear the game entities and attributes for displaying the main menu
* @see MenuManager
* @see EntityManager
* @see LevelManager
* @see updateMenu()
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::clear(){
	EntityManager::getInstance()->deleteAllEntities();
	delete m_pLevelManager;
	delete m_pMenuManager;
	EntityManager::removeInstance();
	m_pMenuManager = nullptr;
	m_pLevelManager = nullptr;
}

/**
* @brief Displays the menus when it needs to be
* This function displays wether the main menu, or the PauseMenu. This function can be called in game for displaying
* again the main menus, in this case, the #GameManager needs to be cleared using the #clear() function. To display the
* game, see #switchToGame().
* @see MenuManager
* @see updateMenu()
* @see switchToGame()
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::switchToMenu(){
	//If the MenuManager doesn't exists, means at the first launch or when the user quit the game, then create it.
	if (m_pMenuManager == nullptr){

		//Retrive data from the player data file
		std::pair<Player*, std::vector<Player*>> playerData = m_pParser->loadPlayerData();

		//Start the menus
		m_pMenuManager = new MenuManager(m_pRender, playerData);
 		m_bIsInGame = false;
 		//manage Camera
		m_pRender->setCamera();
 		m_pRender->setCameraPosition(m_pWindow->getIND_Window()->getWidth()*0.5, m_pWindow->getIND_Window()->getHeight()*0.5);

 	}else {

 		//Pause menu
 		RenderEntity* pDino = EntityManager::getInstance()->getRenderDino();
 		PauseMenu* pPauseMenu = new PauseMenu(m_pMenuManager, pDino->getPosX(), pDino->getPosY());
 		m_pMenuManager->setState(pPauseMenu);
 		m_bIsInGame = false;
 	}
}

/**
* @brief The main loop of the game responsible the application to run
* @see updateMenu()
* @see updateGame()
* @see switchToGame()
* @see switchToMenu()
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::startMainLoop(){
	//If the user didn't closed the window or didn't clicked a "quit" button, then update
	while (!m_pMenuManager->isAboutToQuit() && !m_pInputManager->quit())
	{
		m_pInputManager->update();
 		if(m_bIsInGame) {
			updateGame();
		}
		else {
			updateMenu();
		}
	}
}

/**
* @brief Update the game part of the application each loop
* @see updateMenu()
* @see InputManager
* @see switchToGame()
* @see switchToMenu()
* @see EntityManager
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::updateGame() {
	//move dino
	RenderEntity* pDino = EntityManager::getInstance()->getRenderDino();
	if (m_pInputManager->isKeyPressed(IND_KEYLEFT)){
		pDino->setPosition(pDino->getPosX()-10, pDino->getPosY());
	}
	if (m_pInputManager->isKeyPressed(IND_KEYRIGHT)){
		pDino->setPosition(pDino->getPosX()+10, pDino->getPosY());
	}
	if (m_pInputManager->isKeyPressed(IND_KEYUP)){
		pDino->setPosition(pDino->getPosX(), pDino->getPosY()-10);
	}
	if (m_pInputManager->isKeyPressed(IND_KEYDOWN)){
		pDino->setPosition(pDino->getPosX(), pDino->getPosY()+10);
	}

	//manage Camera
	m_pRender->setCamera();
	m_pRender->setCameraPosition(pDino->getPosX(), pDino->getPosY());

	//update all list of entities
	EntityManager::getInstance()->updateEntities();

	//sound
	if (m_pInputManager->isKeyPressed(IND_SPACE)){
		//m_pSoundManager->play(0); //seg fault : still no song !
	}

	//render openGL
	m_pRender->clearViewPort(60, 60, 60);
	m_pRender->beginScene();
	EntityManager::getInstance()->renderEntities();
	m_pRender->endScene();

	//Pause
	if (m_pInputManager->onKeyPress(IND_ESCAPE)){
		switchToMenu();
	}
}

/**
* @brief Update the menu part of the application each loop
* @see updateGame()
* @see InputManager
* @see switchToGame()
* @see switchToMenu()
* @see EntityManager
* @see GameManager()
* @see ~GameManager()
*/
void GameManager::updateMenu() {
	//manage camera
	m_pRender->setCamera();

	//Forward inputs
	if (m_pInputManager->onKeyPress(IND_KEYDOWN)){
		m_pMenuManager->handleKeyPressed("KEYDOWN");
	}
	else if (m_pInputManager->onKeyPress(IND_KEYUP)){
		m_pMenuManager->handleKeyPressed("KEYUP");
	}
	else if (m_pInputManager->isMouseMotion()){
		// Mouse hover
		m_pMenuManager->handleMouseHover(m_pInputManager->getMouseX(), m_pInputManager->getMouseY());
	}
	else if(m_pInputManager->onMouseButtonPress(IND_MBUTTON_LEFT)){
		// Clic
		m_pMenuManager->handleMouseClic(m_pInputManager->getMouseX(), m_pInputManager->getMouseY());
	}
	else if (m_pInputManager->onKeyPress(IND_ESCAPE) && m_pMenuManager->isDisplayingPauseState()){
		// Hidding the Pause menu
		m_pMenuManager->setLevelChoosen(false);
		m_bIsInGame = true;
	}

	// The PauseMenu need not to refresh the window in order to displayed upon the game view
	if(!m_pMenuManager->isDisplayingPauseState()){
		m_pRender->clearViewPort(60, 60, 60);
	}
	// Otherwise, all the menus needs to refresh the window
	m_pRender->beginScene();
	m_pMenuManager->renderEntities();
	m_pRender->endScene();

	//Manage user decisions
	if(m_pMenuManager->isLevelChoosen()){
		// If the game part needs to be launch
		switchToGame();
		m_pMenuManager->clear();
	}else if (m_pMenuManager->isGoingBackToMenu() && m_pMenuManager->isDisplayingPauseState()){
		// If the user wants to go back to the main menu from the pause menu
		m_pRender->setCameraPosition(m_pWindow->getIND_Window()->getWidth()*0.5, m_pWindow->getIND_Window()->getHeight()*0.5);
		clear();
		switchToMenu();
	}
}

void GameManager::loadLevel(const char* mapFile) {
	EntityManager::getInstance()->deleteAllEntities();
	EntityManager::getInstance()->addDino();
	m_pLevelManager->loadLevel(mapFile);
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include "GameManager.h"
#include "Log.h"
#include "Timer.h"

GameManager::GameManager(Window* window):
    window(window)
{
    currentState = STATE_PLAYING;
    _quit = false;
}

void GameManager::runGame()
{
    Entity* paddle = new Entity(window, "paddle.bmp", 305, 400);
    paddle->setMoveRate(5);
    entities.push_back(paddle);

    ball = new Ball(window, "ball.bmp", window->getWidth() / 2, window->getHeight() / 2, paddle);
    ball->setOnPaddle(true);

    powerup = new Mods(window, "PowerUP.bmp", 305, 0 );	// makes a new power up object
	powerdown = new Mods(window, "PowerUP.bmp", 305, 0 );//makes a new power down object

    Timer fpsTimer;
    Timer capTimer;

    uint32_t frameCount = 0;
    fpsTimer.start();

    while (!_quit)
    {

        capTimer.start();

        switch (currentState)
        {
        case STATE_MENU:
            break;
        case STATE_SETTINGS:
            break;
        case STATE_PLAYING:
            gameTick();
            break;
        }

        window->render();

        frameCount++;

        // if our fps it too high, wait here until we're back to ~60fps
        if (capTimer.getTicks() < (1000 / window->getMaxFps()))
            SDL_Delay((1000 / window->getMaxFps()) - capTimer.getTicks());
    }
}

void GameManager::gameTick()
{

    SDL_PollEvent(&event);

    // paddle is always added to the entities vector first, so this is fine
    Entity* paddle = entities[0];

    switch (event.type)
    {
    // if user clicks the red X
    case SDL_QUIT:
        _quit = true;
        break;

    case SDL_KEYDOWN:
        switch (event.key.keysym.sym)
        {
        case SDLK_LEFT:
            paddle->startMoving(MOVE_LEFT);
            break;
        case SDLK_RIGHT:
            paddle->startMoving(MOVE_RIGHT);
            break;
        case SDLK_SPACE:
            ball->detach();
            break;
        }
        break;

    case SDL_KEYUP:
        switch (event.key.keysym.sym)
        {
        case SDLK_LEFT:
            paddle->stopMoving(MOVE_LEFT);
            break;
        case SDLK_RIGHT:
            paddle->stopMoving(MOVE_RIGHT);
            break;
        }
        break;
    }

    window->clear();

    for (Entity* e : entities)
    {
        // don't think this is that cpu intensive but I guess it could be
        if (ball->collidedWith(e))
            ball->handleCollision(e);

        e->update();
    }
    ball->update();
    powerup->update();

}
<commit_msg>Testing shit.<commit_after>#include <iostream>
#include "GameManager.h"
#include "Log.h"
#include "Timer.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

GameManager::GameManager(Window* window):
    window(window)
{
    currentState = STATE_PLAYING;
    _quit = false;
}

void GameManager::runGame()
{
    Entity* paddle = new Entity(window, "paddle.bmp", 305, 400);
    paddle->setMoveRate(5);
    entities.push_back(paddle);

    ball = new Ball(window, "ball.bmp", window->getWidth() / 2, window->getHeight() / 2, paddle);
    ball->setOnPaddle(true);

    powerup = new Mods(window, "PowerUP.bmp", 305, 0 );	// makes a new power up object
	  powerdown = new Mods(window, "PowerUP.bmp", 305, 0 );//makes a new power down object

    Timer fpsTimer;
    Timer capTimer;

    uint32_t frameCount = 0;
    fpsTimer.start();

    while (!_quit)
    {

        capTimer.start();

        switch (currentState)
        {
        case STATE_MENU:
            break;
        case STATE_SETTINGS:
            break;
        case STATE_PLAYING:
            gameTick();
            break;
        }

        window->render();

        frameCount++;

        // if our fps it too high, wait here until we're back to ~60fps
        if (capTimer.getTicks() < (1000 / window->getMaxFps()))
            SDL_Delay((1000 / window->getMaxFps()) - capTimer.getTicks());
    }
}

void GameManager::gameTick()
{

    SDL_PollEvent(&event);

    // paddle is always added to the entities vector first, so this is fine
    Entity* paddle = entities[0];

    switch (event.type)
    {
    // if user clicks the red X
    case SDL_QUIT:
        _quit = true;
        break;

    case SDL_KEYDOWN:
        switch (event.key.keysym.sym)
        {
        case SDLK_LEFT:
            paddle->startMoving(MOVE_LEFT);
            break;
        case SDLK_RIGHT:
            paddle->startMoving(MOVE_RIGHT);
            break;
        case SDLK_SPACE:
            ball->detach();
            break;
        }
        break;

    case SDL_KEYUP:
        switch (event.key.keysym.sym)
        {
        case SDLK_LEFT:
            paddle->stopMoving(MOVE_LEFT);
            break;
        case SDLK_RIGHT:
            paddle->stopMoving(MOVE_RIGHT);
            break;
        }
        break;
    }

    window->clear();

    for (Entity* e : entities)
    {
        // don't think this is that cpu intensive but I guess it could be
        if (ball->collidedWith(e))
            ball->handleCollision(e);

        e->update();
    }
    ball->update();

    srand(time(NULL));
    int x = rand()%2;
    if(x==1)
      powerup->update();
    else if(x==0)
      powerdown->update();

}
<|endoftext|>


<commit_before>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Bohrium is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <vector>
#include <iostream>
#include <boost/functional/hash.hpp>

#include <jitk/kernel.hpp>

#include "engine_opencl.hpp"

using namespace std;

namespace {

#define CL_DEVICE_AUTO 1024 // More than maximum in the bitmask

map<const string, cl_device_type> device_map = {
    {"auto",        CL_DEVICE_AUTO},
    {"gpu",         CL_DEVICE_TYPE_GPU},
    {"accelerator", CL_DEVICE_TYPE_ACCELERATOR},
    {"default",     CL_DEVICE_TYPE_DEFAULT},
    {"cpu",         CL_DEVICE_TYPE_CPU}
};

// Get the OpenCL device (search order: GPU, ACCELERATOR, DEFAULT, and CPU)
cl::Device getDevice(const cl::Platform &platform, const string &default_device_type) {
    vector<cl::Device> device_list;
    platform.getDevices(CL_DEVICE_TYPE_ALL, &device_list);

    if(device_list.size() == 0){
        throw runtime_error("No OpenCL device found");
    }

    if (!util::exist(device_map, default_device_type)) {
        stringstream ss;
        ss << "'" << default_device_type << "' is not a OpenCL device type. " \
           << "Must be one of 'auto', 'gpu', 'accelerator', 'cpu', or 'default'";
        throw runtime_error(ss.str());
    } else if (device_map[default_device_type] != CL_DEVICE_AUTO) {
        for (auto &device: device_list) {
            if ((device.getInfo<CL_DEVICE_TYPE>() & device_map[default_device_type]) == device_map[default_device_type]) {
                return device;
            }
        }
        stringstream ss;
        ss << "Could not find selected OpenCL device type ('" \
           << default_device_type << "') on default platform";
        throw runtime_error(ss.str());
    }

    // Type was 'auto'
    for (auto &device_type: device_map) {
        for (auto &device: device_list) {
            if ((device.getInfo<CL_DEVICE_TYPE>() & device_type.second) == device_type.second) {
                return device;
            }
        }
    }

    throw runtime_error("No OpenCL device of usable type found");
}
}

namespace bohrium {

static boost::hash<string> hasher;

EngineOpenCL::EngineOpenCL(const ConfigParser &config, jitk::Statistics &stat) :
                                    work_group_size_1dx(config.defaultGet<int>("work_group_size_1dx", 128)),
                                    work_group_size_2dx(config.defaultGet<int>("work_group_size_2dx", 32)),
                                    work_group_size_2dy(config.defaultGet<int>("work_group_size_2dy", 4)),
                                    work_group_size_3dx(config.defaultGet<int>("work_group_size_3dx", 32)),
                                    work_group_size_3dy(config.defaultGet<int>("work_group_size_3dy", 2)),
                                    work_group_size_3dz(config.defaultGet<int>("work_group_size_3dz", 2)),
                                    compile_flg(config.defaultGet<string>("compiler_flg", "")),
                                    default_device_type(config.defaultGet<string>("device_type", "auto")),
                                    platform_no(config.defaultGet<int>("platform_no", -1)),
                                    verbose(config.defaultGet<bool>("verbose", false)),
                                    stat(stat) {
    vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);
    if(platforms.size() == 0) {
        throw runtime_error("No OpenCL platforms found");
    }

    bool found = false;
    cl::Platform platform;
    if (platform_no == -1) {
        for (auto pform : platforms) {
            // Pick first valid platform
            try {
                // Get the device of the platform
                platform = pform;
                device = getDevice(platform, default_device_type);
                found = true;
            } catch(cl::Error err) {
                // We try next platform
            }
        }
    } else {
        if (platform_no > ((int) platforms.size()-1)) {
            std::stringstream ss;
            ss << "No such OpenCL platform. Tried to fetch #";
            ss << platform_no << " out of ";
            ss << platforms.size()-1 << "." << endl;
            throw std::runtime_error(ss.str());
        }

        platform = platforms[platform_no];
        device = getDevice(platform, default_device_type);
        found = true;
    }

    if (verbose) {
        cout << "Using platform: " << platform.getInfo<CL_PLATFORM_NAME>() << endl;
    }

    if (!found) {
        throw runtime_error("Invalid OpenCL device/platform");
    }

    if(verbose) {
        cout << "Using device: " << device.getInfo<CL_DEVICE_NAME>() \
             << " ("<< device.getInfo<CL_DEVICE_OPENCL_C_VERSION>() << ")" << endl;
    }

    vector<cl::Device> dev_list = {device};
    context = cl::Context(dev_list);
    queue = cl::CommandQueue(context, device);
}

pair<cl::NDRange, cl::NDRange> EngineOpenCL::NDRanges(const vector<const jitk::LoopB*> &threaded_blocks) const {
    const auto &b = threaded_blocks;
    switch (b.size()) {
        case 1:
        {
            const cl_ulong lsize = work_group_size_1dx;
            const cl_ulong rem = b[0]->size % lsize;
            const cl_ulong gsize = b[0]->size + (rem==0?0:(lsize-rem));
            return make_pair(cl::NDRange(gsize), cl::NDRange(lsize));
        }
        case 2:
        {
            const cl_ulong lsize_x = work_group_size_2dx;
            const cl_ulong lsize_y = work_group_size_2dy;
            const cl_ulong rem_x = b[0]->size % lsize_x;
            const cl_ulong rem_y = b[1]->size % lsize_y;
            const cl_ulong gsize_x = b[0]->size + (rem_x==0?0:(lsize_x-rem_x));
            const cl_ulong gsize_y = b[1]->size + (rem_y==0?0:(lsize_y-rem_y));
            return make_pair(cl::NDRange(gsize_x, gsize_y), cl::NDRange(lsize_x, lsize_y));
        }
        case 3:
        {
            const cl_ulong lsize_x = work_group_size_3dx;
            const cl_ulong lsize_y = work_group_size_3dy;
            const cl_ulong lsize_z = work_group_size_3dz;
            const cl_ulong rem_x = b[0]->size % lsize_x;
            const cl_ulong rem_y = b[1]->size % lsize_y;
            const cl_ulong rem_z = b[2]->size % lsize_z;
            const cl_ulong gsize_x = b[0]->size + (rem_x==0?0:(lsize_x-rem_x));
            const cl_ulong gsize_y = b[1]->size + (rem_y==0?0:(lsize_y-rem_y));
            const cl_ulong gsize_z = b[2]->size + (rem_z==0?0:(lsize_z-rem_z));
            return make_pair(cl::NDRange(gsize_x, gsize_y, gsize_z), cl::NDRange(lsize_x, lsize_y, lsize_z));
        }
        default:
            throw runtime_error("NDRanges: maximum of three dimensions!");
    }
}

void EngineOpenCL::execute(const std::string &source, const jitk::Kernel &kernel,
                           const vector<const jitk::LoopB*> &threaded_blocks,
                           const vector<const bh_view*> &offset_strides,
                           const vector<const bh_instruction*> &constants) {
    size_t hash = hasher(source);
    ++stat.kernel_cache_lookups;
    cl::Program program;

    auto tcompile = chrono::steady_clock::now();

    // Do we have the program already?
    if (_programs.find(hash) != _programs.end()) {
        program = _programs.at(hash);
    } else {
        // Or do we have to compile it
        ++stat.kernel_cache_misses;
        program = cl::Program(context, source);
        try {
            if (verbose) {
                cout << "********** Compile Flags **********" << endl \
                << compile_flg.c_str() << endl \
                << "************ Flags END ************" << endl << endl;
                cout << "************ Build Log ************" << endl \
                 << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device) \
                 << "^^^^^^^^^^^^^ Log END ^^^^^^^^^^^^^" << endl << endl;
            }
            program.build({device}, compile_flg.c_str());
        } catch (cl::Error e) {
            cerr << "Error building: " << endl << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device) << endl;
            throw;
        }
        _programs[hash] = program;
    }
    stat.time_compile += chrono::steady_clock::now() - tcompile;

    // Let's execute the OpenCL kernel
    cl::Kernel opencl_kernel = cl::Kernel(program, "execute");
    {
        cl_uint i = 0;
        for (bh_base *base: kernel.getNonTemps()) { // NB: the iteration order matters!
            opencl_kernel.setArg(i++, *buffers.at(base));
        }
        for (const bh_view *view: offset_strides) {
            uint64_t t1 = (uint64_t) view->start;
            opencl_kernel.setArg(i++, t1);
            for (int j=0; j<view->ndim; ++j) {
                uint64_t t2 = (uint64_t) view->stride[j];
                opencl_kernel.setArg(i++, t2);
            }
        }
        for (const bh_instruction *instr: constants) {
            switch (instr->constant.type)
            {
                case BH_BOOL:
                    opencl_kernel.setArg(i++, instr->constant.value.bool8);
                    break;
                case BH_INT8:
                    opencl_kernel.setArg(i++, instr->constant.value.int8);
                    break;
                case BH_INT16:
                    opencl_kernel.setArg(i++, instr->constant.value.int16);
                    break;
                case BH_INT32:
                    opencl_kernel.setArg(i++, instr->constant.value.int32);
                    break;
                case BH_INT64:
                    opencl_kernel.setArg(i++, instr->constant.value.int64);
                    break;
                case BH_UINT8:
                    opencl_kernel.setArg(i++, instr->constant.value.uint8);
                    break;
                case BH_UINT16:
                    opencl_kernel.setArg(i++, instr->constant.value.uint16);
                    break;
                case BH_UINT32:
                    opencl_kernel.setArg(i++, instr->constant.value.uint32);
                    break;
                case BH_UINT64:
                    opencl_kernel.setArg(i++, instr->constant.value.uint64);
                    break;
                case BH_FLOAT32:
                    opencl_kernel.setArg(i++, instr->constant.value.float32);
                    break;
                case BH_FLOAT64:
                    opencl_kernel.setArg(i++, instr->constant.value.float64);
                    break;
                case BH_COMPLEX64:
                    opencl_kernel.setArg(i++, instr->constant.value.complex64);
                    break;
                case BH_COMPLEX128:
                    opencl_kernel.setArg(i++, instr->constant.value.complex128);
                    break;
                default:
                    std::cerr << "Unknown OpenCL type: " << bh_type_text(instr->constant.type) << std::endl;
                    throw std::runtime_error("Unknown OpenCL type");
            }
        }
    }
    const auto ranges = NDRanges(threaded_blocks);
    auto texec = chrono::steady_clock::now();
    queue.enqueueNDRangeKernel(opencl_kernel, cl::NullRange, ranges.first, ranges.second);
    queue.finish();
    stat.time_exec += chrono::steady_clock::now() - texec;
}

} // bohrium
<commit_msg>Various clean up :lipstick:<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Bohrium is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <vector>
#include <iostream>
#include <boost/functional/hash.hpp>

#include <jitk/kernel.hpp>

#include "engine_opencl.hpp"

using namespace std;

namespace {

#define CL_DEVICE_AUTO 1024 // More than maximum in the bitmask

map<const string, cl_device_type> device_map = {
    {"auto",        CL_DEVICE_AUTO},
    {"gpu",         CL_DEVICE_TYPE_GPU},
    {"accelerator", CL_DEVICE_TYPE_ACCELERATOR},
    {"default",     CL_DEVICE_TYPE_DEFAULT},
    {"cpu",         CL_DEVICE_TYPE_CPU}
};

// Get the OpenCL device (search order: GPU, ACCELERATOR, DEFAULT, and CPU)
cl::Device getDevice(const cl::Platform &platform, const string &default_device_type) {
    vector<cl::Device> device_list;
    platform.getDevices(CL_DEVICE_TYPE_ALL, &device_list);

    if(device_list.size() == 0){
        throw runtime_error("No OpenCL device found");
    }

    if (!util::exist(device_map, default_device_type)) {
        stringstream ss;
        ss << "'" << default_device_type << "' is not a OpenCL device type. " \
           << "Must be one of 'auto', 'gpu', 'accelerator', 'cpu', or 'default'";
        throw runtime_error(ss.str());
    } else if (device_map[default_device_type] != CL_DEVICE_AUTO) {
        for (auto &device: device_list) {
            if ((device.getInfo<CL_DEVICE_TYPE>() & device_map[default_device_type]) == device_map[default_device_type]) {
                return device;
            }
        }
        stringstream ss;
        ss << "Could not find selected OpenCL device type ('" \
           << default_device_type << "') on default platform";
        throw runtime_error(ss.str());
    }

    // Type was 'auto'
    for (auto &device_type: device_map) {
        for (auto &device: device_list) {
            if ((device.getInfo<CL_DEVICE_TYPE>() & device_type.second) == device_type.second) {
                return device;
            }
        }
    }

    throw runtime_error("No OpenCL device of usable type found");
}
}

namespace bohrium {

static boost::hash<string> hasher;

EngineOpenCL::EngineOpenCL(const ConfigParser &config, jitk::Statistics &stat) :
                                    work_group_size_1dx(config.defaultGet<int>("work_group_size_1dx", 128)),
                                    work_group_size_2dx(config.defaultGet<int>("work_group_size_2dx", 32)),
                                    work_group_size_2dy(config.defaultGet<int>("work_group_size_2dy", 4)),
                                    work_group_size_3dx(config.defaultGet<int>("work_group_size_3dx", 32)),
                                    work_group_size_3dy(config.defaultGet<int>("work_group_size_3dy", 2)),
                                    work_group_size_3dz(config.defaultGet<int>("work_group_size_3dz", 2)),
                                    compile_flg(config.defaultGet<string>("compiler_flg", "")),
                                    default_device_type(config.defaultGet<string>("device_type", "auto")),
                                    platform_no(config.defaultGet<int>("platform_no", -1)),
                                    verbose(config.defaultGet<bool>("verbose", false)),
                                    stat(stat) {
    vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);
    if(platforms.size() == 0) {
        throw runtime_error("No OpenCL platforms found");
    }

    bool found = false;
    cl::Platform platform;
    if (platform_no == -1) {
        for (auto pform : platforms) {
            // Pick first valid platform
            try {
                // Get the device of the platform
                platform = pform;
                device = getDevice(platform, default_device_type);
                found = true;
            } catch(cl::Error err) {
                // We try next platform
            }
        }
    } else {
        if (platform_no > ((int) platforms.size()-1)) {
            std::stringstream ss;
            ss << "No such OpenCL platform. Tried to fetch #";
            ss << platform_no << " out of ";
            ss << platforms.size()-1 << "." << endl;
            throw std::runtime_error(ss.str());
        }

        platform = platforms[platform_no];
        device = getDevice(platform, default_device_type);
        found = true;
    }

    if (verbose) {
        cout << "Using platform: " << platform.getInfo<CL_PLATFORM_NAME>() << endl;
    }

    if (!found) {
        throw runtime_error("Invalid OpenCL device/platform");
    }

    if(verbose) {
        cout << "Using device: " << device.getInfo<CL_DEVICE_NAME>() \
             << " ("<< device.getInfo<CL_DEVICE_OPENCL_C_VERSION>() << ")" << endl;
    }

    context = cl::Context(device);
    queue = cl::CommandQueue(context, device);
}

pair<cl::NDRange, cl::NDRange> EngineOpenCL::NDRanges(const vector<const jitk::LoopB*> &threaded_blocks) const {
    const auto &b = threaded_blocks;
    switch (b.size()) {
        case 1:
        {
            const cl_ulong lsize = work_group_size_1dx;
            const cl_ulong rem = b[0]->size % lsize;
            const cl_ulong gsize = b[0]->size + (rem==0?0:(lsize-rem));
            return make_pair(cl::NDRange(gsize), cl::NDRange(lsize));
        }
        case 2:
        {
            const cl_ulong lsize_x = work_group_size_2dx;
            const cl_ulong lsize_y = work_group_size_2dy;
            const cl_ulong rem_x = b[0]->size % lsize_x;
            const cl_ulong rem_y = b[1]->size % lsize_y;
            const cl_ulong gsize_x = b[0]->size + (rem_x==0?0:(lsize_x-rem_x));
            const cl_ulong gsize_y = b[1]->size + (rem_y==0?0:(lsize_y-rem_y));
            return make_pair(cl::NDRange(gsize_x, gsize_y), cl::NDRange(lsize_x, lsize_y));
        }
        case 3:
        {
            const cl_ulong lsize_x = work_group_size_3dx;
            const cl_ulong lsize_y = work_group_size_3dy;
            const cl_ulong lsize_z = work_group_size_3dz;
            const cl_ulong rem_x = b[0]->size % lsize_x;
            const cl_ulong rem_y = b[1]->size % lsize_y;
            const cl_ulong rem_z = b[2]->size % lsize_z;
            const cl_ulong gsize_x = b[0]->size + (rem_x==0?0:(lsize_x-rem_x));
            const cl_ulong gsize_y = b[1]->size + (rem_y==0?0:(lsize_y-rem_y));
            const cl_ulong gsize_z = b[2]->size + (rem_z==0?0:(lsize_z-rem_z));
            return make_pair(cl::NDRange(gsize_x, gsize_y, gsize_z), cl::NDRange(lsize_x, lsize_y, lsize_z));
        }
        default:
            throw runtime_error("NDRanges: maximum of three dimensions!");
    }
}

void EngineOpenCL::execute(const std::string &source, const jitk::Kernel &kernel,
                           const vector<const jitk::LoopB*> &threaded_blocks,
                           const vector<const bh_view*> &offset_strides,
                           const vector<const bh_instruction*> &constants) {
    size_t hash = hasher(source);
    ++stat.kernel_cache_lookups;
    cl::Program program;

    auto tcompile = chrono::steady_clock::now();

    // Do we have the program already?
    if (_programs.find(hash) != _programs.end()) {
        program = _programs.at(hash);
    } else {
        // Or do we have to compile it
        ++stat.kernel_cache_misses;
        program = cl::Program(context, source);
        try {
            if (verbose) {
                cout << "********** Compile Flags **********" << endl \
                << compile_flg.c_str() << endl \
                << "************ Flags END ************" << endl << endl;
                cout << "************ Build Log ************" << endl \
                 << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device) \
                 << "^^^^^^^^^^^^^ Log END ^^^^^^^^^^^^^" << endl << endl;
            }
            program.build({device}, compile_flg.c_str());
        } catch (cl::Error e) {
            cerr << "Error building: " << endl << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device) << endl;
            throw;
        }
        _programs[hash] = program;
    }
    stat.time_compile += chrono::steady_clock::now() - tcompile;

    // Let's execute the OpenCL kernel
    cl::Kernel opencl_kernel = cl::Kernel(program, "execute");

    cl_uint i = 0;
    for (bh_base *base: kernel.getNonTemps()) { // NB: the iteration order matters!
        opencl_kernel.setArg(i++, *getBuffer(base));
    }

    for (const bh_view *view: offset_strides) {
        uint64_t t1 = (uint64_t) view->start;
        opencl_kernel.setArg(i++, t1);
        for (int j=0; j<view->ndim; ++j) {
            uint64_t t2 = (uint64_t) view->stride[j];
            opencl_kernel.setArg(i++, t2);
        }
    }

    for (const bh_instruction *instr: constants) {
        switch (instr->constant.type) {
            case BH_BOOL:
                opencl_kernel.setArg(i++, instr->constant.value.bool8);
                break;
            case BH_INT8:
                opencl_kernel.setArg(i++, instr->constant.value.int8);
                break;
            case BH_INT16:
                opencl_kernel.setArg(i++, instr->constant.value.int16);
                break;
            case BH_INT32:
                opencl_kernel.setArg(i++, instr->constant.value.int32);
                break;
            case BH_INT64:
                opencl_kernel.setArg(i++, instr->constant.value.int64);
                break;
            case BH_UINT8:
                opencl_kernel.setArg(i++, instr->constant.value.uint8);
                break;
            case BH_UINT16:
                opencl_kernel.setArg(i++, instr->constant.value.uint16);
                break;
            case BH_UINT32:
                opencl_kernel.setArg(i++, instr->constant.value.uint32);
                break;
            case BH_UINT64:
                opencl_kernel.setArg(i++, instr->constant.value.uint64);
                break;
            case BH_FLOAT32:
                opencl_kernel.setArg(i++, instr->constant.value.float32);
                break;
            case BH_FLOAT64:
                opencl_kernel.setArg(i++, instr->constant.value.float64);
                break;
            case BH_COMPLEX64:
                opencl_kernel.setArg(i++, instr->constant.value.complex64);
                break;
            case BH_COMPLEX128:
                opencl_kernel.setArg(i++, instr->constant.value.complex128);
                break;
            default:
                std::cerr << "Unknown OpenCL type: " << bh_type_text(instr->constant.type) << std::endl;
                throw std::runtime_error("Unknown OpenCL type");
        }
    }

    const auto ranges = NDRanges(threaded_blocks);
    auto texec = chrono::steady_clock::now();
    queue.enqueueNDRangeKernel(opencl_kernel, cl::NullRange, ranges.first, ranges.second);
    queue.finish();
    stat.time_exec += chrono::steady_clock::now() - texec;
}

} // bohrium
<|endoftext|>


<commit_before><commit_msg>WaE: C4190 for extern "C" functions returning C++ type<commit_after><|endoftext|>


<commit_before><commit_msg>Fixes for OSX float differences from Windows.<commit_after><|endoftext|>