// File: donqustix[P]SoftwareRenderer/src/main.cpp
// Function: main
int main()
{
    if (::SDL_Init(SDL_INIT_VIDEO) >= 0)
    {
        SDL_Window* const window = ::SDL_CreateWindow("Software Renderer",
                SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
        if (window)
        {
            SDL_Surface* const surface = ::SDL_GetWindowSurface(window);
            if (surface)
            {
                try
                {
                    const Mesh mesh{::load_obj("res/bunny.obj")};

                    const auto perspective_matrix = mat4f::create_perspective(M_PI / 3,
                            static_cast<float>(WINDOW_WIDTH) / WINDOW_HEIGHT, 1e-1F, 1e3F);
                    auto matrix1 = perspective_matrix * mat4f::create_translation(0.0F, -0.12F, -0.25F);
                    auto matrix2 = perspective_matrix * mat4f::create_translation(2.0F, 1.0F, -5.0F) *
                            mat4f::create_scaling(0.4F, 0.4F, 0.4F);
                    const auto rotation_matrix = mat4f::create_rotation_y(0.05F) * mat4f::create_rotation_x(-0.01F);

                    SDL_Event event;

                    bool running = true;
                    while (running)
                    {
                        while (::SDL_PollEvent(&event))
                        {
                            if (event.type == SDL_QUIT)
                                running = false;
                        }

                        ::clear_zbuffer();

                        ::SDL_FillRect(surface, nullptr, 0);
                        ::SDL_LockSurface(surface);
                        ::render_mesh(surface, mesh, matrix1);
                        ::render_triangle(surface, {{ 0.0F, -1.0F, 0.0F}, {1.0F, 0.0F, 0.0F}},
                                                   {{-1.0F,  1.0F, 0.0F}, {0.0F, 1.0F, 0.0F}},
                                                   {{ 1.0F,  1.0F, 0.0F}, {0.0F, 0.0F, 1.0F}}, matrix2);
                        ::SDL_UnlockSurface(surface);

                        matrix1 *= rotation_matrix;
                        matrix2 *= rotation_matrix;

                        ::SDL_UpdateWindowSurface(window);
                        ::SDL_Delay(20);
                    }
                }
                catch (const std::exception& ex)
                {
                    std::cerr << ex.what() << std::endl;
                }
            }
            else
                std::cerr << "SDL_Surface getting error: " << ::SDL_GetError() << std::endl;

            ::SDL_DestroyWindow(window);
        }
        else
            std::cerr << "SDL_Window creation error: " << ::SDL_GetError() << std::endl;

        ::SDL_Quit();
    }
    else
        std::cerr << "SDL2 initialization error: " << ::SDL_GetError() << std::endl;

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x400, %rsp            # imm = 0x400
movl $0x0, -0x4(%rbp)
movl $0x20, %edi
callq 0x2210
cmpl $0x0, %eax
jl 0x2a21
leaq 0x5b38(%rip), %rdi      # 0x8044
movl $0x1fff0000, %edx       # imm = 0x1FFF0000
movl $0x280, %ecx            # imm = 0x280
movl $0x1e0, %r8d            # imm = 0x1E0
movl $0x4, %r9d
movl %edx, %esi
callq 0x2040
movq %rax, -0x10(%rbp)
cmpq $0x0, -0x10(%rbp)
je 0x29dd
movq -0x10(%rbp), %rdi
callq 0x22a0
movq %rax, -0x18(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x2995
leaq -0x51(%rbp), %rdi
movq %rdi, -0x398(%rbp)
callq 0x2390
movq -0x398(%rbp), %rdx
leaq 0x5ae8(%rip), %rsi      # 0x8056
leaq -0x50(%rbp), %rdi
callq 0x22c0
jmp 0x2579
leaq -0x30(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x2a80
jmp 0x2588
leaq -0x50(%rbp), %rdi
callq 0x2170
leaq -0x51(%rbp), %rdi
callq 0x2260
leaq -0xa4(%rbp), %rdi
movss 0x5a7b(%rip), %xmm0     # 0x8024
movss 0x5a77(%rip), %xmm1     # 0x8028
movss 0x5a73(%rip), %xmm2     # 0x802c
movss 0x5a6f(%rip), %xmm3     # 0x8030
callq 0x3080
leaq -0x124(%rbp), %rdi
xorps %xmm0, %xmm0
movss 0x5a44(%rip), %xmm1     # 0x801c
movss 0x5a40(%rip), %xmm2     # 0x8020
callq 0x32c0
leaq -0xe4(%rbp), %rdi
leaq -0xa4(%rbp), %rsi
leaq -0x124(%rbp), %rdx
callq 0x31d0
leaq -0x1e4(%rbp), %rdi
movss 0x5a02(%rip), %xmm0     # 0x8010
movss 0x59fe(%rip), %xmm1     # 0x8014
movss 0x59fa(%rip), %xmm2     # 0x8018
callq 0x32c0
leaq -0x1a4(%rbp), %rdi
leaq -0xa4(%rbp), %rsi
leaq -0x1e4(%rbp), %rdx
callq 0x31d0
leaq -0x224(%rbp), %rdi
movss 0x59c0(%rip), %xmm2     # 0x800c
movaps %xmm2, %xmm0
movaps %xmm2, %xmm1
callq 0x3390
leaq -0x164(%rbp), %rdi
leaq -0x1a4(%rbp), %rsi
leaq -0x224(%rbp), %rdx
callq 0x31d0
leaq -0x2a4(%rbp), %rdi
movss 0x5988(%rip), %xmm0     # 0x8008
callq 0x3470
leaq -0x2e4(%rbp), %rdi
movss 0x5970(%rip), %xmm0     # 0x8004
callq 0x3580
leaq -0x264(%rbp), %rdi
leaq -0x2a4(%rbp), %rsi
leaq -0x2e4(%rbp), %rdx
callq 0x31d0
movb $0x1, -0x321(%rbp)
testb $0x1, -0x321(%rbp)
je 0x296f
jmp 0x26c9
leaq -0x320(%rbp), %rdi
callq 0x2160
movl %eax, -0x39c(%rbp)
jmp 0x26dd
movl -0x39c(%rbp), %eax
cmpl $0x0, %eax
je 0x27b7
cmpl $0x100, -0x320(%rbp)    # imm = 0x100
jne 0x27b2
movb $0x0, -0x321(%rbp)
jmp 0x27b2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
jmp 0x272b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
leaq -0x50(%rbp), %rdi
callq 0x2170
leaq -0x51(%rbp), %rdi
callq 0x2260
jmp 0x274b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x3a90
movl -0x64(%rbp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0x2a69
movq -0x60(%rbp), %rdi
callq 0x20f0
movq %rax, -0x390(%rbp)
movq -0x390(%rbp), %rdi
movq (%rdi), %rax
movq 0x10(%rax), %rax
callq *%rax
movq %rax, %rsi
movq 0x9863(%rip), %rdi      # 0xbfe8
callq 0x2220
movq %rax, -0x3a8(%rbp)
jmp 0x2793
movq -0x3a8(%rbp), %rdi
movq 0x9817(%rip), %rsi      # 0xbfb8
callq 0x2250
jmp 0x27a8
callq 0x2360
jmp 0x29d2
jmp 0x26c9
callq 0x3670
movq -0x18(%rbp), %rdi
xorl %edx, %edx
movl %edx, %esi
callq 0x2060
jmp 0x27cb
movq -0x18(%rbp), %rdi
callq 0x22b0
jmp 0x27d6
movq -0x18(%rbp), %rdi
leaq -0x30(%rbp), %rsi
leaq -0xe4(%rbp), %rdx
callq 0x36c0
movq -0x18(%rbp), %rax
movq %rax, -0x3c8(%rbp)
leaq -0x344(%rbp), %rdi
movq %rdi, -0x3c0(%rbp)
movss 0x5829(%rip), %xmm1     # 0x8034
movss %xmm1, -0x3d4(%rbp)
xorps %xmm2, %xmm2
movss %xmm2, -0x3d0(%rbp)
movss 0x57ee(%rip), %xmm3     # 0x8014
movss %xmm3, -0x3cc(%rbp)
movaps %xmm2, %xmm0
callq 0x39f0
movss -0x3d0(%rbp), %xmm2
movss -0x3cc(%rbp), %xmm3
leaq -0x334(%rbp), %rdi
movaps %xmm3, %xmm0
movaps %xmm2, %xmm1
callq 0x39f0
movss -0x3d4(%rbp), %xmm0
movss -0x3d0(%rbp), %xmm2
movss -0x3cc(%rbp), %xmm3
leaq -0x364(%rbp), %rdi
movq %rdi, -0x3b8(%rbp)
movaps %xmm3, %xmm1
callq 0x39f0
movss -0x3d0(%rbp), %xmm2
movss -0x3cc(%rbp), %xmm3
leaq -0x354(%rbp), %rdi
movaps %xmm2, %xmm0
movaps %xmm3, %xmm1
callq 0x39f0
movss -0x3d0(%rbp), %xmm2
movss -0x3cc(%rbp), %xmm3
leaq -0x384(%rbp), %rdi
movq %rdi, -0x3b0(%rbp)
movaps %xmm3, %xmm0
movaps %xmm3, %xmm1
callq 0x39f0
movss -0x3d0(%rbp), %xmm1
movss -0x3cc(%rbp), %xmm3
leaq -0x374(%rbp), %rdi
movaps %xmm1, %xmm0
movaps %xmm3, %xmm2
callq 0x39f0
movq -0x3c8(%rbp), %rdi
movq -0x3c0(%rbp), %rsi
movq -0x3b8(%rbp), %rdx
movq -0x3b0(%rbp), %rcx
leaq -0x164(%rbp), %r8
callq 0x3770
movq -0x18(%rbp), %rdi
callq 0x22f0
jmp 0x2926
leaq -0xe4(%rbp), %rdi
leaq -0x264(%rbp), %rsi
movq %rsi, -0x3e0(%rbp)
callq 0x3a40
movq -0x3e0(%rbp), %rsi
leaq -0x164(%rbp), %rdi
callq 0x3a40
movq -0x10(%rbp), %rdi
callq 0x2270
jmp 0x295e
movl $0x14, %edi
callq 0x2190
jmp 0x296a
jmp 0x26ba
leaq -0x30(%rbp), %rdi
callq 0x3a90
jmp 0x27ad
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
callq 0x2360
jmp 0x2990
jmp 0x2a69
movq 0x964c(%rip), %rdi      # 0xbfe8
leaq 0x56c1(%rip), %rsi      # 0x8064
callq 0x2220
movq %rax, -0x3e8(%rbp)
callq 0x21b0
movq -0x3e8(%rbp), %rdi
movq %rax, %rsi
callq 0x2220
movq %rax, %rdi
movq 0x95eb(%rip), %rsi      # 0xbfb8
callq 0x2250
movq -0x10(%rbp), %rdi
callq 0x2030
jmp 0x2a1a
movq 0x9604(%rip), %rdi      # 0xbfe8
leaq 0x5695(%rip), %rsi      # 0x8080
callq 0x2220
movq %rax, -0x3f0(%rbp)
callq 0x21b0
movq -0x3f0(%rbp), %rdi
movq %rax, %rsi
callq 0x2220
movq %rax, %rdi
movq 0x95a3(%rip), %rsi      # 0xbfb8
callq 0x2250
callq 0x2070
jmp 0x2a5e
movq 0x95c0(%rip), %rdi      # 0xbfe8
leaq 0x566d(%rip), %rsi      # 0x809c
callq 0x2220
movq %rax, -0x3f8(%rbp)
callq 0x21b0
movq -0x3f8(%rbp), %rdi
movq %rax, %rsi
callq 0x2220
movq %rax, %rdi
movq 0x955f(%rip), %rsi      # 0xbfb8
callq 0x2250
xorl %eax, %eax
addq $0x400, %rsp            # imm = 0x400
popq %rbp
retq
movq -0x60(%rbp), %rdi
callq 0x2380
movq %rax, %rdi
callq 0x70a0
nopw (%rax,%rax)