// File: /workspace/github_cpp_makefile_star2_O3/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 $0xe8, %rsp
movq %rsi, %r12
movq %rdi, %r15
movl $0x271000, %edi         # imm = 0x271000
callq 0x2190
movq %rax, %rbx
movq %rax, (%r15)
leaq 0x271000(%rax), %r14
movq %r14, 0x10(%r15)
movl $0x271000, %edx         # imm = 0x271000
movq %rax, %rdi
xorl %esi, %esi
callq 0x20c0
movq %r15, -0xd8(%rbp)
movq %r14, 0x8(%r15)
movl $0x271000, %edi         # imm = 0x271000
callq 0x2190
movq %rax, %r14
xorl %r15d, %r15d
movl $0x271000, %edx         # imm = 0x271000
movq %rax, %rdi
xorl %esi, %esi
callq 0x20c0
movl $0x271000, %edx         # imm = 0x271000
movq %rbx, %rdi
xorl %esi, %esi
callq 0x20c0
movl $0xff7fffff, (%r14,%r15) # imm = 0xFF7FFFFF
addq $0x4, %r15
cmpq $0x271000, %r15         # imm = 0x271000
jne 0x3011
movq 0x20(%r12), %rax
subq 0x18(%r12), %rax
shrq $0x2, %rax
imull $0xaaaaaaab, %eax, %eax # imm = 0xAAAAAAAB
testl %eax, %eax
jle 0x364f
movq %r12, %r15
xorl %esi, %esi
movq %r15, %rdi
xorl %edx, %edx
movl %esi, %r12d
callq 0x3dd0
movl %eax, -0x50(%rbp)
movq %r15, %rdi
movl %r12d, %esi
movl $0x1, %edx
callq 0x3dd0
movl %eax, %r13d
movq %r15, %rdi
movl %r12d, -0x84(%rbp)
movl %r12d, %esi
movl $0x2, %edx
callq 0x3dd0
movl %eax, -0x40(%rbp)
movq %r15, %rdi
movl -0x50(%rbp), %esi
callq 0x3e40
movaps %xmm0, -0x60(%rbp)
movss %xmm1, -0x2c(%rbp)
movq %r15, %rdi
movl %r13d, %r12d
movl %r13d, %esi
callq 0x3e40
movaps %xmm0, -0x70(%rbp)
movss %xmm1, -0xc0(%rbp)
movq %r15, %rdi
movl -0x40(%rbp), %esi
callq 0x3e40
movaps %xmm0, -0xa0(%rbp)
movss %xmm1, -0x30(%rbp)
movq %r15, %rdi
movl -0x50(%rbp), %esi
callq 0x3e92
movaps %xmm0, -0x100(%rbp)
movss %xmm1, -0x7c(%rbp)
movq %r15, %rdi
movl %r12d, %esi
callq 0x3e92
movaps %xmm0, -0xd0(%rbp)
movss %xmm1, -0x78(%rbp)
movq %r15, %rdi
movl -0x40(%rbp), %esi
callq 0x3e92
movaps %xmm0, -0xf0(%rbp)
movss %xmm1, -0x74(%rbp)
leaq 0x50(%rbp), %r12
movq %r12, %rdi
movaps -0x60(%rbp), %xmm0
movss -0x2c(%rbp), %xmm1
callq 0x3ee4
movaps %xmm0, -0x50(%rbp)
movss %xmm1, -0x40(%rbp)
movq %r12, %rdi
movaps -0x70(%rbp), %xmm0
movss -0xc0(%rbp), %xmm1
callq 0x3ee4
movaps %xmm0, -0x60(%rbp)
movss %xmm1, -0x70(%rbp)
movq %r12, %rdi
movaps -0xa0(%rbp), %xmm0
movss -0x30(%rbp), %xmm1
callq 0x3ee4
movaps %xmm0, -0xa0(%rbp)
movss %xmm1, -0xb0(%rbp)
leaq 0x90(%rbp), %r12
movq %r12, %rdi
movaps -0x50(%rbp), %xmm0
movss -0x40(%rbp), %xmm1
callq 0x3ee4
movaps %xmm0, -0x50(%rbp)
movss %xmm1, -0x40(%rbp)
movq %r12, %rdi
movaps -0x60(%rbp), %xmm0
movss -0x70(%rbp), %xmm1
callq 0x3ee4
movaps %xmm0, -0x60(%rbp)
movss %xmm1, -0x70(%rbp)
movq %r12, %rdi
movaps -0xa0(%rbp), %xmm0
movss -0xb0(%rbp), %xmm1
callq 0x3ee4
movaps %xmm0, -0x110(%rbp)
movss %xmm1, -0x80(%rbp)
leaq 0x10(%rbp), %r12
movq %r12, %rdi
movaps -0x50(%rbp), %xmm0
movss -0x40(%rbp), %xmm1
callq 0x3ee4
movaps %xmm0, -0xa0(%rbp)
movq %r12, %rdi
movaps -0x60(%rbp), %xmm0
movss -0x70(%rbp), %xmm1
callq 0x3ee4
movaps %xmm0, -0xb0(%rbp)
movq %r12, %rdi
movaps -0x110(%rbp), %xmm0
movss -0x80(%rbp), %xmm1
callq 0x3ee4
movaps -0xa0(%rbp), %xmm5
movss 0x1de7(%rip), %xmm1     # 0x5008
addss %xmm1, %xmm5
movaps -0xb0(%rbp), %xmm3
addss %xmm1, %xmm3
movaps %xmm0, %xmm2
addss %xmm1, %xmm0
movss 0x1dc5(%rip), %xmm1     # 0x5004
mulss %xmm1, %xmm5
mulss %xmm1, %xmm3
mulss %xmm1, %xmm0
movss 0x1dbd(%rip), %xmm1     # 0x5010
mulss %xmm1, %xmm5
mulss %xmm1, %xmm3
mulss %xmm1, %xmm0
movaps %xmm5, %xmm4
minss 0x1daa(%rip), %xmm4     # 0x5014
movaps %xmm5, -0x60(%rbp)
maxss 0x1da2(%rip), %xmm5     # 0x5018
movaps %xmm3, %xmm6
minss %xmm4, %xmm6
movaps %xmm3, -0x50(%rbp)
movaps %xmm3, %xmm4
maxss %xmm5, %xmm4
movaps %xmm0, %xmm5
minss %xmm6, %xmm5
movaps %xmm0, -0x40(%rbp)
movaps %xmm0, %xmm6
maxss %xmm4, %xmm6
movaps %xmm1, %xmm4
minss %xmm5, %xmm4
xorps %xmm5, %xmm5
maxss %xmm5, %xmm4
movaps %xmm1, %xmm0
xorps %xmm1, %xmm1
minss %xmm6, %xmm0
maxss %xmm1, %xmm0
cvttps2dq %xmm4, %xmm4
cvtdq2ps %xmm4, %xmm13
movss %xmm0, -0x70(%rbp)
ucomiss %xmm13, %xmm0
jbe 0x362d
movaps -0xd0(%rbp), %xmm3
addps -0x100(%rbp), %xmm3
movss -0x78(%rbp), %xmm9
addss -0x7c(%rbp), %xmm9
addps -0xf0(%rbp), %xmm3
movaps %xmm3, %xmm4
shufps $0x55, %xmm3, %xmm4     # xmm4 = xmm4[1,1],xmm3[1,1]
addss -0x74(%rbp), %xmm9
xorps %xmm8, %xmm8
movss 0x1d05(%rip), %xmm1     # 0x500c
mulss %xmm1, %xmm3
mulss %xmm1, %xmm4
mulss %xmm1, %xmm9
movaps %xmm4, %xmm5
mulss %xmm4, %xmm5
movaps %xmm3, %xmm6
mulss %xmm3, %xmm6
addss %xmm5, %xmm6
movaps %xmm9, %xmm5
mulss %xmm9, %xmm5
addss %xmm6, %xmm5
sqrtss %xmm5, %xmm5
divss %xmm5, %xmm3
divss %xmm5, %xmm4
divss %xmm5, %xmm9
movaps -0xa0(%rbp), %xmm14
shufps $0x55, %xmm14, %xmm14   # xmm14 = xmm14[1,1,1,1]
movss 0x1caf(%rip), %xmm1     # 0x5008
addss %xmm1, %xmm14
movaps -0xb0(%rbp), %xmm0
shufps $0x55, %xmm0, %xmm0     # xmm0 = xmm0[1,1,1,1]
addss %xmm1, %xmm0
shufps $0x55, %xmm2, %xmm2     # xmm2 = xmm2[1,1,1,1]
addss %xmm1, %xmm2
movss 0x1c87(%rip), %xmm1     # 0x5004
mulss %xmm1, %xmm14
mulss %xmm1, %xmm0
mulss %xmm1, %xmm2
movss 0x1c7e(%rip), %xmm1     # 0x5010
mulss %xmm1, %xmm14
mulss %xmm1, %xmm0
mulss %xmm1, %xmm2
movaps %xmm14, %xmm5
maxss 0x1c6d(%rip), %xmm5     # 0x5018
movaps %xmm0, %xmm6
maxss %xmm5, %xmm6
movaps %xmm2, %xmm7
maxss %xmm6, %xmm7
movaps %xmm1, %xmm5
minss %xmm7, %xmm5
maxss %xmm8, %xmm5
movaps %xmm14, %xmm6
minss 0x1c43(%rip), %xmm6     # 0x5014
movaps %xmm0, %xmm7
minss %xmm6, %xmm7
movaps %xmm2, %xmm6
minss %xmm7, %xmm6
movaps %xmm1, %xmm7
xorps %xmm1, %xmm1
minss %xmm6, %xmm7
maxss %xmm1, %xmm7
mulss %xmm1, %xmm4
mulss %xmm1, %xmm3
addss %xmm4, %xmm3
addss %xmm9, %xmm3
movaps %xmm3, -0xd0(%rbp)
cvttps2dq %xmm7, %xmm4
cvtdq2ps %xmm4, %xmm15
movaps -0x40(%rbp), %xmm10
movaps %xmm10, %xmm7
movaps -0x50(%rbp), %xmm6
subss %xmm6, %xmm7
movaps %xmm2, %xmm8
subss %xmm0, %xmm8
movaps 0x1c22(%rip), %xmm4     # 0x5050
xorps %xmm4, %xmm8
movaps -0x60(%rbp), %xmm3
movaps %xmm3, %xmm9
subss %xmm10, %xmm9
movaps %xmm14, %xmm10
movaps %xmm2, %xmm11
subss %xmm2, %xmm10
xorps %xmm4, %xmm10
movaps %xmm6, %xmm2
subss %xmm3, %xmm2
movss -0x2c(%rbp), %xmm6
addss -0xc0(%rbp), %xmm6
movaps %xmm0, %xmm12
movaps %xmm0, %xmm3
movaps %xmm14, %xmm0
subss %xmm14, %xmm3
xorps %xmm4, %xmm3
addss -0x30(%rbp), %xmm6
divss 0x1b98(%rip), %xmm6     # 0x501c
movss %xmm6, -0x2c(%rbp)
xorps %xmm6, %xmm6
movaps %xmm15, -0xc0(%rbp)
ucomiss %xmm15, %xmm5
movss %xmm13, %xmm6           # xmm6 = xmm13[0],xmm6[1,2,3]
unpcklps %xmm15, %xmm13          # xmm13 = xmm13[0],xmm15[0],xmm13[1],xmm15[1]
jbe 0x3601
movaps %xmm6, %xmm4
movaps %xmm13, %xmm6
movaps %xmm15, %xmm13
subss %xmm12, %xmm13
mulss %xmm7, %xmm13
movaps %xmm4, %xmm14
subss -0x50(%rbp), %xmm14
mulss %xmm8, %xmm14
addss %xmm13, %xmm14
ucomiss %xmm1, %xmm14
jb 0x35e1
movaps %xmm15, %xmm13
subss %xmm11, %xmm13
mulss %xmm9, %xmm13
movaps %xmm4, %xmm14
subss -0x40(%rbp), %xmm14
mulss %xmm10, %xmm14
addss %xmm13, %xmm14
ucomiss %xmm1, %xmm14
jb 0x35e1
movaps %xmm15, %xmm13
subss %xmm0, %xmm13
mulss %xmm2, %xmm13
movaps %xmm4, %xmm14
subss -0x60(%rbp), %xmm14
mulss %xmm3, %xmm14
addss %xmm13, %xmm14
ucomiss %xmm1, %xmm14
jb 0x35e1
cvttss2si %xmm4, %eax
cvttss2si %xmm15, %ecx
imull $0x320, %ecx, %ecx      # imm = 0x320
addl %eax, %ecx
movslq %ecx, %rax
movss -0x2c(%rbp), %xmm13
ucomiss (%r14,%rax,4), %xmm13
jbe 0x35e1
movss %xmm13, (%r14,%rax,4)
xorps %xmm13, %xmm13
maxss -0xd0(%rbp), %xmm13
movaps %xmm13, -0xd0(%rbp)
mulss 0x1aa5(%rip), %xmm13    # 0x5020
movaps %xmm13, %xmm14
mulss 0x1a9c(%rip), %xmm14    # 0x5024
movaps %xmm13, %xmm1
mulss 0x1a94(%rip), %xmm1     # 0x5028
addss %xmm14, %xmm1
mulss 0x1a8a(%rip), %xmm13    # 0x502c
addss %xmm1, %xmm13
cvttss2si %xmm13, %eax
movaps %xmm15, %xmm1
mulss 0x1a58(%rip), %xmm1     # 0x5010
addss %xmm4, %xmm1
cvttss2si %xmm1, %rcx
movq %rcx, %rdx
subss 0x1a64(%rip), %xmm1     # 0x5030
cvttss2si %xmm1, %rsi
xorps %xmm1, %xmm1
sarq $0x3f, %rdx
andq %rdx, %rsi
orq %rcx, %rsi
movl %eax, (%rbx,%rsi,4)
addss 0x1a1e(%rip), %xmm15    # 0x5008
movaps %xmm15, %xmm13
movlhps %xmm6, %xmm13           # xmm13 = xmm13[0],xmm6[0]
shufps $0xe2, %xmm6, %xmm13    # xmm13 = xmm13[2,0],xmm6[2,3]
ucomiss %xmm15, %xmm5
ja 0x34a7
movaps %xmm13, %xmm1
addss 0x19fb(%rip), %xmm6     # 0x5008
movss -0x70(%rbp), %xmm4
ucomiss %xmm6, %xmm4
movaps %xmm6, %xmm13
movaps %xmm1, %xmm6
xorps %xmm1, %xmm1
movaps -0xc0(%rbp), %xmm15
ja 0x3494
movq 0x20(%r15), %rax
subq 0x18(%r15), %rax
movl -0x84(%rbp), %esi
incl %esi
shrq $0x2, %rax
imull $0xaaaaaaab, %eax, %eax # imm = 0xAAAAAAAB
cmpl %eax, %esi
jl 0x3047
movq %r14, %rdi
callq 0x2170
movq -0xd8(%rbp), %rax
addq $0xe8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %r15
jmp 0x369c
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
jmp 0x3691
movq %rax, %r15
movq %r14, %rdi
callq 0x2170
movq %rbx, %rdi
callq 0x2170
movq %r15, %rdi
callq 0x22e0