// File: FreeSlave[P]vhlt/hlrad/loadtextures.cpp
// Function: CQ_CreatePalette(int, unsigned char const (*) [3], int, unsigned char (*) [3], int&, cq_searchnode_s*)
static void CQ_CreatePalette (int numpoints, const unsigned char (*points)[CQ_DIM],
					   int maxcolors, unsigned char (*colors_out)[CQ_DIM], int &numcolors_out,
					   cq_searchnode_t *searchtree_out) //[2 * maxcolors - 1]
{
	if (numpoints <= 0 || maxcolors <= 0)
	{
		numcolors_out = 0;
		return;
	}

	unsigned char (*pointarray)[CQ_DIM];
	pointarray = (unsigned char (*)[CQ_DIM])malloc (numpoints * sizeof (unsigned char [CQ_DIM]));
	hlassume (pointarray != NULL, assume_NoMemory);
	memcpy (pointarray, points, numpoints * sizeof (unsigned char [CQ_DIM]));

	cq_node_t *n;
	cq_searchnode_t *s;
	int numnodes = 0;
	int maxnodes = 2 * maxcolors - 1;
	cq_node_t *nodes = (cq_node_t *)malloc (maxnodes * sizeof (cq_node_t));
	hlassume (nodes != NULL, assume_NoMemory);

	n = &nodes[0];
	numnodes++;

	n->isleafnode = true;
	n->parentnode = NULL;
	n->numpoints = numpoints;
	n->refpoints = pointarray;
	CQ_SelectPartition (n);

	for (int i = 1; i < maxcolors; i++)
	{
		bool needsplit;
		double bestpriority;
		cq_node_t *bestnode;

		needsplit = false;
		for (int j = 0; j < numnodes; j++)
		{
			n = &nodes[j];
			if (!n->isleafnode || !n->needsplit)
			{
				continue;
			}
			if (needsplit == false || n->splitpriority > bestpriority + 0.1)
			{
				needsplit = true;
				bestpriority = n->splitpriority;
				bestnode = n;
			}
		}
		if (!needsplit)
		{
			break;
		}

		bestnode->isleafnode = false;
		for (int k = 0; k < 2; k++)
		{
			n = &nodes[numnodes];
			numnodes++;
			if (numnodes > maxnodes)
			{
				Error ("CQ_CreatePalette: internal error");
			}

			bestnode->childrennode[k] = n;
			n->isleafnode = true;
			n->parentnode = bestnode;
			n->numpoints = 0;
			n->refpoints = NULL;
		}

		// partition the points using the best splitter
		{
			const int splitaxis = bestnode->bestsplitter.axis;
			const int splitdist = bestnode->bestsplitter.dist;
			const int numpoints = bestnode->numpoints;
			unsigned char (*points)[CQ_DIM] = bestnode->refpoints;

			unsigned char (*left)[CQ_DIM];
			unsigned char (*right)[CQ_DIM];
			left = &bestnode->refpoints[0];
			right = &bestnode->refpoints[bestnode->numpoints - 1];
			while (1)
			{
				while ((*left)[splitaxis] < splitdist)
				{
					left++;
				}
				while ((*right)[splitaxis] >= splitdist)
				{
					right--;
				}
				if (left >= right)
				{
					break;
				}
				unsigned char tmp[CQ_DIM];
				CQ_VectorCopy (*left, tmp);
				CQ_VectorCopy (*right, *left);
				CQ_VectorCopy (tmp, *right);
			}
			if (right != left - 1)
			{
				Error ("CQ_CreatePalette: internal error");
			}

			bestnode->childrennode[0]->numpoints = left - bestnode->refpoints;
			bestnode->childrennode[0]->refpoints = bestnode->refpoints;
			bestnode->childrennode[1]->numpoints = &bestnode->refpoints[bestnode->numpoints] - left;
			bestnode->childrennode[1]->refpoints = left;
			if (bestnode->childrennode[0]->numpoints <= 0 ||
				bestnode->childrennode[0]->numpoints != bestnode->bestsplitter.numpoints[0])
			{
				Error ("CQ_CreatePalette: internal error");
			}
			if (bestnode->childrennode[1]->numpoints <= 0 ||
				bestnode->childrennode[1]->numpoints != bestnode->bestsplitter.numpoints[1])
			{
				Error ("CQ_CreatePalette: internal error");
			}
		}

		CQ_SelectPartition (bestnode->childrennode[0]);
		CQ_SelectPartition (bestnode->childrennode[1]);
	}

	for (int i = 0; i < numnodes; i++)
	{
		n = &nodes[i];
		s = &searchtree_out[i];
		s->isleafnode = n->isleafnode;
		if (!n->isleafnode)
		{
			s->planeaxis = n->bestsplitter.axis;
			s->planedist = n->bestsplitter.dist;
			s->childrennode[0] = &searchtree_out[n->childrennode[0] - nodes];
			s->childrennode[1] = &searchtree_out[n->childrennode[1] - nodes];
		}
	}

	numcolors_out = 0;
	n = &nodes[0];
	while (1)
	{
		while (!n->isleafnode)
		{
			n = n->childrennode[0];
		}
		s = &searchtree_out[n - nodes];
		s->result = numcolors_out;
		for (int k = 0; k < CQ_DIM; k++)
		{
			int val = (int)floor (n->centerofpoints[k] + 0.5 + 0.00001);
			val = qmax (0, qmin (val, 255));
			colors_out[numcolors_out][k] = val;
		}
		numcolors_out++;
		while (n->parentnode)
		{
			if (n == n->parentnode->childrennode[0])
			{
				break;
			}
			n = n->parentnode;
		}
		if (!n->parentnode)
		{
			break;
		}
		n = n->parentnode->childrennode[1];
	}

	if (2 * numcolors_out - 1 != numnodes)
	{
		Error ("CQ_CreatePalette: internal error");
	}

	free (pointarray);
	free (nodes);
}

// Assembly:
subq $0xc8, %rsp
movl %edi, 0xc4(%rsp)
movq %rsi, 0xb8(%rsp)
movl %edx, 0xb4(%rsp)
movq %rcx, 0xa8(%rsp)
movq %r8, 0xa0(%rsp)
movq %r9, 0x98(%rsp)
cmpl $0x0, 0xc4(%rsp)
jle 0x487e9
cmpl $0x0, 0xb4(%rsp)
jg 0x487fc
movq 0xa0(%rsp), %rax
movl $0x0, (%rax)
jmp 0x4901f
movslq 0xc4(%rsp), %rax
imulq $0x3, %rax, %rdi
callq 0x4430
movq %rax, 0x90(%rsp)
cmpq $0x0, 0x90(%rsp)
setne %al
movzbl %al, %edi
andl $0x1, %edi
movl $0x1, %esi
callq 0xbf00
movq 0x90(%rsp), %rdi
movq 0xb8(%rsp), %rsi
movslq 0xc4(%rsp), %rax
imulq $0x3, %rax, %rdx
callq 0x4280
movl $0x0, 0x7c(%rsp)
movl 0xb4(%rsp), %eax
shll %eax
subl $0x1, %eax
movl %eax, 0x78(%rsp)
movslq 0x78(%rsp), %rax
imulq $0x70, %rax, %rdi
callq 0x4430
movq %rax, 0x70(%rsp)
cmpq $0x0, 0x70(%rsp)
setne %al
movzbl %al, %edi
andl $0x1, %edi
movl $0x1, %esi
callq 0xbf00
movq 0x70(%rsp), %rax
movq %rax, 0x88(%rsp)
movl 0x7c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x7c(%rsp)
movq 0x88(%rsp), %rax
movb $0x1, (%rax)
movq 0x88(%rsp), %rax
movq $0x0, 0x8(%rax)
movl 0xc4(%rsp), %ecx
movq 0x88(%rsp), %rax
movl %ecx, 0x20(%rax)
movq 0x90(%rsp), %rcx
movq 0x88(%rsp), %rax
movq %rcx, 0x28(%rax)
movq 0x88(%rsp), %rdi
callq 0x49470
movl $0x1, 0x6c(%rsp)
movl 0x6c(%rsp), %eax
cmpl 0xb4(%rsp), %eax
jge 0x48ccd
movb $0x0, 0x6b(%rsp)
movl $0x0, 0x54(%rsp)
movl 0x54(%rsp), %eax
cmpl 0x7c(%rsp), %eax
jge 0x489cc
movq 0x70(%rsp), %rax
movslq 0x54(%rsp), %rcx
imulq $0x70, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x88(%rsp)
movq 0x88(%rsp), %rax
testb $0x1, (%rax)
je 0x48964
movq 0x88(%rsp), %rax
testb $0x1, 0x48(%rax)
jne 0x48966
jmp 0x489bc
movb 0x6b(%rsp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x48995
movq 0x88(%rsp), %rax
movsd 0x68(%rax), %xmm0
movsd 0x24e6f(%rip), %xmm1    # 0x6d7f8
addsd 0x60(%rsp), %xmm1
ucomisd %xmm1, %xmm0
jbe 0x489ba
movb $0x1, 0x6b(%rsp)
movq 0x88(%rsp), %rax
movsd 0x68(%rax), %xmm0
movsd %xmm0, 0x60(%rsp)
movq 0x88(%rsp), %rax
movq %rax, 0x58(%rsp)
jmp 0x489bc
movl 0x54(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x54(%rsp)
jmp 0x48922
testb $0x1, 0x6b(%rsp)
jne 0x489d8
jmp 0x48ccd
movq 0x58(%rsp), %rax
movb $0x0, (%rax)
movl $0x0, 0x50(%rsp)
cmpl $0x2, 0x50(%rsp)
jge 0x48a91
movq 0x70(%rsp), %rax
movslq 0x7c(%rsp), %rcx
imulq $0x70, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x88(%rsp)
movl 0x7c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x7c(%rsp)
movl 0x7c(%rsp), %eax
cmpl 0x78(%rsp), %eax
jle 0x48a2f
leaq 0x2609a(%rip), %rdi     # 0x6eac2
movb $0x0, %al
callq 0xb580
movq 0x88(%rsp), %rdx
movq 0x58(%rsp), %rax
movslq 0x50(%rsp), %rcx
movq %rdx, 0x10(%rax,%rcx,8)
movq 0x88(%rsp), %rax
movb $0x1, (%rax)
movq 0x58(%rsp), %rcx
movq 0x88(%rsp), %rax
movq %rcx, 0x8(%rax)
movq 0x88(%rsp), %rax
movl $0x0, 0x20(%rax)
movq 0x88(%rsp), %rax
movq $0x0, 0x28(%rax)
movl 0x50(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x50(%rsp)
jmp 0x489e8
movq 0x58(%rsp), %rax
movl 0x50(%rax), %eax
movl %eax, 0x4c(%rsp)
movq 0x58(%rsp), %rax
movl 0x54(%rax), %eax
movl %eax, 0x48(%rsp)
movq 0x58(%rsp), %rax
movl 0x20(%rax), %eax
movl %eax, 0x44(%rsp)
movq 0x58(%rsp), %rax
movq 0x28(%rax), %rax
movq %rax, 0x38(%rsp)
movq 0x58(%rsp), %rax
movq 0x28(%rax), %rax
movq %rax, 0x30(%rsp)
movq 0x58(%rsp), %rax
movq 0x28(%rax), %rax
movq 0x58(%rsp), %rcx
movl 0x20(%rcx), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
imulq $0x3, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x28(%rsp)
jmp 0x48af6
movq 0x30(%rsp), %rax
movslq 0x4c(%rsp), %rcx
movzbl (%rax,%rcx), %eax
cmpl 0x48(%rsp), %eax
jge 0x48b1a
movq 0x30(%rsp), %rax
addq $0x3, %rax
movq %rax, 0x30(%rsp)
jmp 0x48af6
jmp 0x48b1c
movq 0x28(%rsp), %rax
movslq 0x4c(%rsp), %rcx
movzbl (%rax,%rcx), %eax
cmpl 0x48(%rsp), %eax
jl 0x48b40
movq 0x28(%rsp), %rax
addq $-0x3, %rax
movq %rax, 0x28(%rsp)
jmp 0x48b1c
movq 0x30(%rsp), %rax
cmpq 0x28(%rsp), %rax
jb 0x48b4e
jmp 0x48b80
movq 0x30(%rsp), %rdi
leaq 0x25(%rsp), %rsi
callq 0x49b80
movq 0x28(%rsp), %rdi
movq 0x30(%rsp), %rsi
callq 0x49b80
leaq 0x25(%rsp), %rdi
movq 0x28(%rsp), %rsi
callq 0x49b80
jmp 0x48af4
movq 0x28(%rsp), %rax
movq 0x30(%rsp), %rcx
addq $-0x3, %rcx
cmpq %rcx, %rax
je 0x48ba1
leaq 0x25f28(%rip), %rdi     # 0x6eac2
movb $0x0, %al
callq 0xb580
movq 0x30(%rsp), %rax
movq 0x58(%rsp), %rcx
movq 0x28(%rcx), %rcx
subq %rcx, %rax
movl $0x3, %ecx
cqto
idivq %rcx
movl %eax, %ecx
movq 0x58(%rsp), %rax
movq 0x10(%rax), %rax
movl %ecx, 0x20(%rax)
movq 0x58(%rsp), %rax
movq 0x28(%rax), %rcx
movq 0x58(%rsp), %rax
movq 0x10(%rax), %rax
movq %rcx, 0x28(%rax)
movq 0x58(%rsp), %rax
movq 0x28(%rax), %rax
movq 0x58(%rsp), %rcx
movslq 0x20(%rcx), %rcx
imulq $0x3, %rcx, %rcx
addq %rcx, %rax
movq 0x30(%rsp), %rcx
subq %rcx, %rax
movl $0x3, %ecx
cqto
idivq %rcx
movl %eax, %ecx
movq 0x58(%rsp), %rax
movq 0x18(%rax), %rax
movl %ecx, 0x20(%rax)
movq 0x30(%rsp), %rcx
movq 0x58(%rsp), %rax
movq 0x18(%rax), %rax
movq %rcx, 0x28(%rax)
movq 0x58(%rsp), %rax
movq 0x10(%rax), %rax
cmpl $0x0, 0x20(%rax)
jle 0x48c58
movq 0x58(%rsp), %rax
movq 0x10(%rax), %rax
cvtsi2sdl 0x20(%rax), %xmm0
movq 0x58(%rsp), %rax
ucomisd 0x58(%rax), %xmm0
jne 0x48c58
jp 0x48c58
jmp 0x48c66
leaq 0x25e63(%rip), %rdi     # 0x6eac2
movb $0x0, %al
callq 0xb580
movq 0x58(%rsp), %rax
movq 0x18(%rax), %rax
cmpl $0x0, 0x20(%rax)
jle 0x48c93
movq 0x58(%rsp), %rax
movq 0x18(%rax), %rax
cvtsi2sdl 0x20(%rax), %xmm0
movq 0x58(%rsp), %rax
ucomisd 0x60(%rax), %xmm0
jne 0x48c93
jp 0x48c93
jmp 0x48ca1
leaq 0x25e28(%rip), %rdi     # 0x6eac2
movb $0x0, %al
callq 0xb580
movq 0x58(%rsp), %rax
movq 0x10(%rax), %rdi
callq 0x49470
movq 0x58(%rsp), %rax
movq 0x18(%rax), %rdi
callq 0x49470
movl 0x6c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x6c(%rsp)
jmp 0x48904
movl $0x0, 0x20(%rsp)
movl 0x20(%rsp), %eax
cmpl 0x7c(%rsp), %eax
jge 0x48df0
movq 0x70(%rsp), %rax
movslq 0x20(%rsp), %rcx
imulq $0x70, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x88(%rsp)
movq 0x98(%rsp), %rax
movslq 0x20(%rsp), %rcx
imulq $0x28, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x80(%rsp)
movq 0x88(%rsp), %rax
movb (%rax), %cl
movq 0x80(%rsp), %rax
andb $0x1, %cl
movb %cl, (%rax)
movq 0x88(%rsp), %rax
testb $0x1, (%rax)
jne 0x48dde
movq 0x88(%rsp), %rax
movl 0x50(%rax), %ecx
movq 0x80(%rsp), %rax
movl %ecx, 0x18(%rax)
movq 0x88(%rsp), %rax
movl 0x54(%rax), %ecx
movq 0x80(%rsp), %rax
movl %ecx, 0x1c(%rax)
movq 0x98(%rsp), %rcx
movq 0x88(%rsp), %rax
movq 0x10(%rax), %rax
movq 0x70(%rsp), %rdx
subq %rdx, %rax
movl $0x70, %esi
cqto
idivq %rsi
imulq $0x28, %rax, %rax
addq %rax, %rcx
movq 0x80(%rsp), %rax
movq %rcx, 0x8(%rax)
movq 0x98(%rsp), %rcx
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rax
movq 0x70(%rsp), %rdx
subq %rdx, %rax
movl $0x70, %esi
cqto
idivq %rsi
imulq $0x28, %rax, %rax
addq %rax, %rcx
movq 0x80(%rsp), %rax
movq %rcx, 0x10(%rax)
jmp 0x48de0
movl 0x20(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x20(%rsp)
jmp 0x48cd5
movq 0xa0(%rsp), %rax
movl $0x0, (%rax)
movq 0x70(%rsp), %rax
movq %rax, 0x88(%rsp)
jmp 0x48e0d
movq 0x88(%rsp), %rax
movb (%rax), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x48e1f
jmp 0x48e35
movq 0x88(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0x88(%rsp)
jmp 0x48e0d
movq 0x98(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x88(%rsp), %rax
movq 0x70(%rsp), %rcx
subq %rcx, %rax
movl $0x70, %ecx
cqto
idivq %rcx
movq %rax, %rcx
movq 0x10(%rsp), %rax
imulq $0x28, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x80(%rsp)
movq 0xa0(%rsp), %rax
movl (%rax), %ecx
movq 0x80(%rsp), %rax
movl %ecx, 0x20(%rax)
movl $0x0, 0x1c(%rsp)
cmpl $0x3, 0x1c(%rsp)
jge 0x48f67
movq 0x88(%rsp), %rax
movslq 0x1c(%rsp), %rcx
movsd 0x24640(%rip), %xmm0    # 0x6d4f0
addsd 0x30(%rax,%rcx,8), %xmm0
movsd 0x211aa(%rip), %xmm1    # 0x6a068
addsd %xmm1, %xmm0
callq 0x45a0
cvttsd2si %xmm0, %eax
movl %eax, 0x18(%rsp)
cmpl $0xff, 0x18(%rsp)
jge 0x48ee3
movl 0x18(%rsp), %eax
movl %eax, 0xc(%rsp)
jmp 0x48eee
movl $0xff, %eax
movl %eax, 0xc(%rsp)
jmp 0x48eee
movl 0xc(%rsp), %ecx
xorl %eax, %eax
cmpl %ecx, %eax
jle 0x48f00
xorl %eax, %eax
movl %eax, 0x8(%rsp)
jmp 0x48f27
cmpl $0xff, 0x18(%rsp)
jge 0x48f14
movl 0x18(%rsp), %eax
movl %eax, 0x4(%rsp)
jmp 0x48f1f
movl $0xff, %eax
movl %eax, 0x4(%rsp)
jmp 0x48f1f
movl 0x4(%rsp), %eax
movl %eax, 0x8(%rsp)
movl 0x8(%rsp), %eax
movl %eax, 0x18(%rsp)
movl 0x18(%rsp), %eax
movb %al, %dl
movq 0xa8(%rsp), %rax
movq 0xa0(%rsp), %rcx
movslq (%rcx), %rcx
imulq $0x3, %rcx, %rcx
addq %rcx, %rax
movslq 0x1c(%rsp), %rcx
movb %dl, (%rax,%rcx)
movl 0x1c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1c(%rsp)
jmp 0x48e90
movq 0xa0(%rsp), %rax
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
movq 0x88(%rsp), %rax
cmpq $0x0, 0x8(%rax)
je 0x48fb7
movq 0x88(%rsp), %rax
movq 0x88(%rsp), %rcx
movq 0x8(%rcx), %rcx
cmpq 0x10(%rcx), %rax
jne 0x48fa1
jmp 0x48fb7
movq 0x88(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x88(%rsp)
jmp 0x48f76
movq 0x88(%rsp), %rax
cmpq $0x0, 0x8(%rax)
jne 0x48fc8
jmp 0x48fe5
movq 0x88(%rsp), %rax
movq 0x8(%rax), %rax
movq 0x18(%rax), %rax
movq %rax, 0x88(%rsp)
jmp 0x48e0b
movq 0xa0(%rsp), %rax
movl (%rax), %eax
shll %eax
subl $0x1, %eax
cmpl 0x7c(%rsp), %eax
je 0x49008
leaq 0x25ac1(%rip), %rdi     # 0x6eac2
movb $0x0, %al
callq 0xb580
movq 0x90(%rsp), %rdi
callq 0x43a0
movq 0x70(%rsp), %rdi
callq 0x43a0
addq $0xc8, %rsp
retq
nopw (%rax,%rax)