// File: FreeSlave[P]vhlt/hlbsp/solidbsp.cpp
// Function: ChooseMidPlaneFromList(surface_s*, double const*, double const*, int)
static surface_t* ChooseMidPlaneFromList(surface_t* surfaces, const vec3_t mins, const vec3_t maxs
#ifdef ZHLT_DETAILBRUSH
										 , int detaillevel
#endif
										 )
{
    int             j, l;
    surface_t*      p;
    surface_t*      bestsurface;
    vec_t           bestvalue;
    vec_t           value;
    vec_t           dist;
    dplane_t*       plane;
#ifdef HLBSP_CHOOSEMIDPLANE
	surfacetree_t*	surfacetree;
	std::vector< face_t * >::iterator it;
	face_t*			f;

	surfacetree = BuildSurfaceTree (surfaces, ON_EPSILON);
#endif

    //
    // pick the plane that splits the least
    //
#ifdef HLBSP_CHOOSEMIDPLANE
	bestvalue = 9e30;
#else
#ifdef ZHLT_LARGERANGE
	bestvalue = 6.0f * BOGUS_RANGE * BOGUS_RANGE;
#else
    bestvalue = 6 * 8192 * 8192;
#endif
#endif
    bestsurface = NULL;

    for (p = surfaces; p; p = p->next)
    {
        if (p->onnode)
        {
            continue;
        }
#ifdef ZHLT_DETAILBRUSH
		if (p->detaillevel != detaillevel)
		{
			continue;
		}
#endif

        plane = &g_dplanes[p->planenum];

        // check for axis aligned surfaces
        l = plane->type;
        if (l > last_axial)
        {
            continue;
        }

        //
        // calculate the split metric along axis l, smaller values are better
        //
        value = 0;

        dist = plane->dist * plane->normal[l];
#ifdef HLBSP_MAXNODESIZE_SKYBOX
		if (maxs[l] - dist < ON_EPSILON || dist - mins[l] < ON_EPSILON)
			continue;
#endif
#ifdef HLBSP_ChooseMidPlane_FIX
		if (maxs[l] - dist < g_maxnode_size/2.0 - ON_EPSILON || dist - mins[l] < g_maxnode_size/2.0 - ON_EPSILON)
			continue;
#endif
#ifdef HLBSP_CHOOSEMIDPLANE
		double crosscount = 0;
		double frontcount = 0;
		double backcount = 0;
		double coplanarcount = 0;

		TestSurfaceTree (surfacetree, plane);
		frontcount += surfacetree->result.frontsize;
		backcount += surfacetree->result.backsize;
		for (it = surfacetree->result.middle->begin (); it != surfacetree->result.middle->end (); ++it)
		{
			f = *it;
#ifdef HLCSG_HLBSP_SOLIDHINT
			if (f->facestyle == face_discardable)
			{
				continue;
			}
#endif
			if (f->planenum == p->planenum || f->planenum == (p->planenum ^ 1))
			{
				coplanarcount++;
				continue;
			}
			switch (FaceSide (f, plane))
			{
			case SIDE_FRONT:
				frontcount++;
				break;
			case SIDE_BACK:
				backcount++;
				break;
			case SIDE_ON:
				crosscount++;
				break;
			}
		}

		double frontsize = frontcount + 0.5 * coplanarcount + 0.5 * crosscount;
		double frontfrac = (maxs[l] - dist) / (maxs[l] - mins[l]);
		double backsize = backcount + 0.5 * coplanarcount + 0.5 * crosscount;
		double backfrac = (dist - mins[l]) / (maxs[l] - mins[l]);
		value = crosscount + 0.1 * (frontsize * (log (frontfrac) / log (2.0)) + backsize * (log (backfrac) / log (2.0)));
		// the first part is how the split will increase the number of faces
		// the second part is how the split will increase the average depth of the bsp tree
#else
        for (j = 0; j < 3; j++)
        {
            if (j == l)
            {
                value += (maxs[l] - dist) * (maxs[l] - dist);
                value += (dist - mins[l]) * (dist - mins[l]);
            }
            else
            {
                value += 2 * (maxs[j] - mins[j]) * (maxs[j] - mins[j]);
            }
        }
#endif

        if (value > bestvalue)
        {
            continue;
        }

        //
        // currently the best!
        //
        bestvalue = value;
        bestsurface = p;
    }

#ifdef HLBSP_CHOOSEMIDPLANE
	DeleteSurfaceTree (surfacetree);
#endif
    if (!bestsurface)
    {
#ifdef HLBSP_ChooseMidPlane_FIX
		return NULL;
#else
        for (p = surfaces; p; p = p->next)
        {
            if (!p->onnode)
            {
#ifdef ZHLT_DETAILBRUSH
				if (p->detaillevel != detaillevel)
				{
					continue;
				}
#endif
                return p;                                  // first valid surface
            }
        }
        Error("ChooseMidPlaneFromList: no valid planes");
#endif
    }

    return bestsurface;
}

// Assembly:
subq $0x108, %rsp            # imm = 0x108
movq %rdi, 0xf8(%rsp)
movq %rsi, 0xf0(%rsp)
movq %rdx, 0xe8(%rsp)
movl %ecx, 0xe4(%rsp)
leaq 0x98(%rsp), %rdi
callq 0x2e920
movq 0xf8(%rsp), %rdi
movsd 0xc8bd(%rip), %xmm0     # 0x39600
callq 0x2a4e0
movq %rax, 0xa0(%rsp)
movsd 0xeb80(%rip), %xmm0     # 0x3b8d8
movsd %xmm0, 0xc0(%rsp)
movq $0x0, 0xc8(%rsp)
movq 0xf8(%rsp), %rax
movq %rax, 0xd0(%rsp)
cmpq $0x0, 0xd0(%rsp)
je 0x2d329
movq 0xd0(%rsp), %rax
cmpq $0x0, 0x40(%rax)
je 0x2cda0
jmp 0x2d311
movq 0xd0(%rsp), %rax
movl 0x50(%rax), %eax
cmpl 0xe4(%rsp), %eax
je 0x2cdb9
jmp 0x2d311
movq 0xd0(%rsp), %rax
movslq 0x8(%rax), %rcx
leaq 0x20c2c64(%rip), %rax   # 0x20efa30
shlq $0x6, %rcx
addq %rcx, %rax
movq %rax, 0xa8(%rsp)
movq 0xa8(%rsp), %rax
movl 0x38(%rax), %eax
movl %eax, 0xdc(%rsp)
cmpl $0x2, 0xdc(%rsp)
jle 0x2cdfc
jmp 0x2d311
xorps %xmm0, %xmm0
movsd %xmm0, 0xb8(%rsp)
movq 0xa8(%rsp), %rax
movsd 0x30(%rax), %xmm0
movq 0xa8(%rsp), %rax
movslq 0xdc(%rsp), %rcx
mulsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0xb0(%rsp)
movq 0xe8(%rsp), %rax
movslq 0xdc(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm1
subsd 0xb0(%rsp), %xmm1
movsd 0xc7a7(%rip), %xmm0     # 0x39600
ucomisd %xmm1, %xmm0
ja 0x2ce8b
movsd 0xb0(%rsp), %xmm1
movq 0xf0(%rsp), %rax
movslq 0xdc(%rsp), %rcx
subsd (%rax,%rcx,8), %xmm1
movsd 0xc77b(%rip), %xmm0     # 0x39600
ucomisd %xmm1, %xmm0
jbe 0x2ce90
jmp 0x2d311
movq 0xe8(%rsp), %rax
movslq 0xdc(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm1
subsd 0xb0(%rsp), %xmm1
cvtsi2sdl 0x1a546(%rip), %xmm0 # 0x473fc
movsd 0xd14a(%rip), %xmm2     # 0x3a008
divsd %xmm2, %xmm0
movsd 0xc736(%rip), %xmm2     # 0x39600
subsd %xmm2, %xmm0
ucomisd %xmm1, %xmm0
ja 0x2cf18
movsd 0xb0(%rsp), %xmm1
movq 0xf0(%rsp), %rax
movslq 0xdc(%rsp), %rcx
subsd (%rax,%rcx,8), %xmm1
cvtsi2sdl 0x1a502(%rip), %xmm0 # 0x473fc
movsd 0xd106(%rip), %xmm2     # 0x3a008
divsd %xmm2, %xmm0
movsd 0xc6f2(%rip), %xmm2     # 0x39600
subsd %xmm2, %xmm0
ucomisd %xmm1, %xmm0
jbe 0x2cf1d
jmp 0x2d311
xorps %xmm0, %xmm0
movsd %xmm0, 0x88(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x80(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x78(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x70(%rsp)
movq 0xa0(%rsp), %rdi
movq 0xa8(%rsp), %rsi
callq 0x2a970
movq 0xa0(%rsp), %rax
cvtsi2sdl 0x18(%rax), %xmm0
addsd 0x80(%rsp), %xmm0
movsd %xmm0, 0x80(%rsp)
movq 0xa0(%rsp), %rax
cvtsi2sdl 0x1c(%rax), %xmm0
addsd 0x78(%rsp), %xmm0
movsd %xmm0, 0x78(%rsp)
movq 0xa0(%rsp), %rax
movq 0x20(%rax), %rdi
callq 0x2e400
movq %rax, 0x68(%rsp)
movq 0x68(%rsp), %rax
movq %rax, 0x98(%rsp)
movq 0xa0(%rsp), %rax
movq 0x20(%rax), %rdi
callq 0x2e470
movq %rax, 0x60(%rsp)
leaq 0x98(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x2e430
testb $0x1, %al
jne 0x2cfe8
jmp 0x2d0fc
leaq 0x98(%rsp), %rdi
callq 0x2e4a0
movq (%rax), %rax
movq %rax, 0x90(%rsp)
movq 0x90(%rsp), %rax
cmpl $0x4, 0x30(%rax)
jne 0x2d013
jmp 0x2d0ea
movq 0x90(%rsp), %rax
movl 0x8(%rax), %eax
movq 0xd0(%rsp), %rcx
cmpl 0x8(%rcx), %eax
je 0x2d048
movq 0x90(%rsp), %rax
movl 0x8(%rax), %eax
movq 0xd0(%rsp), %rcx
movl 0x8(%rcx), %ecx
xorl $0x1, %ecx
cmpl %ecx, %eax
jne 0x2d061
movsd 0xc0f8(%rip), %xmm0     # 0x39148
addsd 0x70(%rsp), %xmm0
movsd %xmm0, 0x70(%rsp)
jmp 0x2d0ea
movq 0x90(%rsp), %rdi
movq 0xa8(%rsp), %rsi
xorl %eax, %eax
movl %eax, %edx
callq 0x2dac0
movl %eax, %ecx
movl %ecx, 0x3c(%rsp)
testl %eax, %eax
je 0x2d09c
jmp 0x2d086
movl 0x3c(%rsp), %eax
subl $0x1, %eax
je 0x2d0b8
jmp 0x2d091
movl 0x3c(%rsp), %eax
subl $0x2, %eax
je 0x2d0ce
jmp 0x2d0e8
movsd 0xc0a4(%rip), %xmm0     # 0x39148
addsd 0x80(%rsp), %xmm0
movsd %xmm0, 0x80(%rsp)
jmp 0x2d0e8
movsd 0xc088(%rip), %xmm0     # 0x39148
addsd 0x78(%rsp), %xmm0
movsd %xmm0, 0x78(%rsp)
jmp 0x2d0e8
movsd 0xc072(%rip), %xmm0     # 0x39148
addsd 0x88(%rsp), %xmm0
movsd %xmm0, 0x88(%rsp)
jmp 0x2d0ea
leaq 0x98(%rsp), %rdi
callq 0x2e4b0
jmp 0x2cfb7
movsd 0x80(%rsp), %xmm0
movsd 0x70(%rsp), %xmm1
movsd 0xc325(%rip), %xmm2     # 0x39438
mulsd %xmm2, %xmm1
addsd %xmm0, %xmm1
movsd 0x88(%rsp), %xmm0
movsd 0xc30c(%rip), %xmm2     # 0x39438
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x58(%rsp)
movq 0xe8(%rsp), %rax
movslq 0xdc(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm0
subsd 0xb0(%rsp), %xmm0
movq 0xe8(%rsp), %rax
movslq 0xdc(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm1
movq 0xf0(%rsp), %rax
movslq 0xdc(%rsp), %rcx
subsd (%rax,%rcx,8), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x50(%rsp)
movsd 0x78(%rsp), %xmm0
movsd 0x70(%rsp), %xmm1
movsd 0xc298(%rip), %xmm2     # 0x39438
mulsd %xmm2, %xmm1
addsd %xmm0, %xmm1
movsd 0x88(%rsp), %xmm0
movsd 0xc27f(%rip), %xmm2     # 0x39438
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x48(%rsp)
movsd 0xb0(%rsp), %xmm0
movq 0xf0(%rsp), %rax
movslq 0xdc(%rsp), %rcx
subsd (%rax,%rcx,8), %xmm0
movq 0xe8(%rsp), %rax
movslq 0xdc(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm1
movq 0xf0(%rsp), %rax
movslq 0xdc(%rsp), %rcx
subsd (%rax,%rcx,8), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x40(%rsp)
movsd 0x88(%rsp), %xmm0
movsd %xmm0, 0x28(%rsp)
movsd 0x58(%rsp), %xmm0
movsd %xmm0, 0x30(%rsp)
movsd 0x50(%rsp), %xmm0
callq 0x4250
movsd %xmm0, 0x8(%rsp)
movsd 0xcdbb(%rip), %xmm0     # 0x3a008
callq 0x4250
movaps %xmm0, %xmm1
movsd 0x8(%rsp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0x20(%rsp)
movsd 0x48(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x40(%rsp), %xmm0
callq 0x4250
movsd %xmm0, 0x10(%rsp)
movsd 0xcd7e(%rip), %xmm0     # 0x3a008
callq 0x4250
movsd 0x10(%rsp), %xmm4
movsd 0x18(%rsp), %xmm2
movsd 0x20(%rsp), %xmm3
movsd 0x28(%rsp), %xmm1
movaps %xmm0, %xmm5
movsd 0x30(%rsp), %xmm0
divsd %xmm5, %xmm4
mulsd %xmm4, %xmm2
mulsd %xmm3, %xmm0
addsd %xmm2, %xmm0
movsd 0xe618(%rip), %xmm2     # 0x3b8e0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0xb8(%rsp)
movsd 0xb8(%rsp), %xmm0
ucomisd 0xc0(%rsp), %xmm0
jbe 0x2d2ef
jmp 0x2d311
movsd 0xb8(%rsp), %xmm0
movsd %xmm0, 0xc0(%rsp)
movq 0xd0(%rsp), %rax
movq %rax, 0xc8(%rsp)
movq 0xd0(%rsp), %rax
movq (%rax), %rax
movq %rax, 0xd0(%rsp)
jmp 0x2cd7d
movq 0xa0(%rsp), %rdi
callq 0x2aa80
cmpq $0x0, 0xc8(%rsp)
jne 0x2d34f
movq $0x0, 0x100(%rsp)
jmp 0x2d35f
movq 0xc8(%rsp), %rax
movq %rax, 0x100(%rsp)
movq 0x100(%rsp), %rax
addq $0x108, %rsp            # imm = 0x108
retq
nop