// File: /workspace/github_cpp_makefile_star2_O1/kryffin[P]software-rasterizer/rasterizer.cpp
// Function: render(Model, Mat4f, Mat4f, Mat4f)
std::vector<int> render (Model model, Mat4f P, Mat4f M, Mat4f C) {

    std::vector<int>frameBuffer(WIDTH * HEIGHT); //single colored pixels for the grayscale
    std::vector<float>zBuffer(WIDTH * HEIGHT);

    std::fill(frameBuffer.begin(), frameBuffer.end(), BACKGROUND_COLOR);
    std::fill(zBuffer.begin(), zBuffer.end(), FLT_MIN);

	//
	// iteration through all the triangles of the model
    
    int i;
    for (i = 0; i < model.nTriangles(); i++) {

    	//triangle indices
    	int tv0 = model.triangleVertice(i, 0), tv1 = model.triangleVertice(i, 1), tv2 = model.triangleVertice(i, 2);

    	// triangle vertices
        Vec3f p0 = model.vertice(tv0);
		Vec3f p1 = model.vertice(tv1);
		Vec3f p2 = model.vertice(tv2);

		// vertices normals
		Vec3f vn0 = model.normal(tv0);
		Vec3f vn1 = model.normal(tv1);
		Vec3f vn2 = model.normal(tv2);

		Vec3f tp0 = p0;
		Vec3f tp1 = p1;
		Vec3f tp2 = p2;

		//
		// world transformation

		tp0 = M * tp0;
		tp1 = M * tp1;
		tp2 = M * tp2;

		//
		// transformation to get along with the camera

        tp0 = C * tp0;
		tp1 = C * tp1;
		tp2 = C * tp2;

        //
        // normal of triangle calculation : average of the 3 vertices' normals
        
        Vec3f surfaceNormal = ((vn0 + vn1 + vn2) * (1.f / 3.f)).normalize();

        //
		// projection of the vertices - clean that somehow

        Vec3f pp0 = P * tp0;
		Vec3f pp1 = P * tp1;
		Vec3f pp2 = P * tp2;

		pp0.x += 1.f; pp0.y += 1.f;
		pp1.x += 1.f; pp1.y += 1.f;
		pp2.x += 1.f; pp2.y += 1.f;

		pp0.x /= 2.f; pp0.y /= 2.f;
		pp1.x /= 2.f; pp1.y /= 2.f;
		pp2.x /= 2.f; pp2.y /= 2.f;

		pp0.x *= (float)WIDTH; pp0.y *= (float)HEIGHT; pp0.z *= 2.f;
		pp1.x *= (float)WIDTH; pp1.y *= (float)HEIGHT; pp1.z *= 2.f;
		pp2.x *= (float)WIDTH; pp2.y *= (float)HEIGHT; pp2.z *= 2.f;
        
        //
    	// constant light exposure

        Vec3f lightDirection = Vec3f(0.f, 0.f, 1.f).normalize();

        //
        // angle between triangle normal and light direction

        float dot = surfaceNormal.dot(lightDirection);

        //
        // bounding box init -- clean that somehow

        Vec2f bboxMin(FLT_MAX, FLT_MAX);
        Vec2f bboxMax(FLT_MIN, FLT_MIN);
        
        if (pp0.x < bboxMin.x) bboxMin.x = pp0.x;
        if (pp0.y < bboxMin.y) bboxMin.y = pp0.y;
        if (pp0.x > bboxMax.x) bboxMax.x = pp0.x;
        if (pp0.y > bboxMax.y) bboxMax.y = pp0.y;

        if (pp1.x < bboxMin.x) bboxMin.x = pp1.x;
        if (pp1.y < bboxMin.y) bboxMin.y = pp1.y;
        if (pp1.x > bboxMax.x) bboxMax.x = pp1.x;
        if (pp1.y > bboxMax.y) bboxMax.y = pp1.y;

        if (pp2.x < bboxMin.x) bboxMin.x = pp2.x;
        if (pp2.y < bboxMin.y) bboxMin.y = pp2.y;
        if (pp2.x > bboxMax.x) bboxMax.x = pp2.x;
        if (pp2.y > bboxMax.y) bboxMax.y = pp2.y;
        
        //
        // bounding box clamping in-screen -- clean that somehow

        bboxMin.x = std::max(0.f, std::min(bboxMin.x, (float)WIDTH));
        bboxMin.y = std::max(0.f, std::min(bboxMin.y, (float)HEIGHT));
        bboxMax.x = std::max(0.f, std::min(bboxMax.x, (float)WIDTH));
        bboxMax.y = std::max(0.f, std::min(bboxMax.y, (float)HEIGHT));

        //
        // iterating through the bounding box -- maybe clean that?

        Vec3f pixel;
        for (pixel.x = (int)bboxMin.x; pixel.x < bboxMax.x; pixel.x++) {
            for (pixel.y = (int)bboxMin.y; pixel.y < bboxMax.y; pixel.y++) {

            	// barycenter of the pixel relative to the triangle (whether or not the pixel is in the triangle)
                Vec3f bc = barycenter(pp0, pp1, pp2, pixel);

                if (bc.x >= 0 && bc.y >= 0 && bc.z >= 0) {
                	
                	// depth of the triangle by average of z coordinates
                	pixel.z = (p0.z + p1.z + p2.z) / 3.f;

            		// drawing (only if nearest pixel visited)
                	if (zBuffer[(int)pixel.x + ((int)pixel.y * WIDTH)] < pixel.z) {

                		// updating the zBuffer
                		zBuffer[(int)pixel.x + ((int)pixel.y * WIDTH)] = pixel.z;

                		if (dot < 0.f) dot = 0.f;

	                    frameBuffer[pixel.x + (pixel.y * WIDTH)] = (0.21f * (MODEL_R * dot)) + (0.72f * (MODEL_G * dot)) + (0.07f * (MODEL_B * dot));
                	}
                }

            }
        }
    }

    // return the frame buffer write image outside
    return frameBuffer;

}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xd8, %rsp
movq %rsi, %r15
movq %rdi, %r14
xorps %xmm0, %xmm0
movups %xmm0, (%rdi)
movq $0x0, 0x10(%rdi)
movl $0x271000, %edi         # imm = 0x271000
callq 0x2190
movq %rax, %r12
movq %rax, (%r14)
movq %rax, 0x8(%r14)
leaq 0x271000(%rax), %rbx
movq %rbx, 0x10(%r14)
movl $0x271000, %edx         # imm = 0x271000
movq %rax, %rdi
xorl %esi, %esi
callq 0x20c0
movq %r14, -0x30(%rbp)
movq %rbx, 0x8(%r14)
movl $0x271000, %edi         # imm = 0x271000
callq 0x2190
movq %rax, %r14
xorl %ebx, %ebx
movl $0x271000, %edx         # imm = 0x271000
movq %rax, %rdi
xorl %esi, %esi
callq 0x20c0
movl $0x271000, %edx         # imm = 0x271000
movq %r12, %rdi
xorl %esi, %esi
callq 0x20c0
movl $0xff7fffff, (%r14,%rbx) # imm = 0xFF7FFFFF
addq $0x4, %rbx
cmpq $0x271000, %rbx         # imm = 0x271000
jne 0x30ab
movq 0x20(%r15), %rax
subq 0x18(%r15), %rax
shrq $0x2, %rax
imull $0xaaaaaaab, %eax, %eax # imm = 0xAAAAAAAB
testl %eax, %eax
jle 0x3730
movq %r15, %rbx
xorl %esi, %esi
movq %rbx, %rdi
xorl %edx, %edx
movl %esi, %r15d
callq 0x3ecc
movl %eax, -0x80(%rbp)
movq %rbx, %rdi
movl %r15d, %esi
movl $0x1, %edx
callq 0x3ecc
movl %eax, %r13d
movq %rbx, %rdi
movl %r15d, -0x88(%rbp)
movl %r15d, %esi
movl $0x2, %edx
callq 0x3ecc
movl %eax, -0x50(%rbp)
movq %rbx, %rdi
movl -0x80(%rbp), %esi
callq 0x3f3c
movaps %xmm0, -0x60(%rbp)
movss %xmm1, -0x34(%rbp)
movq %rbx, %rdi
movl %r13d, %r15d
movl %r13d, %esi
callq 0x3f3c
movaps %xmm0, -0x70(%rbp)
movss %xmm1, -0x40(%rbp)
movq %rbx, %rdi
movl -0x50(%rbp), %esi
callq 0x3f3c
movaps %xmm0, -0xa0(%rbp)
movss %xmm1, -0x3c(%rbp)
movq %rbx, %rdi
movl -0x80(%rbp), %esi
callq 0x3f8e
movaps %xmm0, -0xe0(%rbp)
movss %xmm1, -0x80(%rbp)
movq %rbx, %rdi
movl %r15d, %esi
callq 0x3f8e
movaps %xmm0, -0xb0(%rbp)
movss %xmm1, -0xc0(%rbp)
movq %rbx, %rdi
movl -0x50(%rbp), %esi
callq 0x3f8e
movaps %xmm0, -0xd0(%rbp)
movss %xmm1, -0x100(%rbp)
leaq 0x50(%rbp), %r15
movq %r15, %rdi
movaps -0x60(%rbp), %xmm0
movss -0x34(%rbp), %xmm1
callq 0x3fe0
movaps %xmm0, -0x50(%rbp)
movss %xmm1, -0x60(%rbp)
movq %r15, %rdi
movaps -0x70(%rbp), %xmm0
movss -0x40(%rbp), %xmm1
callq 0x3fe0
movaps %xmm0, -0x70(%rbp)
movss %xmm1, -0x38(%rbp)
movq %r15, %rdi
movaps -0xa0(%rbp), %xmm0
movss -0x3c(%rbp), %xmm1
callq 0x3fe0
movaps %xmm0, -0xa0(%rbp)
movss %xmm1, -0xf0(%rbp)
leaq 0x90(%rbp), %r15
movq %r15, %rdi
movaps -0x50(%rbp), %xmm0
movss -0x60(%rbp), %xmm1
callq 0x3fe0
movaps %xmm0, -0x50(%rbp)
movss %xmm1, -0x60(%rbp)
movq %r15, %rdi
movaps -0x70(%rbp), %xmm0
movss -0x38(%rbp), %xmm1
callq 0x3fe0
movaps %xmm0, -0x70(%rbp)
movss %xmm1, -0x38(%rbp)
movq %r15, %rdi
movaps -0xa0(%rbp), %xmm0
movss -0xf0(%rbp), %xmm1
callq 0x3fe0
movaps %xmm0, -0xf0(%rbp)
movss %xmm1, -0x84(%rbp)
movaps -0xb0(%rbp), %xmm1
addps -0xe0(%rbp), %xmm1
movss -0xc0(%rbp), %xmm2
addss -0x80(%rbp), %xmm2
addps -0xd0(%rbp), %xmm1
movaps %xmm1, %xmm3
shufps $0x55, %xmm1, %xmm3     # xmm3 = xmm3[1,1],xmm1[1,1]
addss -0x100(%rbp), %xmm2
movss 0x1d6e(%rip), %xmm0     # 0x500c
mulss %xmm0, %xmm1
mulss %xmm0, %xmm3
mulss %xmm0, %xmm2
movaps %xmm3, -0x100(%rbp)
movaps %xmm3, %xmm0
mulss %xmm3, %xmm0
movaps %xmm1, -0xb0(%rbp)
mulss %xmm1, %xmm1
addss %xmm0, %xmm1
movss %xmm2, -0xc0(%rbp)
movaps %xmm2, %xmm0
mulss %xmm2, %xmm0
addss %xmm1, %xmm0
ucomiss 0x1d53(%rip), %xmm0     # 0x5034
jb 0x32e9
sqrtss %xmm0, %xmm0
jmp 0x32ee
callq 0x22f0
movss %xmm0, -0xd0(%rbp)
leaq 0x10(%rbp), %r15
movq %r15, %rdi
movaps -0x50(%rbp), %xmm0
movss -0x60(%rbp), %xmm1
callq 0x3fe0
movaps %xmm0, -0xa0(%rbp)
movq %r15, %rdi
movaps -0x70(%rbp), %xmm0
movss -0x38(%rbp), %xmm1
callq 0x3fe0
movaps %xmm0, -0xe0(%rbp)
movq %r15, %rdi
movaps -0xf0(%rbp), %xmm0
movss -0x84(%rbp), %xmm1
callq 0x3fe0
movaps -0xa0(%rbp), %xmm5
movss 0x1cb8(%rip), %xmm1     # 0x5008
addss %xmm1, %xmm5
movaps -0xe0(%rbp), %xmm2
addss %xmm1, %xmm2
movaps %xmm0, %xmm11
addss %xmm1, %xmm0
movss 0x1c95(%rip), %xmm1     # 0x5004
mulss %xmm1, %xmm5
mulss %xmm1, %xmm2
mulss %xmm1, %xmm0
movss 0x1c8d(%rip), %xmm7     # 0x5010
mulss %xmm7, %xmm5
mulss %xmm7, %xmm2
mulss %xmm7, %xmm0
movaps %xmm5, %xmm4
minss 0x1c7a(%rip), %xmm4     # 0x5014
movaps %xmm5, -0x60(%rbp)
maxss 0x1c72(%rip), %xmm5     # 0x5018
movaps %xmm2, %xmm6
minss %xmm4, %xmm6
movaps %xmm2, -0x80(%rbp)
movaps %xmm2, %xmm4
maxss %xmm5, %xmm4
movaps %xmm0, %xmm5
minss %xmm6, %xmm5
movaps %xmm0, -0x50(%rbp)
movaps %xmm0, %xmm6
maxss %xmm4, %xmm6
movaps %xmm7, %xmm4
minss %xmm5, %xmm4
xorps %xmm1, %xmm1
maxss %xmm1, %xmm4
minss %xmm6, %xmm7
maxss %xmm1, %xmm7
cvttps2dq %xmm4, %xmm4
cvtdq2ps %xmm4, %xmm14
movss %xmm7, -0x70(%rbp)
ucomiss %xmm14, %xmm7
jbe 0x370e
movaps -0xb0(%rbp), %xmm8
movss -0xd0(%rbp), %xmm1
divss %xmm1, %xmm8
movaps -0x100(%rbp), %xmm2
divss %xmm1, %xmm2
movss -0xc0(%rbp), %xmm0
divss %xmm1, %xmm0
movaps -0xa0(%rbp), %xmm13
shufps $0x55, %xmm13, %xmm13   # xmm13 = xmm13[1,1,1,1]
movss 0x1bd0(%rip), %xmm1     # 0x5008
addss %xmm1, %xmm13
movaps -0xe0(%rbp), %xmm3
shufps $0x55, %xmm3, %xmm3     # xmm3 = xmm3[1,1,1,1]
addss %xmm1, %xmm3
shufps $0x55, %xmm11, %xmm11   # xmm11 = xmm11[1,1,1,1]
addss %xmm1, %xmm11
movss 0x1ba6(%rip), %xmm1     # 0x5004
mulss %xmm1, %xmm13
mulss %xmm1, %xmm3
mulss %xmm1, %xmm11
movss 0x1b9c(%rip), %xmm7     # 0x5010
mulss %xmm7, %xmm13
mulss %xmm7, %xmm3
mulss %xmm7, %xmm11
movaps %xmm13, %xmm4
maxss 0x1b8a(%rip), %xmm4     # 0x5018
movaps %xmm3, %xmm5
maxss %xmm4, %xmm5
movaps %xmm11, %xmm4
maxss %xmm5, %xmm4
movaps %xmm7, %xmm5
minss %xmm4, %xmm5
xorps %xmm1, %xmm1
maxss %xmm1, %xmm5
movaps %xmm13, %xmm4
minss 0x1b5d(%rip), %xmm4     # 0x5014
movaps %xmm3, %xmm6
minss %xmm4, %xmm6
movaps %xmm11, %xmm4
minss %xmm6, %xmm4
movaps %xmm7, %xmm6
minss %xmm4, %xmm6
maxss %xmm1, %xmm6
mulss %xmm1, %xmm2
mulss %xmm1, %xmm8
addss %xmm2, %xmm8
addss %xmm0, %xmm8
movaps %xmm8, -0xb0(%rbp)
cvttps2dq %xmm6, %xmm4
cvtdq2ps %xmm4, %xmm15
movaps -0x50(%rbp), %xmm0
movaps %xmm0, %xmm7
movaps -0x80(%rbp), %xmm4
subss %xmm4, %xmm7
movaps %xmm11, %xmm8
subss %xmm3, %xmm8
movaps 0x1b3d(%rip), %xmm1     # 0x5050
xorps %xmm1, %xmm8
movaps -0x60(%rbp), %xmm2
movaps %xmm2, %xmm9
subss %xmm0, %xmm9
movaps %xmm13, %xmm10
movaps %xmm11, %xmm0
subss %xmm11, %xmm10
xorps %xmm1, %xmm10
movaps %xmm4, %xmm11
subss %xmm2, %xmm11
movss -0x34(%rbp), %xmm4
addss -0x40(%rbp), %xmm4
movaps %xmm3, %xmm12
movaps %xmm3, %xmm2
movaps %xmm13, %xmm3
subss %xmm13, %xmm2
xorps %xmm1, %xmm2
addss -0x3c(%rbp), %xmm4
divss 0x1ab4(%rip), %xmm4     # 0x501c
movss %xmm4, -0x34(%rbp)
xorps %xmm6, %xmm6
movaps %xmm15, -0xc0(%rbp)
ucomiss %xmm15, %xmm5
movss %xmm14, %xmm6           # xmm6 = xmm14[0],xmm6[1,2,3]
unpcklps %xmm15, %xmm14          # xmm14 = xmm14[0],xmm15[0],xmm14[1],xmm15[1]
jbe 0x36e5
movaps %xmm6, %xmm4
movaps %xmm14, %xmm6
movaps %xmm15, %xmm14
subss %xmm12, %xmm14
mulss %xmm7, %xmm14
movaps %xmm4, %xmm13
subss -0x80(%rbp), %xmm13
mulss %xmm8, %xmm13
addss %xmm14, %xmm13
xorps %xmm1, %xmm1
ucomiss %xmm1, %xmm13
jb 0x36c5
movaps %xmm15, %xmm13
subss %xmm0, %xmm13
mulss %xmm9, %xmm13
movaps %xmm4, %xmm14
subss -0x50(%rbp), %xmm14
mulss %xmm10, %xmm14
addss %xmm13, %xmm14
ucomiss %xmm1, %xmm14
jb 0x36c5
movaps %xmm15, %xmm13
subss %xmm3, %xmm13
mulss %xmm11, %xmm13
movaps %xmm4, %xmm14
subss -0x60(%rbp), %xmm14
mulss %xmm2, %xmm14
addss %xmm13, %xmm14
ucomiss %xmm1, %xmm14
jb 0x36c5
cvttss2si %xmm4, %eax
cvttss2si %xmm15, %ecx
imull $0x320, %ecx, %ecx      # imm = 0x320
addl %eax, %ecx
movslq %ecx, %rax
movss -0x34(%rbp), %xmm1
ucomiss (%r14,%rax,4), %xmm1
jbe 0x36c5
movss %xmm1, (%r14,%rax,4)
xorps %xmm13, %xmm13
maxss -0xb0(%rbp), %xmm13
movaps %xmm13, -0xb0(%rbp)
mulss 0x19bf(%rip), %xmm13    # 0x5020
movaps %xmm13, %xmm14
mulss 0x19b6(%rip), %xmm14    # 0x5024
movaps %xmm13, %xmm1
mulss 0x19ae(%rip), %xmm1     # 0x5028
addss %xmm14, %xmm1
mulss 0x19a4(%rip), %xmm13    # 0x502c
addss %xmm1, %xmm13
cvttss2si %xmm13, %eax
movaps %xmm15, %xmm1
mulss 0x1972(%rip), %xmm1     # 0x5010
addss %xmm4, %xmm1
cvttss2si %xmm1, %rcx
movq %rcx, %rdx
subss 0x197e(%rip), %xmm1     # 0x5030
cvttss2si %xmm1, %rsi
sarq $0x3f, %rdx
andq %rdx, %rsi
orq %rcx, %rsi
movl %eax, (%r12,%rsi,4)
addss 0x193a(%rip), %xmm15    # 0x5008
movaps %xmm15, %xmm14
movlhps %xmm6, %xmm14           # xmm14 = xmm14[0],xmm6[0]
shufps $0xe2, %xmm6, %xmm14    # xmm14 = xmm14[2,0],xmm6[2,3]
ucomiss %xmm15, %xmm5
ja 0x358b
movaps %xmm14, %xmm1
addss 0x1917(%rip), %xmm6     # 0x5008
movss -0x70(%rbp), %xmm4
ucomiss %xmm6, %xmm4
movaps %xmm6, %xmm14
movaps %xmm1, %xmm6
movaps -0xc0(%rbp), %xmm15
ja 0x3578
movq 0x20(%rbx), %rax
subq 0x18(%rbx), %rax
movl -0x88(%rbp), %esi
incl %esi
shrq $0x2, %rax
imull $0xaaaaaaab, %eax, %eax # imm = 0xAAAAAAAB
cmpl %eax, %esi
jl 0x30df
movq %r14, %rdi
callq 0x2170
movq -0x30(%rbp), %rax
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
movq -0x30(%rbp), %r15
jmp 0x3782
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
jmp 0x3773
movq %rax, %rbx
movq -0x30(%rbp), %r15
movq %r14, %rdi
callq 0x2170
movq (%r15), %rdi
testq %rdi, %rdi
je 0x378f
callq 0x2170
movq %rbx, %rdi
callq 0x22e0