// File: /workspace/github_cpp_makefile_star2_O3/FreeSlave[P]vhlt/hlbsp/brink.cpp
// Function: AnalyzeBrinks(bbrinkinfo_s*)
void AnalyzeBrinks (bbrinkinfo_t *info)
{
	int countgood = 0;
	int countinvalid = 0;
	int countskipped = 0;
	int countfixed = 0;
	int i, j, side;
	for (i = 0; i < info->numbrinks; i++)
	{
		bbrink_t *b = info->brinks[i];
		if (b->numnodes <= 5) // quickly reject the most trivial brinks
		{
#ifdef HLBSP_BRINKNOTUSEDBYLEAF_FIX
			if (b->numnodes != 3 && b->numnodes != 5)
			{
				PrintOnce ("AnalyzeBrinks: internal error 1");
				hlassume (false, assume_first);
			}
			// because a brink won't necessarily be split twice after its creation
			if (b->numnodes == 3)
			{
				if (g_developer >= DEVELOPER_LEVEL_FLUFF)
				{
					Developer (DEVELOPER_LEVEL_FLUFF, "Brink wasn't split by the second plane:\n");
					PrintBrink (b);
				}
				countinvalid++;
			}
			else
			{
				countgood++;
			}
			continue;
#else
			hlassume (b->numnodes == 5, assume_first);
			countgood++;
			continue;
#endif
		}
		
		if (b->numnodes > 2 * MAXBRINKWEDGES - 1)
		{
			if (g_developer >= DEVELOPER_LEVEL_MEGASPAM)
			{
				Developer (DEVELOPER_LEVEL_MEGASPAM, "Skipping complicated brink:\n");
				PrintBrink (b);
			}
			countskipped++;
			continue;
		}
		bcircle_t c;
		// build the circle to find out the planes a player may move along
		if (!CalculateCircle (b, &c))
		{
			if (g_developer >= DEVELOPER_LEVEL_FLUFF)
			{
				Developer (DEVELOPER_LEVEL_FLUFF, "CalculateCircle failed for brink:\n");
				PrintBrink (b);
			}
			countinvalid++;
			continue;
		}
		
		int transitionfound[2];
		bsurface_t *transitionpos[2];
		bool transitionside[2];
		for (side = 0; side < 2; side++)
		{
			transitionfound[side] = 0;
			for (j = 1; j < c.numwedges[side]; j++) // we will later consider the surfaces on the first split
			{
				bsurface_t *s = &c.surfaces[side][j];
				if ((s->prev->content == CONTENTS_SOLID) != (s->next->content == CONTENTS_SOLID))
				{
					transitionfound[side]++;
					transitionpos[side] = s;
					transitionside[side] = (s->prev->content == CONTENTS_SOLID);
				}
			}
		}

		if (transitionfound[0] == 0 || transitionfound[1] == 0)
		{
			// at least one side of the first split is completely SOLID or EMPTY. no bugs in this case
			countgood++;
			continue;
		}

		if (transitionfound[0] > 1 || transitionfound[1] > 1 ||
			(c.surfaces[0][0].prev->content == CONTENTS_SOLID) != (c.surfaces[0][0].next->content == CONTENTS_SOLID) ||
			(c.surfaces[1][0].prev->content == CONTENTS_SOLID) != (c.surfaces[1][0].next->content == CONTENTS_SOLID))
		{
			// there must at least 3 transition surfaces now, which is too complicated. just leave it unfixed
			if (g_developer >= DEVELOPER_LEVEL_MEGASPAM)
			{
				Developer (DEVELOPER_LEVEL_MEGASPAM, "Skipping complicated brink:\n");
				PrintBrink (b);
				PrintCircle (&c);
			}
			countskipped++;
			continue;
		}
		
		if (transitionside[1] != !transitionside[0])
		{
			PrintOnce ("AnalyzeBrinks: internal error 2");
			hlassume (false, assume_first);
		}
		bool bfix = false;
		bool berror = false;
		vec3_t vup = {0, 0, 1};
		bool isfloor;
		bool onfloor;
		bool blocking;
		{
			isfloor = false;
			for (int side2 = 0; side2 < 2; side2++)
			{
				vec3_t normal;
				VectorScale (transitionpos[side2]->normal, transitionside[side2]? -1: 1, normal); // pointing from SOLID to EMPTY
				if (DotProduct (normal, vup) > BRINK_FLOOR_THRESHOLD)
				{
					isfloor = true;
				}
			}
		}
		{
			onfloor = false;
			for (int side2 = 0; side2 < 2; side2++)
			{
				btreepoint_t *tp = GetPointFromEdge (b->edge, side2);
#ifdef HLBSP_BRINKHACK_BUGFIX
				if (tp->infinite)
				{
					continue;
				}
#endif
				for (btreeedge_l::iterator ei = tp->edges->begin (); ei != tp->edges->end (); ei++)
				{
					for (btreeface_l::iterator fi = ei->e->faces->begin (); fi != ei->e->faces->end (); fi++)
					{
#ifdef HLBSP_BRINKHACK_BUGFIX
						if (fi->f->infinite || GetLeafFromFace (fi->f, false)->infinite || GetLeafFromFace (fi->f, true)->infinite)
						{
							PrintOnce ("AnalyzeBrinks: internal error: an infinite object contains a finite object");
							hlassume (false, assume_first);
						}
#endif
						for (int side3 = 0; side3 < 2; side3++)
						{
							vec3_t normal;
							VectorScale (fi->f->plane->normal, (fi->f->planeside != (bool)side3)? -1: 1, normal);
							if (DotProduct (normal, vup) > BRINK_FLOOR_THRESHOLD
								&& GetLeafFromFace (fi->f, side3)->clipnode->content == CONTENTS_SOLID
								&& GetLeafFromFace (fi->f, !side3)->clipnode->content != CONTENTS_SOLID)
							{
								onfloor = true;
							}
						}
					}
				}
			}
		}
		// this code does not fix all the bugs, it only aims to fix most of the bugs
		for (side = 0; side < 2; side++)
		{
			bsurface_t *smovement = transitionpos[side];
			bsurface_t *s;
			for (s = transitionside[!side]? &c.surfaces[!side][0]: &c.surfaces[side][0]; ; s = transitionside[!side]? s->next->next: s->prev->prev)
			{
				bwedge_t *w = transitionside[!side]? s->next: s->prev;
				bsurface_t *snext = transitionside[!side]? w->next: w->prev;
				vec3_t tmp;
				vec_t dot;
				CrossProduct (smovement->normal, snext->normal, tmp);
				dot = DotProduct (tmp, c.axis);
				if (transitionside[!side]? dot < 0.01: dot > -0.01)
				{
					break;
				}
				if (w->content != CONTENTS_SOLID)
				{
					break;
				}
				if (snext == (transitionside[!side]? &c.surfaces[side][0]: &c.surfaces[!side][0]))
				{
					Developer (DEVELOPER_LEVEL_ERROR, "AnalyzeBrinks: surface past 0\n");
					break;
				}
				bfix = true;
				{
					if (DotProduct (smovement->normal, s->normal) > 0.01)
					{
						blocking = false;
					}
					else
					{
						blocking = true;
					}
				}
				bclipnode_t *clipnode = (*b->nodes)[w->nodenum].clipnode;
				int planenum = (*b->nodes)[smovement->nodenum].planenum;
				bool planeside = transitionside[!side]? smovement->nodeside: !smovement->nodeside;
				bbrinklevel_e brinktype;
				brinktype = isfloor? (blocking? BrinkFloorBlocking: BrinkFloor): onfloor? (blocking? BrinkWallBlocking: BrinkWall): BrinkAny;
				if (!AddPartition (clipnode, planenum, planeside, CONTENTS_EMPTY, brinktype))
				{
					berror = true;
				}
			}
		}
		if (berror)
		{
			if (g_developer >= DEVELOPER_LEVEL_FLUFF)
			{
				Developer (DEVELOPER_LEVEL_FLUFF, "AddPartition failed for brink:\n");
				PrintBrink (b);
			}
			countinvalid++;
		}
		else if (!bfix)
		{
			countgood++;
		}
		else
		{
			countfixed++;
		}
	}
	Developer (DEVELOPER_LEVEL_MESSAGE, "brinks: good = %d skipped = %d fixed = %d invalid = %d\n", countgood, countskipped, countfixed, countinvalid);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x24a8, %rsp           # imm = 0x24A8
cmpl $0x0, 0x20(%rdi)
jle 0x10fe5
movq %rdi, %r15
leaq 0xcd8(%rsp), %r13
leaq 0x20b0af2(%rip), %rbp   # 0x20c1400
leaq 0x70(%rsp), %rbx
leaq 0x10367(%rip), %r14     # 0x20c81
xorl %r12d, %r12d
movl $0x0, 0x8(%rsp)
movl $0x0, 0xc(%rsp)
movl $0x0, 0x1c(%rsp)
movl $0x0, 0x20(%rsp)
movq 0x28(%r15), %rax
movq (%rax,%r12,8), %rax
movq %rax, 0x10(%rsp)
movl 0x48(%rax), %eax
cmpl $0x5, %eax
jg 0x109b0
cmpl $0x3, %eax
je 0x1097b
cmpl $0x5, %eax
je 0x1097b
leaq 0x10275(%rip), %rdi     # 0x20bd8
xorl %eax, %eax
callq 0xa10c
xorl %edi, %edi
xorl %esi, %esi
callq 0xa655
movq 0x10(%rsp), %rax
movl 0x48(%rax), %eax
cmpl $0x3, %eax
jne 0x10fcf
cmpl $0x4, (%rbp)
jl 0x109a7
movl $0x4, %edi
leaq 0x10262(%rip), %rsi     # 0x20bf8
xorl %eax, %eax
callq 0xa3ae
movq 0x10(%rsp), %rdi
callq 0xdb8e
incl 0xc(%rsp)
jmp 0x10fd3
cmpl $0x80, %eax
jb 0x109e3
cmpl $0x6, (%rbp)
jl 0x109da
movl $0x6, %edi
leaq 0x10258(%rip), %rsi     # 0x20c21
xorl %eax, %eax
callq 0xa3ae
movq 0x10(%rsp), %rdi
callq 0xdb8e
incl 0x1c(%rsp)
jmp 0x10fd3
movq %r12, 0x28(%rsp)
movq 0x10(%rsp), %rdi
movq %rbx, %rsi
callq 0xffd7
testb %al, %al
je 0x10aac
movb $0x1, %al
leaq 0x50(%rsp), %rdx
leaq 0x4c(%rsp), %rsi
xorl %ecx, %ecx
movl $0x0, (%rsi)
movslq 0xa0(%rsp,%rcx,4), %rdi
cmpq $0x2, %rdi
jl 0x10a6a
leaq (%rcx,%rcx,2), %r8
shlq $0xa, %r8
addq %r13, %r8
decq %rdi
xorl %r9d, %r9d
movq 0x20(%r8), %r10
movq 0x28(%r8), %r11
movl (%r10), %r10d
cmpl $-0x2, %r10d
sete %bl
cmpl $-0x2, (%r11)
setne %r11b
xorb %bl, %r11b
jne 0x10a61
incl %r9d
cmpl $-0x2, %r10d
movl %r9d, (%rsi)
movq %r8, (%rdx)
sete 0x6(%rsp,%rcx)
addq $0x30, %r8
decq %rdi
jne 0x10a30
movl $0x1, %ecx
leaq 0x60(%rsp), %rdx
leaq 0x48(%rsp), %rsi
testb $0x1, %al
movl $0x0, %eax
jne 0x10a0b
movl 0x4c(%rsp), %eax
testl %eax, %eax
sete %dl
movl 0x48(%rsp), %ecx
testl %ecx, %ecx
sete %sil
orb %dl, %sil
cmpb $0x1, %sil
jne 0x10ad8
incl 0x8(%rsp)
leaq 0x70(%rsp), %rbx
jmp 0x10d76
cmpl $0x4, (%rbp)
jl 0x10acf
movl $0x4, %edi
leaq 0x10180(%rip), %rsi     # 0x20c3e
xorl %eax, %eax
callq 0xa3ae
movq 0x10(%rsp), %rdi
callq 0xdb8e
incl 0xc(%rsp)
jmp 0x10d76
cmpl $0x2, %eax
setge %al
cmpl $0x2, %ecx
setge %cl
orb %al, %cl
leaq 0x70(%rsp), %rbx
jne 0x10d47
movq 0xcc8(%rsp), %rax
movq 0xcd0(%rsp), %rcx
cmpl $-0x2, (%rax)
sete %al
cmpl $-0x2, (%rcx)
setne %cl
cmpb %cl, %al
je 0x10d47
movq 0x18c8(%rsp), %rax
movq 0x18d0(%rsp), %rcx
cmpl $-0x2, (%rax)
sete %al
cmpl $-0x2, (%rcx)
setne %cl
xorb %al, %cl
je 0x10d47
movb 0x6(%rsp), %al
cmpb 0x7(%rsp), %al
jne 0x10b5a
leaq 0x10117(%rip), %rdi     # 0x20c61
xorl %eax, %eax
callq 0xa10c
xorl %edi, %edi
xorl %esi, %esi
callq 0xa655
movb $0x1, %al
movl $0x0, 0x24(%rsp)
leaq 0x6(%rsp), %rcx
leaq 0x50(%rsp), %rdx
leaq 0x7(%rsp), %rsi
movq (%rdx), %rdx
cmpb $0x0, (%rcx)
movsd 0xf6f7(%rip), %xmm0     # 0x20278
jne 0x10b8b
movsd 0xf53d(%rip), %xmm0     # 0x200c8
movsd (%rdx), %xmm1
mulsd %xmm0, %xmm1
movsd 0x8(%rdx), %xmm2
mulsd %xmm0, %xmm2
mulsd 0x10(%rdx), %xmm0
xorpd %xmm3, %xmm3
mulsd %xmm3, %xmm2
mulsd %xmm3, %xmm1
addsd %xmm2, %xmm1
addsd %xmm0, %xmm1
ucomisd 0xf8eb(%rip), %xmm1     # 0x204a8
seta %cl
movl 0x24(%rsp), %edx
orb %cl, %dl
movl %edx, 0x24(%rsp)
movq %rsi, %rcx
leaq 0x60(%rsp), %rdx
testb $0x1, %al
movl $0x0, %eax
jne 0x10b73
movq %r15, 0x58(%rsp)
movb $0x1, %cl
xorl %r15d, %r15d
xorl %eax, %eax
movl %ecx, 0x38(%rsp)
movq 0x10(%rsp), %rcx
movq 0x58(%rcx), %rdi
movzbl %al, %esi
andl $0x1, %esi
callq 0xe75d
cmpb $0x0, 0x18(%rax)
je 0x10c18
movb $0x1, %al
testb $0x1, 0x38(%rsp)
movl $0x0, %ecx
jne 0x10be7
jmp 0x10d80
movq %rax, 0x30(%rsp)
movq 0x20(%rax), %rax
movq (%rax), %r13
cmpq %rax, %r13
je 0x10c05
movq 0x10(%r13), %rcx
movq 0x28(%rcx), %rcx
movq (%rcx), %rbx
cmpq %rcx, %rbx
je 0x10d3e
movq 0x10(%rbx), %rdi
cmpb $0x0, 0x8(%rdi)
jne 0x10c68
xorl %esi, %esi
callq 0xe9eb
cmpb $0x0, 0x8(%rax)
jne 0x10c68
movq 0x10(%rbx), %rdi
movl $0x1, %esi
callq 0xe9eb
cmpb $0x1, 0x8(%rax)
jne 0x10c7b
movq %r14, %rdi
xorl %eax, %eax
callq 0xa10c
xorl %edi, %edi
xorl %esi, %esi
callq 0xa655
xorl %r12d, %r12d
movb $0x1, %bpl
xorl %eax, %eax
movq 0x10(%rbx), %rdi
movq 0x30(%rdi), %rcx
movzbl 0x3c(%rdi), %edx
xorl %esi, %esi
cmpl %edx, %eax
sete %sil
leal -0x1(%rsi,%rsi), %eax
xorps %xmm0, %xmm0
cvtsi2sd %eax, %xmm0
movsd (%rcx), %xmm1
mulsd %xmm0, %xmm1
movsd 0x8(%rcx), %xmm2
mulsd %xmm0, %xmm2
mulsd 0x10(%rcx), %xmm0
xorpd %xmm3, %xmm3
mulsd %xmm3, %xmm2
mulsd %xmm3, %xmm1
addsd %xmm2, %xmm1
addsd %xmm0, %xmm1
ucomisd 0xf7d4(%rip), %xmm1     # 0x204a8
jbe 0x10d0d
movzbl %r12b, %esi
andl $0x1, %esi
callq 0xe9eb
movq 0x10(%rax), %rax
cmpl $-0x2, 0x20(%rax)
jne 0x10d0d
movq 0x10(%rbx), %rdi
notb %r12b
movzbl %r12b, %esi
andl $0x1, %esi
callq 0xe9eb
movq 0x10(%rax), %rax
cmpl $-0x2, 0x20(%rax)
setne %al
orb %al, %r15b
movl $0x1, %eax
movb $0x1, %r12b
testb $0x1, %bpl
movl $0x0, %ebp
jne 0x10c83
movq (%rbx), %rbx
movq 0x10(%r13), %rax
cmpq 0x28(%rax), %rbx
jne 0x10c3d
movq 0x30(%rsp), %rax
movq 0x20(%rax), %rax
movq (%r13), %r13
jmp 0x10c24
cmpl $0x6, (%rbp)
jl 0x10d72
movl $0x6, %edi
leaq 0xfec8(%rip), %rsi      # 0x20c21
xorl %eax, %eax
callq 0xa3ae
movq 0x10(%rsp), %rdi
callq 0xdb8e
movq %rbx, %rdi
callq 0x10646
incl 0x1c(%rsp)
movq 0x28(%rsp), %r12
jmp 0x10fd3
movb $0x1, %dl
xorl %eax, %eax
leaq 0x50(%rsp), %rcx
xorl %edi, %edi
movq $0x0, 0x30(%rsp)
movl %edx, 0x44(%rsp)
movq (%rcx), %r13
movq %rax, %rcx
xorq $0x1, %rcx
movzbl 0x6(%rsp,%rcx), %esi
testl %esi, %esi
movq %rax, %rdx
cmovneq %rcx, %rdx
leaq (%rdx,%rdx,2), %rbp
cmovneq %rax, %rcx
shlq $0xa, %rbp
leaq 0xca8(%rsp), %rax
addq %rax, %rbp
movq %rsi, 0x38(%rsp)
leaq 0x8(,%rsi,8), %rbx
leaq (%rcx,%rcx,2), %rcx
shlq $0xa, %rcx
addq %rax, %rcx
movq %rcx, 0x68(%rsp)
movzbl 0x38(%rsp), %r12d
movq 0x20(%rbp,%r12,8), %rax
movq (%rax,%rbx), %rcx
movsd (%r13), %xmm0
movsd 0x8(%r13), %xmm2
movsd 0x10(%rcx), %xmm4
movsd 0x10(%r13), %xmm1
movsd (%rcx), %xmm5
movsd 0x8(%rcx), %xmm3
movapd %xmm3, %xmm6
mulsd %xmm1, %xmm6
movapd %xmm2, %xmm7
mulsd %xmm4, %xmm7
subsd %xmm6, %xmm7
mulsd %xmm0, %xmm4
movapd %xmm1, %xmm6
mulsd %xmm5, %xmm6
subsd %xmm4, %xmm6
mulsd %xmm2, %xmm5
mulsd %xmm0, %xmm3
mulsd 0x78(%rsp), %xmm6
subsd %xmm5, %xmm3
mulsd 0x70(%rsp), %xmm7
addsd %xmm6, %xmm7
mulsd 0x80(%rsp), %xmm3
addsd %xmm7, %xmm3
testb %r12b, %r12b
je 0x10e78
movsd 0xf64b(%rip), %xmm4     # 0x204b8
ucomisd %xmm3, %xmm4
jbe 0x10e86
jmp 0x10f55
ucomisd 0xf630(%rip), %xmm3     # 0x204b0
ja 0x10f55
cmpl $-0x2, (%rax)
jne 0x10f55
cmpq 0x68(%rsp), %rcx
je 0x10f3c
mulsd 0x8(%rbp), %xmm2
mulsd (%rbp), %xmm0
addsd %xmm2, %xmm0
mulsd 0x10(%rbp), %xmm1
addsd %xmm0, %xmm1
xorl %ecx, %ecx
ucomisd 0xf5fd(%rip), %xmm1     # 0x204b8
setbe %cl
movq 0x10(%rsp), %rdx
movq 0x50(%rdx), %rdx
movslq 0x4(%rax), %rax
movq (%rdx), %rsi
leaq (%rax,%rax,4), %rax
movq 0x20(%rsi,%rax,8), %rdi
xorl %edx, %edx
cmpb 0x1c(%r13), %r12b
sete %dl
movl $0x2, %eax
subl %ecx, %eax
movl $0x4, %r8d
subl %ecx, %r8d
movslq 0x18(%r13), %rcx
leaq (%rcx,%rcx,4), %rcx
testb $0x1, %r15b
movl $0x5, %r9d
cmovel %r9d, %r8d
movl 0x4(%rsi,%rcx,8), %esi
testb $0x1, 0x24(%rsp)
cmovnel %eax, %r8d
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
callq 0x10758
xorb $0x1, %al
movq 0x30(%rsp), %rcx
orb %al, %cl
movq %rcx, 0x30(%rsp)
movq 0x20(%rbp,%r12,8), %rax
movq (%rax,%rbx), %rbp
movb $0x1, %dil
jmp 0x10de4
movq %rdi, %rbx
movl $0x1, %edi
leaq 0xfd81(%rip), %rsi      # 0x20ccc
xorl %eax, %eax
callq 0xa3ae
movq %rbx, %rdi
movl $0x1, %eax
leaq 0x60(%rsp), %rcx
testb $0x1, 0x44(%rsp)
movl $0x0, %edx
jne 0x10d94
testb $0x1, 0x30(%rsp)
leaq 0x70(%rsp), %rbx
je 0x10faa
leaq 0x20b047e(%rip), %rbp   # 0x20c1400
cmpl $0x4, (%rbp)
movq 0x58(%rsp), %r15
leaq 0xcd8(%rsp), %r13
jl 0x10acf
movl $0x4, %edi
leaq 0xfd46(%rip), %rsi      # 0x20ceb
jmp 0x10abe
testb $0x1, %dil
movq 0x58(%rsp), %r15
leaq 0xcd8(%rsp), %r13
leaq 0x20b043e(%rip), %rbp   # 0x20c1400
movq 0x28(%rsp), %r12
je 0x10fcf
incl 0x20(%rsp)
jmp 0x10fd3
incl 0x8(%rsp)
incq %r12
movslq 0x20(%r15), %rax
cmpq %rax, %r12
jl 0x1093d
jmp 0x11005
movl $0x0, 0x20(%rsp)
movl $0x0, 0x1c(%rsp)
movl $0x0, 0xc(%rsp)
movl $0x0, 0x8(%rsp)
leaq 0xfcff(%rip), %rsi      # 0x20d0b
movl $0x3, %edi
movl 0x8(%rsp), %edx
movl 0x1c(%rsp), %ecx
movl 0x20(%rsp), %r8d
movl 0xc(%rsp), %r9d
xorl %eax, %eax
callq 0xa3ae
addq $0x24a8, %rsp           # imm = 0x24A8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq