// File: /workspace/github_cpp_makefile_star2_O2/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 $0xf8, %rsp
movq %rsi, %r13
movq %rdi, %rbx
leaq -0xd8(%rbp), %rdx
movl $0x9c400, %esi          # imm = 0x9C400
callq 0x3a40
leaq -0xd8(%rbp), %rdi
leaq -0x80(%rbp), %rdx
movl $0x9c400, %esi          # imm = 0x9C400
callq 0x3a92
movq (%rbx), %rax
movq %rbx, -0x30(%rbp)
movq 0x8(%rbx), %rcx
cmpq %rcx, %rax
je 0x2deb
andl $0x0, (%rax)
addq $0x4, %rax
jmp 0x2ddd
movq -0xd8(%rbp), %rax
movq -0xd0(%rbp), %rcx
cmpq %rcx, %rax
je 0x2e0a
movl $0xff7fffff, (%rax)     # imm = 0xFF7FFFFF
addq $0x4, %rax
jmp 0x2df9
xorl %esi, %esi
movq 0x20(%r13), %rax
subq 0x18(%r13), %rax
cqto
pushq $0xc
popq %rcx
idivq %rcx
cmpl %eax, %esi
jge 0x3386
movq %r13, %rdi
xorl %edx, %edx
movl %esi, %r12d
callq 0x3ae4
movl %eax, %r15d
movq %r13, %rdi
movl %r12d, %esi
pushq $0x1
popq %rdx
callq 0x3ae4
movl %eax, %ebx
movq %r13, %rdi
movl %r12d, %r14d
movl %r12d, %esi
pushq $0x2
popq %rdx
callq 0x3ae4
movl %eax, %r12d
movq %r13, %rdi
movl %r15d, %esi
callq 0x3b50
movaps %xmm0, -0x70(%rbp)
movss %xmm1, -0x38(%rbp)
movq %r13, %rdi
movl %ebx, %esi
callq 0x3b50
movaps %xmm0, -0x60(%rbp)
movss %xmm1, -0x90(%rbp)
movq %r13, %rdi
movl %r12d, %esi
callq 0x3b50
movaps %xmm0, -0x50(%rbp)
movss %xmm1, -0xb0(%rbp)
movq %r13, %rdi
movl %r15d, %esi
callq 0x3b9e
movaps %xmm0, -0x110(%rbp)
movss %xmm1, -0xc0(%rbp)
movq %r13, %rdi
movl %ebx, %esi
callq 0x3b9e
movaps %xmm0, -0x100(%rbp)
movss %xmm1, -0xf0(%rbp)
movq %r13, %rdi
movl %r12d, %esi
callq 0x3b9e
movaps %xmm0, -0x120(%rbp)
movss %xmm1, -0x98(%rbp)
leaq 0x50(%rbp), %r15
movq %r15, %rdi
movaps -0x70(%rbp), %xmm0
movss -0x38(%rbp), %xmm1
callq 0x3bec
movaps %xmm0, -0x70(%rbp)
movss %xmm1, -0x34(%rbp)
movq %r15, %rdi
movaps -0x60(%rbp), %xmm0
movss -0x90(%rbp), %xmm1
callq 0x3bec
movaps %xmm0, -0x60(%rbp)
movss %xmm1, -0x40(%rbp)
movq %r15, %rdi
movaps -0x50(%rbp), %xmm0
movss -0xb0(%rbp), %xmm1
callq 0x3bec
movaps %xmm0, -0x50(%rbp)
movss %xmm1, -0x3c(%rbp)
leaq 0x90(%rbp), %r15
movq %r15, %rdi
movaps -0x70(%rbp), %xmm0
movss -0x34(%rbp), %xmm1
callq 0x3bec
movaps %xmm0, -0x70(%rbp)
movss %xmm1, -0x94(%rbp)
movq %r15, %rdi
movaps -0x60(%rbp), %xmm0
movss -0x40(%rbp), %xmm1
callq 0x3bec
movaps %xmm0, -0x60(%rbp)
movss %xmm1, -0x40(%rbp)
movq %r15, %rdi
movaps -0x50(%rbp), %xmm0
movss -0x3c(%rbp), %xmm1
callq 0x3bec
movaps %xmm0, -0x50(%rbp)
movss %xmm1, -0x3c(%rbp)
movaps -0x100(%rbp), %xmm2
addps -0x110(%rbp), %xmm2
movss -0xf0(%rbp), %xmm3
addss -0xc0(%rbp), %xmm3
addps -0x120(%rbp), %xmm2
movaps %xmm2, %xmm0
shufps $0x55, %xmm2, %xmm0     # xmm0 = xmm0[1,1],xmm2[1,1]
addss -0x98(%rbp), %xmm3
movss 0x203a(%rip), %xmm1     # 0x500c
mulss %xmm1, %xmm2
mulss %xmm1, %xmm0
unpcklps %xmm0, %xmm2            # xmm2 = xmm2[0],xmm0[0],xmm2[1],xmm0[1]
mulss %xmm1, %xmm3
movlps %xmm2, -0x80(%rbp)
movss %xmm3, -0x78(%rbp)
leaq -0x80(%rbp), %rdi
callq 0x39b0
movaps %xmm0, -0xc0(%rbp)
movss %xmm1, -0x34(%rbp)
leaq 0x10(%rbp), %r15
movq %r15, %rdi
movaps -0x70(%rbp), %xmm0
movss -0x94(%rbp), %xmm1
callq 0x3bec
movaps %xmm0, -0x70(%rbp)
movq %r15, %rdi
movaps -0x60(%rbp), %xmm0
movss -0x40(%rbp), %xmm1
callq 0x3bec
movaps %xmm0, -0x60(%rbp)
movq %r15, %rdi
movaps -0x50(%rbp), %xmm0
movss -0x3c(%rbp), %xmm1
callq 0x3bec
movaps %xmm0, -0x50(%rbp)
andq $0x0, -0x80(%rbp)
movl $0x3f800000, -0x78(%rbp) # imm = 0x3F800000
leaq -0x80(%rbp), %rdi
callq 0x39b0
movaps -0x70(%rbp), %xmm11
movaps %xmm11, %xmm3
movss 0x1f9d(%rip), %xmm5     # 0x5008
addss %xmm5, %xmm3
shufps $0x55, %xmm11, %xmm11   # xmm11 = xmm11[1,1,1,1]
addss %xmm5, %xmm11
movaps -0x60(%rbp), %xmm12
movaps %xmm12, %xmm2
addss %xmm5, %xmm2
shufps $0x55, %xmm12, %xmm12   # xmm12 = xmm12[1,1,1,1]
addss %xmm5, %xmm12
movss 0x1f6c(%rip), %xmm6     # 0x5004
mulss %xmm6, %xmm3
mulss %xmm6, %xmm11
mulss %xmm6, %xmm2
mulss %xmm6, %xmm12
movss 0x1f5e(%rip), %xmm7     # 0x5010
mulss %xmm7, %xmm3
mulss %xmm7, %xmm11
movaps -0xc0(%rbp), %xmm8
movaps %xmm8, %xmm4
mulps %xmm0, %xmm4
mulss %xmm8, %xmm0
movaps %xmm3, %xmm9
mulss %xmm7, %xmm2
mulss %xmm7, %xmm12
shufps $0x55, %xmm4, %xmm4     # xmm4 = xmm4[1,1,1,1]
addss %xmm4, %xmm0
movss -0x34(%rbp), %xmm4
mulss %xmm1, %xmm4
addss %xmm0, %xmm4
movss %xmm4, -0x34(%rbp)
movaps %xmm3, %xmm0
movss 0x1f13(%rip), %xmm4     # 0x5014
minss %xmm4, %xmm0
movaps %xmm11, %xmm1
minss %xmm4, %xmm1
movaps %xmm2, %xmm4
minss %xmm0, %xmm4
movaps %xmm12, %xmm0
minss %xmm1, %xmm0
movaps %xmm2, %xmm10
movss 0x1eef(%rip), %xmm8     # 0x5018
maxss %xmm8, %xmm3
maxss %xmm3, %xmm2
movaps -0x50(%rbp), %xmm13
movaps %xmm13, %xmm1
addss %xmm5, %xmm1
shufps $0x55, %xmm13, %xmm13   # xmm13 = xmm13[1,1,1,1]
addss %xmm5, %xmm13
mulss %xmm6, %xmm1
mulss %xmm6, %xmm13
unpcklps %xmm11, %xmm9           # xmm9 = xmm9[0],xmm11[0],xmm9[1],xmm11[1]
movaps %xmm9, -0x50(%rbp)
unpcklps %xmm12, %xmm10          # xmm10 = xmm10[0],xmm12[0],xmm10[1],xmm12[1]
movaps %xmm10, -0xc0(%rbp)
mulss %xmm7, %xmm1
mulss %xmm7, %xmm13
maxss %xmm8, %xmm11
maxss %xmm11, %xmm12
movaps %xmm1, %xmm3
minss %xmm4, %xmm3
movaps %xmm13, %xmm4
minss %xmm0, %xmm4
movaps %xmm1, %xmm0
maxss %xmm2, %xmm1
unpcklps %xmm13, %xmm0           # xmm0 = xmm0[0],xmm13[0],xmm0[1],xmm13[1]
movaps %xmm0, -0x110(%rbp)
maxss %xmm12, %xmm13
movaps %xmm7, %xmm0
minss %xmm3, %xmm0
movaps %xmm7, %xmm2
minss %xmm4, %xmm2
movaps %xmm7, %xmm4
minss %xmm1, %xmm4
minss %xmm13, %xmm7
movss -0x38(%rbp), %xmm3
addss -0x90(%rbp), %xmm3
xorps %xmm1, %xmm1
maxss %xmm1, %xmm0
maxss %xmm1, %xmm2
maxss %xmm1, %xmm4
movss %xmm4, -0x100(%rbp)
maxss %xmm1, %xmm7
movss %xmm7, -0x60(%rbp)
cvttps2dq %xmm0, %xmm0
cvtdq2ps %xmm0, %xmm1
cvttps2dq %xmm2, %xmm0
cvtdq2ps %xmm0, %xmm0
movaps %xmm0, -0xf0(%rbp)
addss -0xb0(%rbp), %xmm3
divss 0x1e10(%rip), %xmm3     # 0x501c
movss %xmm3, -0x38(%rbp)
xorps %xmm6, %xmm6
movl %r14d, %esi
movss -0x100(%rbp), %xmm0
ucomiss %xmm1, %xmm0
jbe 0x337f
movss %xmm1, %xmm6            # xmm6 = xmm1[0],xmm6[1,2,3]
movq -0xd8(%rbp), %r15
movq -0x30(%rbp), %rax
movq (%rax), %r12
movaps -0xf0(%rbp), %xmm3
movaps %xmm6, %xmm1
movaps %xmm3, %xmm6
movlhps %xmm1, %xmm6            # xmm6 = xmm6[0],xmm1[0]
shufps $0xe2, %xmm1, %xmm6     # xmm6 = xmm6[2,0],xmm1[2,3]
movss -0x60(%rbp), %xmm0
ucomiss %xmm3, %xmm0
jbe 0x3372
movaps %xmm1, -0x70(%rbp)
movaps %xmm3, -0xb0(%rbp)
movaps -0x50(%rbp), %xmm0
movaps -0xc0(%rbp), %xmm2
movaps -0x110(%rbp), %xmm4
movaps %xmm6, -0x90(%rbp)
callq 0x2cf3
xorps %xmm2, %xmm2
ucomiss %xmm2, %xmm0
jb 0x3354
shufps $0x55, %xmm0, %xmm0     # xmm0 = xmm0[1,1,1,1]
ucomiss %xmm2, %xmm0
movl %r14d, %esi
jb 0x3357
ucomiss %xmm2, %xmm1
movaps -0xb0(%rbp), %xmm3
jb 0x334b
movaps -0x70(%rbp), %xmm4
cvttss2si %xmm4, %eax
cvttss2si %xmm3, %ecx
imull $0x320, %ecx, %ecx      # imm = 0x320
addl %eax, %ecx
movslq %ecx, %rax
movss -0x38(%rbp), %xmm0
ucomiss (%r15,%rax,4), %xmm0
jbe 0x334b
movss %xmm0, (%r15,%rax,4)
xorps %xmm0, %xmm0
maxss -0x34(%rbp), %xmm0
movss %xmm0, -0x34(%rbp)
mulss 0x1d31(%rip), %xmm0     # 0x5020
movaps %xmm0, %xmm1
mulss 0x1d2a(%rip), %xmm1     # 0x5024
movaps %xmm0, %xmm2
mulss 0x1d23(%rip), %xmm2     # 0x5028
addss %xmm1, %xmm2
mulss 0x1d1b(%rip), %xmm0     # 0x502c
addss %xmm2, %xmm0
cvttss2si %xmm0, %eax
movaps %xmm3, %xmm0
mulss 0x1cec(%rip), %xmm0     # 0x5010
addss %xmm4, %xmm0
cvttss2si %xmm0, %rcx
movq %rcx, %rdx
subss 0x1cf8(%rip), %xmm0     # 0x5030
cvttss2si %xmm0, %rdi
sarq $0x3f, %rdx
andq %rdx, %rdi
orq %rcx, %rdi
movl %eax, (%r12,%rdi,4)
movaps -0x90(%rbp), %xmm6
jmp 0x3365
movl %r14d, %esi
movaps -0x90(%rbp), %xmm6
movaps -0xb0(%rbp), %xmm3
addss 0x1c9b(%rip), %xmm3     # 0x5008
jmp 0x3241
addss 0x1c8e(%rip), %xmm1     # 0x5008
jmp 0x3217
incl %esi
jmp 0x2e0c
leaq -0xd8(%rbp), %rdi
callq 0x489e
movq -0x30(%rbp), %rax
addq $0xf8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %r14
jmp 0x33e0
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
jmp 0x33cd
movq %rax, %r14
movq -0x30(%rbp), %rbx
leaq -0xd8(%rbp), %rdi
callq 0x489e
movq %rbx, %rdi
callq 0x4794
movq %r14, %rdi
callq 0x2290