import glm
import math

from lib.opengl import RenderSettings


class GameProjection:

    def __init__(self, rs: "GameRenderSettings"):
        self.rs = rs
        self.scale = 10.
        self.rotation_deg = 0.
        self.location = glm.vec3(0)
        self._stack = []

    def projection_matrix_4(self) -> glm.mat4:
        scale = 1.
        ratio = self.rs.render_width / self.rs.render_height
        m = glm.ortho(-scale * ratio, scale * ratio, -scale, scale, -10, 10)
        return m

    def transformation_matrix_4(self) -> glm.mat4:
        m = glm.rotate(
            glm.mat4(1), -self.rotation_deg / 180 * glm.pi(), glm.vec3(0, 0, 1)
        )
        m = m * glm.scale(glm.mat4(), glm.vec3(2. / self.scale))
        m = m * glm.translate(glm.mat4(), glm.vec3(-self.location.x, -self.location.y, 0))
        return m

    def transformation_matrix(self) -> glm.mat3:
        m = rotation_matrix_2d(self.rotation_deg)
        m *= self.scale * .5
        m[2][0] = self.location.x
        m[2][1] = self.location.y
        return m

    def push(self):
        self._stack.append({
            "scale": self.scale,
            "rotation": self.rotation_deg,
            "location": self.location.__copy__(),
        })

    def pop(self):
        s = self._stack.pop(-1)
        self.scale = s["scale"]
        self.rotation_deg = s["rotation"]
        self.location = s["location"]

    def __enter__(self):
        self.push()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.pop()


def rotation_matrix_2d(degree: float) -> glm.mat3:
    a = degree / 180. * math.pi
    sa = math.sin(a)
    ca = math.cos(a)
    return glm.mat3(
        ca, sa, 0,
        -sa, ca, 0,
        0, 0, 1
    )


class GameRenderSettings(RenderSettings):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.projection = GameProjection(self)

[((60, 9, 60, 20), 'math.sin', 'math.sin', ({(60, 18, 60, 19): 'a'}, {}), '(a)', False, 'import math\n'), ((61, 9, 61, 20), 'math.cos', 'math.cos', ({(61, 18, 61, 19): 'a'}, {}), '(a)', False, 'import math\n'), ((62, 11, 66, 5), 'glm.mat3', 'glm.mat3', ({(63, 8, 63, 10): 'ca', (63, 12, 63, 14): 'sa', (63, 16, 63, 17): '(0)', (64, 8, 64, 11): '(-sa)', (64, 13, 64, 15): 'ca', (64, 17, 64, 18): '(0)', (65, 8, 65, 9): '(0)', (65, 11, 65, 12): '(0)', (65, 14, 65, 15): '(1)'}, {}), '(ca, sa, 0, -sa, ca, 0, 0, 0, 1)', False, 'import glm\n'), ((13, 24, 13, 35), 'glm.vec3', 'glm.vec3', ({(13, 33, 13, 34): '0'}, {}), '(0)', False, 'import glm\n'), ((19, 12, 19, 76), 'glm.ortho', 'glm.ortho', ({(19, 22, 19, 36): '-scale * ratio', (19, 38, 19, 51): 'scale * ratio', (19, 53, 19, 59): '-scale', (19, 61, 19, 66): 'scale', (19, 68, 19, 71): '-10', (19, 73, 19, 75): '10'}, {}), '(-scale * ratio, scale * ratio, -scale, scale, -10, 10)', False, 'import glm\n'), ((24, 12, 24, 23), 'glm.mat4', 'glm.mat4', ({(24, 21, 24, 22): '1'}, {}), '(1)', False, 'import glm\n'), ((24, 62, 24, 79), 'glm.vec3', 'glm.vec3', ({(24, 71, 24, 72): '0', (24, 74, 24, 75): '0', (24, 77, 24, 78): '1'}, {}), '(0, 0, 1)', False, 'import glm\n'), ((24, 52, 24, 60), 'glm.pi', 'glm.pi', ({}, {}), '()', False, 'import glm\n'), ((26, 26, 26, 36), 'glm.mat4', 'glm.mat4', ({}, {}), '()', False, 'import glm\n'), ((26, 38, 26, 63), 'glm.vec3', 'glm.vec3', ({(26, 47, 26, 62): '(2.0 / self.scale)'}, {}), '(2.0 / self.scale)', False, 'import glm\n'), ((27, 30, 27, 40), 'glm.mat4', 'glm.mat4', ({}, {}), '()', False, 'import glm\n'), ((27, 42, 27, 89), 'glm.vec3', 'glm.vec3', ({(27, 51, 27, 67): '(-self.location.x)', (27, 69, 27, 85): '(-self.location.y)', (27, 87, 27, 88): '(0)'}, {}), '(-self.location.x, -self.location.y, 0)', False, 'import glm\n')]