2014 lines
62 KiB
C
2014 lines
62 KiB
C
|
/*
|
||
|
** Copyright 1991, 1922, Silicon Graphics, Inc.
|
||
|
** All Rights Reserved.
|
||
|
**
|
||
|
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
|
||
|
** the contents of this file may not be disclosed to third parties, copied or
|
||
|
** duplicated in any form, in whole or in part, without the prior written
|
||
|
** permission of Silicon Graphics, Inc.
|
||
|
**
|
||
|
** RESTRICTED RIGHTS LEGEND:
|
||
|
** Use, duplication or disclosure by the Government is subject to restrictions
|
||
|
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
|
||
|
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
|
||
|
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
|
||
|
** rights reserved under the Copyright Laws of the United States.
|
||
|
**
|
||
|
** Display list table management routines.
|
||
|
**
|
||
|
** $Revision: 1.3 $
|
||
|
** $Date: 1995/02/11 00:53:45 $
|
||
|
*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <namesint.h>
|
||
|
#include "..\..\dlist\dlistint.h"
|
||
|
|
||
|
/************************************************************************/
|
||
|
/*
|
||
|
** The Name Space Management code is used to store and retreive named
|
||
|
** data structures. The data being stored is referred to with void
|
||
|
** pointers to allow for the storage of any type of structure.
|
||
|
**
|
||
|
** Note that this code was developed for dlist name management.
|
||
|
** The bulk of it remains the same, but the semaphores for locking
|
||
|
** dlist access have been moved up one level. The code that uses
|
||
|
** this module for name space management must enclose the calls
|
||
|
** to Names entry points with LOCK and UNLOCK statements.
|
||
|
*/
|
||
|
/************************************************************************/
|
||
|
|
||
|
/*----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
** Internal data structures. Not intended for consumption outside of
|
||
|
** this module.
|
||
|
*/
|
||
|
/*----------------------------------------------------------------------*/
|
||
|
|
||
|
/*
|
||
|
** The name space is implemented as a 2-3 tree.
|
||
|
** The depth of the tree is the same for
|
||
|
** the entire tree (so we always know once we reach that depth that the
|
||
|
** node found is a leaf).
|
||
|
**
|
||
|
** A 2-3 tree in a nutshell goes like this:
|
||
|
**
|
||
|
** Every node at the maximum depth is a leaf, all other nodes are branch
|
||
|
** nodes and have 2 or 3 children.
|
||
|
**
|
||
|
** A new node can be inserted in O(depth) time and an old node can be deleted
|
||
|
** in O(depth) time. During this insertion or deletion, the tree is
|
||
|
** automatically rebalanced.
|
||
|
**
|
||
|
**
|
||
|
** Hmmm. Derrick Burns mentions splay trees. They would probably work
|
||
|
** as well if not better, and might be easier to code. Maybe later -- little
|
||
|
** point in re-writing working code.
|
||
|
**
|
||
|
** Leaf nodes are arrays of sequential display lists. The typical tree will
|
||
|
** actually only be one node (since users will define a few sequential
|
||
|
** lists, all of which fit into one leaf node).
|
||
|
**
|
||
|
** The range of display lists stored in a leaf is indicated by "start" and
|
||
|
** "end" (inclusive).
|
||
|
**
|
||
|
** There are two varieties of leaves. There are leaves which contain unused
|
||
|
** (but reserved) display lists. They are unique in that "lists" will be
|
||
|
** NULL. The other type of leaf contains display lists currently in use.
|
||
|
** "lists" will not be NULL for these leaves, and will point to an array
|
||
|
** containing the actual display lists.
|
||
|
**
|
||
|
** Leaves containing unused (but reserved) display lists are generated when
|
||
|
** the user calls glGenLists().
|
||
|
**
|
||
|
** As the user starts using these reserved lists, the leaf containing unused
|
||
|
** (reserved) lists is split into two (or sometimes three) leaves. One of
|
||
|
** the leaves will contain the display list the user is currently using, and
|
||
|
** the other will contain the rest of the still unused display lists.
|
||
|
**
|
||
|
** When this split takes place, the new leaf (containing the "now used" display
|
||
|
** lists) will be sized to __GL_DLIST_MIN_ARRAY_BLOCK entries if possible
|
||
|
** (with one of the array entries being the new display list, and the other
|
||
|
** entries pointing to a NOP dummy display list). As the user continues
|
||
|
** to define more and more display lists, the leaf containing a range
|
||
|
** of used display lists will continue to grow until it reaches a
|
||
|
** size of __GL_DLIST_MAX_ARRAY_BLOCK entries, at which point a new
|
||
|
** leaf will be created to hold additional lists.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
** A leaf node.
|
||
|
** The data pointers are void so diffent types of data structures can
|
||
|
** be managed. The dataInfo pointer points back to information needed
|
||
|
** to manage the specific data structure pointed to by a void pointer.
|
||
|
*/
|
||
|
struct __GLnamesLeafRec {
|
||
|
__GLnamesBranch *parent; /* parent node - must be first */
|
||
|
GLuint start; /* start of range */
|
||
|
GLuint end; /* end of range */
|
||
|
void **dataList; /* array of ptrs to named data */
|
||
|
__GLnamesArrayTypeInfo *dataInfo; /* ptr to data type info */
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
** A branch node.
|
||
|
** The section of the tree in children[0] has name values all <= low.
|
||
|
** The section in children[1] has values: low < value <= medium.
|
||
|
** The section in children[2] (if not NULL) has values > medium.
|
||
|
*/
|
||
|
struct __GLnamesBranchRec {
|
||
|
__GLnamesBranch *parent; /* parent node - must be first */
|
||
|
GLuint low; /* children[0] all <= low */
|
||
|
GLuint medium; /* children[1] all <= medium & > low */
|
||
|
__GLnamesBranch *children[3]; /* children[2] all > medium */
|
||
|
};
|
||
|
|
||
|
/*----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
** Name Space Manager internal routines.
|
||
|
*/
|
||
|
/*----------------------------------------------------------------------*/
|
||
|
|
||
|
/*
|
||
|
** Sets up a new names tree and returns a pointer to it.
|
||
|
*/
|
||
|
__GLnamesArray * FASTCALL __glNamesNewArray(__GLcontext *gc, __GLnamesArrayTypeInfo *dataInfo)
|
||
|
{
|
||
|
__GLnamesArray *array;
|
||
|
int i;
|
||
|
|
||
|
array = (__GLnamesArray *) GCALLOC(gc, sizeof(__GLnamesArray));
|
||
|
if (array == NULL) {
|
||
|
__glSetError(GL_OUT_OF_MEMORY);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
#ifdef NT
|
||
|
__try
|
||
|
{
|
||
|
InitializeCriticalSection(&array->critsec);
|
||
|
}
|
||
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
GCFREE(gc, array);
|
||
|
__glSetError(GL_OUT_OF_MEMORY);
|
||
|
return NULL;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
array->refcount = 1;
|
||
|
array->tree = NULL;
|
||
|
array->depth = 0;
|
||
|
array->dataInfo = dataInfo;
|
||
|
/*
|
||
|
** Pre-allocate a few leaves and branches for paranoid OUT_OF_MEMORY
|
||
|
** reasons.
|
||
|
*/
|
||
|
array->nbranches = __GL_DL_EXTRA_BRANCHES;
|
||
|
array->nleaves = __GL_DL_EXTRA_LEAVES;
|
||
|
for (i = 0; i < __GL_DL_EXTRA_BRANCHES; i++) {
|
||
|
array->branches[i] = (__GLnamesBranch*)
|
||
|
GCALLOC(gc, sizeof(__GLnamesBranch));
|
||
|
if (array->branches[i] == NULL) {
|
||
|
array->nbranches = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
for (i = 0; i < __GL_DL_EXTRA_LEAVES; i++) {
|
||
|
array->leaves[i] = (__GLnamesLeaf*)
|
||
|
GCALLOC(gc, sizeof(__GLnamesLeaf));
|
||
|
if (array->leaves[i] == NULL) {
|
||
|
array->nleaves = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return array;
|
||
|
}
|
||
|
|
||
|
static void FASTCALL freeLeafData(__GLcontext *gc, void **dataList)
|
||
|
{
|
||
|
/*
|
||
|
** Note that the actual data pointed to by the elements of this list
|
||
|
** have already been freed with the callback.
|
||
|
*/
|
||
|
GCFREE(gc, dataList);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void FASTCALL freeLeaf(__GLcontext *gc, __GLnamesLeaf *leaf)
|
||
|
{
|
||
|
if (leaf->dataList) {
|
||
|
freeLeafData(gc, leaf->dataList);
|
||
|
}
|
||
|
GCFREE(gc, leaf);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void FASTCALL freeBranch(__GLcontext *gc, __GLnamesBranch *branch)
|
||
|
{
|
||
|
GCFREE(gc, branch);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Free an entire names tree.
|
||
|
*/
|
||
|
void FASTCALL __glNamesFreeTree(__GLcontext *gc, __GLnamesArray *array,
|
||
|
__GLnamesBranch *tree, GLint depth)
|
||
|
{
|
||
|
GLuint i;
|
||
|
__GLnamesLeaf *leaf;
|
||
|
void *empty;
|
||
|
GLint maxdepth = array->depth;
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
if (tree == NULL) return;
|
||
|
|
||
|
if (depth < maxdepth) {
|
||
|
__glNamesFreeTree(gc, array, tree->children[2], depth+1);
|
||
|
__glNamesFreeTree(gc, array, tree->children[1], depth+1);
|
||
|
__glNamesFreeTree(gc, array, tree->children[0], depth+1);
|
||
|
|
||
|
freeBranch(gc, tree);
|
||
|
} else {
|
||
|
leaf = (__GLnamesLeaf *) tree;
|
||
|
empty = array->dataInfo->empty;
|
||
|
|
||
|
if (leaf->dataList) {
|
||
|
for (i=leaf->start; i<=leaf->end; i++) {
|
||
|
if (leaf->dataList[i - leaf->start] != empty) {
|
||
|
ASSERTOPENGL(leaf->dataInfo->free != NULL,
|
||
|
"No free function\n");
|
||
|
(*leaf->dataInfo->free)(gc,
|
||
|
leaf->dataList[i - leaf->start]);
|
||
|
leaf->dataList[i - leaf->start] = empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
freeLeaf(gc, leaf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FASTCALL __glNamesFreeArray(__GLcontext *gc, __GLnamesArray *array)
|
||
|
{
|
||
|
GLuint i;
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
for (i = 0; i < array->nbranches; i++) {
|
||
|
GCFREE(gc, array->branches[i]);
|
||
|
}
|
||
|
for (i = 0; i < array->nleaves; i++) {
|
||
|
GCFREE(gc, array->leaves[i]);
|
||
|
}
|
||
|
|
||
|
__glNamesFreeTree(gc, array, array->tree, 0);
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
#ifdef NT
|
||
|
DeleteCriticalSection(&array->critsec);
|
||
|
#endif
|
||
|
|
||
|
GCFREE(gc, array);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Find the leaf with the given name.
|
||
|
** If exact is TRUE, then only the leaf that contains this name will
|
||
|
** be returned (NULL, otherwise).
|
||
|
** If exact is FALSE, than the leaf containing the number will be returned
|
||
|
** if it exists, and otherwise the next highest leaf will be returned.
|
||
|
** A NULL value indicates that number is higher than any other leaves in
|
||
|
** the tree.
|
||
|
** This routine has been tuned for the case of finding the number in
|
||
|
** the tree, since this is the most likely case when dispatching a
|
||
|
** display list.
|
||
|
*/
|
||
|
static __GLnamesLeaf * FASTCALL findLeaf(__GLnamesArray *array, GLuint number,
|
||
|
GLint exact)
|
||
|
{
|
||
|
__GLnamesBranch *branch;
|
||
|
__GLnamesLeaf *leaf;
|
||
|
int depth = array->depth, r;
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
branch = array->tree;
|
||
|
|
||
|
while (depth > 0 && branch) {
|
||
|
|
||
|
/* rather than following if-then-else code
|
||
|
* for correct branch, evaluate all conditions
|
||
|
* quickly to compute correct branch.
|
||
|
*/
|
||
|
int r = (number > branch->low) + (number > branch->medium);
|
||
|
ASSERTOPENGL(branch->low <= branch->medium,
|
||
|
"Branch ordering wrong\n");
|
||
|
branch = branch->children[r];
|
||
|
--depth;
|
||
|
}
|
||
|
if (!(leaf = (__GLnamesLeaf *) branch)) return NULL;
|
||
|
|
||
|
/* the case we want to optimize is the one in which we
|
||
|
* actually find the node, so evaluate both conditions
|
||
|
* quickly, since both results are required in this case
|
||
|
* and return appropriately. the choice of the final
|
||
|
* if construct is to match the current vagaries of the
|
||
|
* 3.19 compiler code generator (db)
|
||
|
*/
|
||
|
r = (leaf->end < number) | (exact&(number<leaf->start));
|
||
|
if (!r) return leaf;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Copy data from leaf->lists into newleaf->lists.
|
||
|
*/
|
||
|
static void FASTCALL copyLeafInfo(__GLnamesLeaf *leaf, __GLnamesLeaf *newleaf)
|
||
|
{
|
||
|
GLint offset;
|
||
|
GLuint number;
|
||
|
GLuint i;
|
||
|
|
||
|
number = newleaf->end - newleaf->start + 1;
|
||
|
offset = newleaf->start - leaf->start;
|
||
|
|
||
|
for (i = 0; i < number; i++) {
|
||
|
newleaf->dataList[i] = leaf->dataList[i+offset];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Attempt to fix a possible situation caused by lack of memory.
|
||
|
*/
|
||
|
static GLboolean FASTCALL fixMemoryProblem(__GLcontext *gc, __GLnamesArray *array)
|
||
|
{
|
||
|
GLuint i;
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
for (i = array->nbranches; i < __GL_DL_EXTRA_BRANCHES; i++) {
|
||
|
array->branches[i] = (__GLnamesBranch*)
|
||
|
GCALLOC(gc, sizeof(__GLnamesBranch));
|
||
|
if (array->branches[i] == NULL) {
|
||
|
array->nbranches = i;
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
}
|
||
|
array->nbranches = __GL_DL_EXTRA_BRANCHES;
|
||
|
for (i = array->nleaves; i < __GL_DL_EXTRA_LEAVES; i++) {
|
||
|
array->leaves[i] = (__GLnamesLeaf*) GCALLOC(gc, sizeof(__GLnamesLeaf));
|
||
|
if (array->leaves[i] == NULL) {
|
||
|
array->nleaves = i;
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
}
|
||
|
array->nleaves = __GL_DL_EXTRA_LEAVES;
|
||
|
return GL_TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Compute the maximum value contained in the given tree. If
|
||
|
** curdepth == maxdepth, the tree is simply a leaf.
|
||
|
*/
|
||
|
static GLuint FASTCALL computeMax(__GLnamesBranch *branch, GLint curdepth,
|
||
|
GLint maxdepth)
|
||
|
{
|
||
|
__GLnamesLeaf *leaf;
|
||
|
|
||
|
while (curdepth < maxdepth) {
|
||
|
if (branch->children[2] != NULL) {
|
||
|
branch = branch->children[2];
|
||
|
} else if (branch->children[1] != NULL) {
|
||
|
return branch->medium;
|
||
|
} else {
|
||
|
return branch->low;
|
||
|
}
|
||
|
curdepth++;
|
||
|
}
|
||
|
leaf = (__GLnamesLeaf *) branch;
|
||
|
return leaf->end;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Make sure that all parents of this child know that maxval is the
|
||
|
** highest value that can be found in this child.
|
||
|
*/
|
||
|
static void FASTCALL pushMaxVal(__GLnamesBranch *child, GLuint maxval)
|
||
|
{
|
||
|
__GLnamesBranch *parent;
|
||
|
|
||
|
while (parent = child->parent) {
|
||
|
if (parent->children[0] == child) {
|
||
|
parent->low = maxval;
|
||
|
if (parent->children[1] != NULL) {
|
||
|
return;
|
||
|
}
|
||
|
} else if (parent->children[1] == child) {
|
||
|
parent->medium = maxval;
|
||
|
if (parent->children[2] != NULL) {
|
||
|
return;
|
||
|
}
|
||
|
} else {
|
||
|
ASSERTOPENGL(parent->children[2] == child,
|
||
|
"Parent/child relationship incorrect\n");
|
||
|
}
|
||
|
child = parent;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static GLboolean FASTCALL allocLeafData(__GLcontext *gc, __GLnamesLeaf *leaf)
|
||
|
{
|
||
|
GLint number;
|
||
|
GLint i;
|
||
|
|
||
|
number = leaf->end - leaf->start + 1;
|
||
|
leaf->dataList = (void **) GCALLOC(gc, (size_t)(sizeof(void *)*number));
|
||
|
if (!leaf->dataList) return GL_FALSE;
|
||
|
|
||
|
for (i=0; i < number; i++) {
|
||
|
leaf->dataList[i] = leaf->dataInfo->empty;
|
||
|
}
|
||
|
return GL_TRUE;
|
||
|
}
|
||
|
|
||
|
static GLboolean FASTCALL reallocLeafData(__GLcontext *gc, __GLnamesLeaf *leaf)
|
||
|
{
|
||
|
size_t number;
|
||
|
void **answer;
|
||
|
|
||
|
number = (size_t) (leaf->end - leaf->start + 1);
|
||
|
answer = (void **) GCREALLOC(gc, leaf->dataList, sizeof(void *)*number);
|
||
|
if (answer) {
|
||
|
leaf->dataList = answer;
|
||
|
return GL_TRUE;
|
||
|
} else {
|
||
|
/*
|
||
|
** Crud! Out of memory!
|
||
|
*/
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static __GLnamesLeaf * FASTCALL allocLeaf(__GLcontext *gc, __GLnamesArray *array)
|
||
|
{
|
||
|
__GLnamesLeaf *leaf;
|
||
|
|
||
|
leaf = (__GLnamesLeaf *) GCALLOC(gc, sizeof(__GLnamesLeaf));
|
||
|
|
||
|
if (leaf == NULL) {
|
||
|
/*
|
||
|
** Ouch! No memory? We had better use one of the preallocated
|
||
|
** leaves.
|
||
|
*/
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
ASSERTOPENGL(array->nleaves != 0,
|
||
|
"No preallocated leaves\n");
|
||
|
array->nleaves--;
|
||
|
leaf = array->leaves[array->nleaves];
|
||
|
}
|
||
|
|
||
|
leaf->parent = NULL;
|
||
|
leaf->dataList = NULL;
|
||
|
leaf->dataInfo = array->dataInfo;
|
||
|
|
||
|
return leaf;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Allocates a branch node.
|
||
|
*/
|
||
|
static __GLnamesBranch * FASTCALL allocBranch(__GLcontext *gc, __GLnamesArray *array)
|
||
|
{
|
||
|
__GLnamesBranch *branch;
|
||
|
|
||
|
branch = (__GLnamesBranch *) GCALLOC(gc, sizeof(__GLnamesBranch));
|
||
|
|
||
|
if (branch == NULL) {
|
||
|
/*
|
||
|
** Ouch! No memory? We had better use one of the preallocated
|
||
|
** branches.
|
||
|
*/
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
ASSERTOPENGL(array->nbranches != 0,
|
||
|
"No preallocated branches\n");
|
||
|
array->nbranches--;
|
||
|
branch = array->branches[array->nbranches];
|
||
|
}
|
||
|
|
||
|
branch->children[0] = branch->children[1] = branch->children[2] = NULL;
|
||
|
branch->parent = NULL;
|
||
|
|
||
|
return branch;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Remove the child from the parent. depth refers to the parent.
|
||
|
** This deletion may delete a child from a parent with only two children.
|
||
|
** If so, the parent itself will soon be deleted, of course.
|
||
|
*/
|
||
|
static void FASTCALL deleteChild(__GLnamesArray *array, __GLnamesBranch *parent,
|
||
|
__GLnamesBranch *child, GLint depth)
|
||
|
{
|
||
|
GLuint maxval;
|
||
|
GLint maxdepth;
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
maxdepth = array->depth;
|
||
|
|
||
|
if (parent->children[0] == child) {
|
||
|
parent->children[0] = parent->children[1];
|
||
|
parent->children[1] = parent->children[2];
|
||
|
parent->children[2] = NULL;
|
||
|
parent->low = parent->medium;
|
||
|
if (parent->children[1] != NULL) {
|
||
|
maxval = computeMax(parent->children[1], depth+1, maxdepth);
|
||
|
parent->medium = maxval;
|
||
|
} else parent->medium = 0;
|
||
|
} else if (parent->children[1] == child) {
|
||
|
parent->children[1] = parent->children[2];
|
||
|
parent->children[2] = NULL;
|
||
|
if (parent->children[1] != NULL) {
|
||
|
maxval = computeMax(parent->children[1], depth+1, maxdepth);
|
||
|
parent->medium = maxval;
|
||
|
} else parent->medium = 0;
|
||
|
} else {
|
||
|
ASSERTOPENGL(parent->children[2] == child,
|
||
|
"Parent/child relationship wrong\n");
|
||
|
parent->children[2] = NULL;
|
||
|
pushMaxVal(parent, parent->medium);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Add child to parent. child is a leaf if curdepth == maxdepth - 1
|
||
|
** (curdepth refers to the depth of the parent, not the child). Parent
|
||
|
** only has one or two children (thus has room for another child).
|
||
|
*/
|
||
|
static void FASTCALL addChild(__GLnamesBranch *parent, __GLnamesBranch *child,
|
||
|
GLint curdepth, GLint maxdepth)
|
||
|
{
|
||
|
GLuint maxval;
|
||
|
|
||
|
maxval = computeMax(child, curdepth+1, maxdepth);
|
||
|
|
||
|
child->parent = parent;
|
||
|
if (maxval > parent->medium && parent->children[1] != NULL) {
|
||
|
/* This becomes the third child */
|
||
|
parent->children[2] = child;
|
||
|
|
||
|
/* Propagate the maximum value for this child to its parents */
|
||
|
pushMaxVal(parent, maxval);
|
||
|
} else if (maxval > parent->low) {
|
||
|
/* This becomes the second child */
|
||
|
parent->children[2] = parent->children[1];
|
||
|
parent->children[1] = child;
|
||
|
parent->medium = maxval;
|
||
|
|
||
|
if (parent->children[2] == NULL) {
|
||
|
pushMaxVal(parent, maxval);
|
||
|
}
|
||
|
} else {
|
||
|
parent->children[2] = parent->children[1];
|
||
|
parent->children[1] = parent->children[0];
|
||
|
parent->children[0] = child;
|
||
|
parent->medium = parent->low;
|
||
|
parent->low = maxval;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** From the three children in parent, and the extraChild, build two parents:
|
||
|
** parent and newParent. curdepth refers to the depth of parent. parent
|
||
|
** is part of the tree, so its maxval needs to be propagated up if it
|
||
|
** changes.
|
||
|
*/
|
||
|
static void FASTCALL splitParent(__GLnamesBranch *parent,
|
||
|
__GLnamesBranch *newParent,
|
||
|
__GLnamesBranch *extraChild,
|
||
|
GLint curdepth,
|
||
|
GLint maxdepth)
|
||
|
{
|
||
|
__GLnamesBranch *children[4], *tempchild;
|
||
|
GLuint maxvals[4], tempval;
|
||
|
int i;
|
||
|
|
||
|
/* Collect our four children */
|
||
|
children[0] = parent->children[0];
|
||
|
maxvals[0] = parent->low;
|
||
|
children[1] = parent->children[1];
|
||
|
maxvals[1] = parent->medium;
|
||
|
children[2] = parent->children[2];
|
||
|
maxvals[2] = computeMax(children[2], curdepth+1, maxdepth);
|
||
|
children[3] = extraChild;
|
||
|
maxvals[3] = computeMax(extraChild, curdepth+1, maxdepth);
|
||
|
|
||
|
/* Children 0-2 are sorted. Sort child 3 too. */
|
||
|
for (i = 3; i > 0; i--) {
|
||
|
if (maxvals[i] < maxvals[i-1]) {
|
||
|
tempval = maxvals[i];
|
||
|
tempchild = children[i];
|
||
|
maxvals[i] = maxvals[i-1];
|
||
|
children[i] = children[i-1];
|
||
|
maxvals[i-1] = tempval;
|
||
|
children[i-1] = tempchild;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Construct the two parents */
|
||
|
parent->low = maxvals[0];
|
||
|
parent->children[0] = children[0];
|
||
|
parent->medium = maxvals[1];
|
||
|
parent->children[1] = children[1];
|
||
|
parent->children[2] = NULL;
|
||
|
children[0]->parent = parent;
|
||
|
children[1]->parent = parent;
|
||
|
pushMaxVal(parent, maxvals[1]);
|
||
|
|
||
|
newParent->low = maxvals[2];
|
||
|
newParent->children[0] = children[2];
|
||
|
newParent->medium = maxvals[3];
|
||
|
newParent->children[1] = children[3];
|
||
|
newParent->children[2] = NULL;
|
||
|
children[2]->parent = newParent;
|
||
|
children[3]->parent = newParent;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Build a parent from child1 and child2. depth tells the depth of
|
||
|
** the trees pointed to by child1 and child2.
|
||
|
*/
|
||
|
static void FASTCALL buildParent(__GLnamesBranch *parent, __GLnamesBranch *child1,
|
||
|
__GLnamesBranch *child2, GLint depth)
|
||
|
{
|
||
|
GLuint maxChild1, maxChild2;
|
||
|
|
||
|
child1->parent = parent;
|
||
|
child2->parent = parent;
|
||
|
maxChild1 = computeMax(child1, 0, depth);
|
||
|
maxChild2 = computeMax(child2, 0, depth);
|
||
|
if (maxChild2 > maxChild1) {
|
||
|
parent->children[0] = child1;
|
||
|
parent->low = maxChild1;
|
||
|
parent->children[1] = child2;
|
||
|
parent->medium = maxChild2;
|
||
|
} else {
|
||
|
parent->children[0] = child2;
|
||
|
parent->low = maxChild2;
|
||
|
parent->children[1] = child1;
|
||
|
parent->medium = maxChild1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Insert the new leaf into the tree.
|
||
|
*/
|
||
|
static void FASTCALL insertLeaf(__GLcontext *gc, __GLnamesArray *array,
|
||
|
__GLnamesLeaf *leaf)
|
||
|
{
|
||
|
__GLnamesBranch *extraChild;
|
||
|
__GLnamesBranch *branch;
|
||
|
__GLnamesBranch *parent;
|
||
|
__GLnamesBranch *newParent;
|
||
|
GLint maxdepth, curdepth;
|
||
|
GLuint number;
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
number = leaf->end;
|
||
|
maxdepth = array->depth;
|
||
|
branch = array->tree;
|
||
|
if (!branch) {
|
||
|
/* No tree! Make a one leaf tree. */
|
||
|
array->depth = 0;
|
||
|
array->tree = (__GLnamesBranch *) leaf;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
curdepth = 0;
|
||
|
while (curdepth < maxdepth) {
|
||
|
if (number <= branch->low) {
|
||
|
branch = branch->children[0];
|
||
|
} else if (number <= branch->medium) {
|
||
|
branch = branch->children[1];
|
||
|
} else {
|
||
|
if (branch->children[2] != NULL) {
|
||
|
branch = branch->children[2];
|
||
|
} else {
|
||
|
branch = branch->children[1];
|
||
|
}
|
||
|
}
|
||
|
curdepth++;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Ok, we just managed to work our way to the bottom of the tree.
|
||
|
** 'leaf' becomes the extraChild, and we now try to insert it anywhere
|
||
|
** it will fit.
|
||
|
*/
|
||
|
extraChild = (__GLnamesBranch *) leaf;
|
||
|
parent = branch->parent;
|
||
|
|
||
|
curdepth--;
|
||
|
while (parent) {
|
||
|
if (parent->children[2] == NULL) {
|
||
|
/* We have room to squeeze this node in here! */
|
||
|
addChild(parent, extraChild, curdepth, maxdepth);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** We have one parent and four children. This simply
|
||
|
** won't do. We create a new parent, and end up with two
|
||
|
** parents with two children each. That works.
|
||
|
*/
|
||
|
newParent = allocBranch(gc, array);
|
||
|
splitParent(parent, newParent, extraChild, curdepth, maxdepth);
|
||
|
|
||
|
/*
|
||
|
** Great. Now newParent becomes the orphan, and we try to
|
||
|
** trivially insert it up a level.
|
||
|
*/
|
||
|
extraChild = newParent;
|
||
|
branch = parent;
|
||
|
parent = branch->parent;
|
||
|
curdepth--;
|
||
|
}
|
||
|
|
||
|
/* We just reached the top node, and there is no parent, and we
|
||
|
** still haven't managed to rid ourselves of an extra child. So,
|
||
|
** we make a new parent to take branch and extraChild as it's two
|
||
|
** children. We have to increase the depth of the tree, of course.
|
||
|
*/
|
||
|
ASSERTOPENGL(curdepth == -1, "Wrong depth at top\n");
|
||
|
parent = allocBranch(gc, array);
|
||
|
buildParent(parent, branch, extraChild, maxdepth);
|
||
|
array->tree = parent;
|
||
|
array->depth++;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Delete the given leaf from the tree. The leaf itself is not
|
||
|
** freed or anything, so the calling procedure needs to worry about it.
|
||
|
*/
|
||
|
static void FASTCALL deleteLeaf(__GLcontext *gc, __GLnamesArray *array,
|
||
|
__GLnamesLeaf *leaf)
|
||
|
{
|
||
|
__GLnamesBranch *orphan;
|
||
|
__GLnamesBranch *parent, *newParent;
|
||
|
__GLnamesBranch *grandparent;
|
||
|
GLint depth, maxdepth;
|
||
|
GLuint maxval;
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
maxdepth = depth = array->depth;
|
||
|
parent = leaf->parent;
|
||
|
if (parent == NULL) {
|
||
|
/* Ack! We just nuked the only node! */
|
||
|
array->tree = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
deleteChild(array, parent, (__GLnamesBranch *) leaf, depth-1);
|
||
|
|
||
|
/*
|
||
|
** depth is the depth of the child in this case.
|
||
|
*/
|
||
|
depth--;
|
||
|
while (parent->children[1] == NULL) {
|
||
|
/* Crud. Need to do work. */
|
||
|
orphan = parent->children[0];
|
||
|
|
||
|
/* Ax the parent, insert child into grandparent. */
|
||
|
grandparent = parent->parent;
|
||
|
|
||
|
if (grandparent == NULL) {
|
||
|
/*
|
||
|
** Hmmm. Parent was the root. Nuke it and make the orphan
|
||
|
** the new root.
|
||
|
*/
|
||
|
freeBranch(gc, parent);
|
||
|
array->tree = orphan;
|
||
|
orphan->parent = NULL;
|
||
|
array->depth--;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
deleteChild(array, grandparent, parent, depth-1);
|
||
|
freeBranch(gc, parent);
|
||
|
|
||
|
/* The parent is dead. Find a new parent. */
|
||
|
maxval = computeMax(orphan, depth+1, maxdepth);
|
||
|
if (grandparent->children[1] == NULL ||
|
||
|
maxval <= grandparent->low) {
|
||
|
parent = grandparent->children[0];
|
||
|
} else {
|
||
|
parent = grandparent->children[1];
|
||
|
}
|
||
|
|
||
|
/* Insert orphan into new parent. */
|
||
|
if (parent->children[2] != NULL) {
|
||
|
newParent = allocBranch(gc, array);
|
||
|
splitParent(parent, newParent, orphan, depth, maxdepth);
|
||
|
/* We know there is room! */
|
||
|
addChild(grandparent, newParent, depth-1, maxdepth);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* The parent has room for the child */
|
||
|
addChild(parent, orphan, depth, maxdepth);
|
||
|
|
||
|
depth--;
|
||
|
parent = grandparent;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Shrink the leaf by adjusting start and end.
|
||
|
** If necessary, call pushMaxVal() to notify the database about the change.
|
||
|
** Also fix up the lists pointer if necessary.
|
||
|
*/
|
||
|
static void FASTCALL resizeLeaf(__GLcontext *gc, __GLnamesLeaf *leaf,
|
||
|
GLuint newstart, GLuint newend)
|
||
|
{
|
||
|
GLuint oldstart, oldend;
|
||
|
GLuint newsize, offset, i;
|
||
|
|
||
|
oldstart = leaf->start;
|
||
|
oldend = leaf->end;
|
||
|
|
||
|
leaf->start = newstart;
|
||
|
if (newend != oldend) {
|
||
|
leaf->end = newend;
|
||
|
pushMaxVal((__GLnamesBranch *) leaf, newend);
|
||
|
}
|
||
|
if (leaf->dataList == NULL) return;
|
||
|
|
||
|
/*
|
||
|
** Copy the appropriate pointers to the begining of the array, and
|
||
|
** realloc it.
|
||
|
*/
|
||
|
offset = newstart - oldstart;
|
||
|
newsize = newend - newstart + 1;
|
||
|
if (offset) {
|
||
|
for (i=0; i<newsize; i++) {
|
||
|
/*
|
||
|
** Copy the whole structure with one line.
|
||
|
*/
|
||
|
leaf->dataList[i] = leaf->dataList[i+offset];
|
||
|
}
|
||
|
}
|
||
|
reallocLeafData(gc, leaf);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Find the previous leaf (before "leaf") in the tree.
|
||
|
*/
|
||
|
static __GLnamesLeaf * FASTCALL prevLeaf(__GLnamesLeaf *leaf)
|
||
|
{
|
||
|
__GLnamesBranch *branch, *child;
|
||
|
GLint reldepth;
|
||
|
|
||
|
branch = leaf->parent;
|
||
|
if (!branch) return NULL; /* A one leaf tree! */
|
||
|
|
||
|
child = (__GLnamesBranch *) leaf;
|
||
|
|
||
|
/* We start off at a relative depth of 1 above the child (-1) */
|
||
|
reldepth = -1;
|
||
|
|
||
|
while (branch) {
|
||
|
/* If the child was the 3rd child, branch down to the second. */
|
||
|
if (branch->children[2] == child) {
|
||
|
branch = branch->children[1];
|
||
|
reldepth++; /* One level lower */
|
||
|
break;
|
||
|
} else if (branch->children[1] == child) {
|
||
|
/* If the child was the 2nd child, branch down to the first */
|
||
|
branch = branch->children[0];
|
||
|
reldepth++; /* One level lower */
|
||
|
break;
|
||
|
} else {
|
||
|
/* Must have been 1st child */
|
||
|
ASSERTOPENGL(branch->children[0] == child,
|
||
|
"Parent/child relationship wrong\n");
|
||
|
}
|
||
|
/*
|
||
|
** Otherwise, we have already visited all of this branch's children,
|
||
|
** so we go up a level.
|
||
|
*/
|
||
|
child = branch;
|
||
|
branch = branch->parent;
|
||
|
reldepth--; /* One level higher */
|
||
|
}
|
||
|
if (!branch) return NULL; /* All leaves visited! */
|
||
|
|
||
|
/* Go down the 'right'most trail of this branch until we get to
|
||
|
** a child, then return it.
|
||
|
*/
|
||
|
while (reldepth) {
|
||
|
if (branch->children[2] != NULL) {
|
||
|
branch = branch->children[2];
|
||
|
} else if (branch->children[1] != NULL) {
|
||
|
branch = branch->children[1];
|
||
|
} else {
|
||
|
branch = branch->children[0];
|
||
|
}
|
||
|
reldepth++; /* One level lower */
|
||
|
}
|
||
|
|
||
|
return (__GLnamesLeaf *) branch;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Find the first leaf in the tree.
|
||
|
*/
|
||
|
static __GLnamesLeaf * FASTCALL firstLeaf(__GLnamesArray *array)
|
||
|
{
|
||
|
__GLnamesBranch *branch;
|
||
|
GLint maxdepth, curdepth;
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
maxdepth = array->depth;
|
||
|
curdepth = 0;
|
||
|
branch = array->tree;
|
||
|
|
||
|
/* No tree, no leaves! */
|
||
|
if (!branch) return NULL;
|
||
|
|
||
|
/* Take the 'left'most branch until we reach a leaf */
|
||
|
while (curdepth != maxdepth) {
|
||
|
branch = branch->children[0];
|
||
|
curdepth++;
|
||
|
}
|
||
|
return (__GLnamesLeaf *) branch;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Find the next leaf (after "leaf") in the tree.
|
||
|
*/
|
||
|
static __GLnamesLeaf * FASTCALL nextLeaf(__GLnamesLeaf *leaf)
|
||
|
{
|
||
|
__GLnamesBranch *branch, *child;
|
||
|
GLint reldepth;
|
||
|
|
||
|
branch = leaf->parent;
|
||
|
if (!branch) return NULL; /* A one leaf tree! */
|
||
|
|
||
|
child = (__GLnamesBranch *) leaf;
|
||
|
|
||
|
/* We start off at a relative depth of 1 above the child (-1) */
|
||
|
reldepth = -1;
|
||
|
|
||
|
while (branch) {
|
||
|
/* If the child was the 1st child, branch down to the second. */
|
||
|
if (branch->children[0] == child) {
|
||
|
branch = branch->children[1];
|
||
|
reldepth++; /* One level lower */
|
||
|
break;
|
||
|
} else if (branch->children[1] == child) {
|
||
|
/*
|
||
|
** If the child was the 2nd child, and there is a third, branch
|
||
|
** down to it.
|
||
|
*/
|
||
|
if (branch->children[2] != NULL) {
|
||
|
branch = branch->children[2];
|
||
|
reldepth++; /* One level lower */
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
/* Must have been 3rd child */
|
||
|
ASSERTOPENGL(branch->children[2] == child,
|
||
|
"Parent/child relationship wrong\n");
|
||
|
}
|
||
|
/*
|
||
|
** Otherwise, we have already visited all of this branch's children,
|
||
|
** so we go up a level.
|
||
|
*/
|
||
|
child = branch;
|
||
|
branch = branch->parent;
|
||
|
reldepth--; /* One level higher */
|
||
|
}
|
||
|
if (!branch) return NULL; /* All leaves visited! */
|
||
|
|
||
|
/* Go down the 'left'most trail of this branch until we get to
|
||
|
** a child, then return it.
|
||
|
*/
|
||
|
while (reldepth) {
|
||
|
branch = branch->children[0];
|
||
|
reldepth++; /* One level lower */
|
||
|
}
|
||
|
|
||
|
return (__GLnamesLeaf *) branch;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Merge leaf2 into leaf1, and free leaf2.
|
||
|
** Need to pushMaxVal on the new leaf.
|
||
|
** We can assume that leaf1 and leaf2 are fit for merging.
|
||
|
** The return value is GL_TRUE if we did it.
|
||
|
*/
|
||
|
static GLboolean FASTCALL mergeLeaves(__GLcontext *gc, __GLnamesLeaf *leaf1,
|
||
|
__GLnamesLeaf *leaf2)
|
||
|
{
|
||
|
GLuint end;
|
||
|
GLuint i;
|
||
|
GLuint number, offset;
|
||
|
|
||
|
/* If we don't have to merge lists, it is easy. */
|
||
|
if (leaf1->dataList == NULL) {
|
||
|
ASSERTOPENGL(leaf2->dataList == NULL, "Data already exists\n");
|
||
|
if (leaf1->start < leaf2->start) {
|
||
|
leaf1->end = leaf2->end;
|
||
|
pushMaxVal((__GLnamesBranch *) leaf1, leaf1->end);
|
||
|
} else {
|
||
|
leaf1->start = leaf2->start;
|
||
|
}
|
||
|
freeLeaf(gc, leaf2);
|
||
|
return GL_TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Yick! Need to merge lists.
|
||
|
*/
|
||
|
ASSERTOPENGL(leaf2->dataList != NULL, "No data\n");
|
||
|
if (leaf1->start < leaf2->start) {
|
||
|
/*
|
||
|
** Expand size of leaf1's array, copy leaf2's array into it,
|
||
|
** free leaf2.
|
||
|
*/
|
||
|
offset = leaf1->end - leaf1->start + 1;
|
||
|
number = leaf2->end - leaf2->start + 1;
|
||
|
end = leaf1->end;
|
||
|
leaf1->end = leaf2->end;
|
||
|
if (!reallocLeafData(gc, leaf1)) {
|
||
|
/*
|
||
|
** Heavens! No memory? That sucks!
|
||
|
** We won't bother merging. It is never an absolutely critical
|
||
|
** operation.
|
||
|
*/
|
||
|
leaf1->end = end;
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
for (i = 0; i < number; i++) {
|
||
|
leaf1->dataList[i+offset] = leaf2->dataList[i];
|
||
|
}
|
||
|
|
||
|
freeLeaf(gc, leaf2);
|
||
|
|
||
|
pushMaxVal((__GLnamesBranch *) leaf1, leaf1->end);
|
||
|
} else {
|
||
|
/*
|
||
|
** Expand the size of leaf2's array, copy leaf1's array into it.
|
||
|
** Then free leaf1's array, copy leaf2's array to leaf1, and free
|
||
|
** leaf2.
|
||
|
*/
|
||
|
offset = leaf2->end - leaf2->start + 1;
|
||
|
number = leaf1->end - leaf1->start + 1;
|
||
|
end = leaf2->end;
|
||
|
leaf2->end = leaf1->end;
|
||
|
if (!reallocLeafData(gc, leaf2)) {
|
||
|
/*
|
||
|
** Heavens! No memory? That sucks!
|
||
|
** We won't bother merging. It is never an absolutely critical
|
||
|
** operation.
|
||
|
*/
|
||
|
leaf2->end = end;
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
for (i = 0; i < number; i++) {
|
||
|
leaf2->dataList[i+offset] = leaf1->dataList[i];
|
||
|
}
|
||
|
|
||
|
freeLeafData(gc, leaf1->dataList);
|
||
|
leaf1->start = leaf2->start;
|
||
|
|
||
|
leaf1->dataList = leaf2->dataList;
|
||
|
leaf2->dataList = NULL;
|
||
|
freeLeaf(gc, leaf2);
|
||
|
}
|
||
|
return GL_TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Check if this leaf can merge with any neighbors, and if so, do it.
|
||
|
*/
|
||
|
static void FASTCALL mergeLeaf(__GLcontext *gc, __GLnamesArray *array,
|
||
|
__GLnamesLeaf *leaf)
|
||
|
{
|
||
|
__GLnamesLeaf *next, *prev;
|
||
|
|
||
|
__GL_NAMES_ASSERT_LOCKED(array);
|
||
|
|
||
|
next = nextLeaf(leaf);
|
||
|
if (next) {
|
||
|
/* Try to merge with next leaf */
|
||
|
if (leaf->end + 1 == next->start) {
|
||
|
if ((leaf->dataList == NULL && next->dataList == NULL) ||
|
||
|
(next->dataList && leaf->dataList &&
|
||
|
next->end - leaf->start < (GLuint) __GL_DLIST_MAX_ARRAY_BLOCK)) {
|
||
|
/* It's legal to merge these leaves */
|
||
|
deleteLeaf(gc, array, next);
|
||
|
if (!mergeLeaves(gc, leaf, next)) {
|
||
|
/*
|
||
|
** Ack! No memory? We bail on the merge.
|
||
|
*/
|
||
|
insertLeaf(gc, array, next);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
prev = prevLeaf(leaf);
|
||
|
if (prev) {
|
||
|
/* Try to merge with prev leaf */
|
||
|
if (prev->end + 1 == leaf->start) {
|
||
|
if ((prev->dataList == NULL && leaf->dataList == NULL) ||
|
||
|
(leaf->dataList && prev->dataList &&
|
||
|
leaf->end - prev->start < (GLuint) __GL_DLIST_MAX_ARRAY_BLOCK)) {
|
||
|
/* It's legal to merge these leaves */
|
||
|
deleteLeaf(gc, array, prev);
|
||
|
if (!mergeLeaves(gc, leaf, prev)) {
|
||
|
/*
|
||
|
** Ack! No memory? We bail on the merge.
|
||
|
*/
|
||
|
insertLeaf(gc, array, prev);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GLboolean FASTCALL __glNamesNewData(__GLcontext *gc, __GLnamesArray *array,
|
||
|
GLuint name, void *data)
|
||
|
{
|
||
|
__GLnamesLeaf *leaf, *newleaf;
|
||
|
GLint entry;
|
||
|
GLuint start, end;
|
||
|
|
||
|
__GL_NAMES_LOCK(array);
|
||
|
|
||
|
leaf = findLeaf(array, name, GL_TRUE);
|
||
|
|
||
|
/*
|
||
|
** First we check for possible memory problems, since it will be
|
||
|
** difficult to back out once we start.
|
||
|
*/
|
||
|
if (leaf == NULL || leaf->dataList == NULL) {
|
||
|
/*
|
||
|
** May need memory in these cases.
|
||
|
*/
|
||
|
if (array->nbranches != __GL_DL_EXTRA_BRANCHES ||
|
||
|
array->nleaves != __GL_DL_EXTRA_LEAVES) {
|
||
|
if (!fixMemoryProblem(gc, array)) {
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
__glSetError(GL_OUT_OF_MEMORY);
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!leaf) {
|
||
|
/*
|
||
|
** Make new leaf with just this display list
|
||
|
*/
|
||
|
leaf = allocLeaf(gc, array);
|
||
|
leaf->start = leaf->end = name;
|
||
|
if (data) {
|
||
|
if (!allocLeafData(gc, leaf)) {
|
||
|
/*
|
||
|
** Bummer. No new list for you!
|
||
|
*/
|
||
|
freeLeaf(gc, leaf);
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
__glSetError(GL_OUT_OF_MEMORY);
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
leaf->dataList[0] = data;
|
||
|
(*(GLint *)data) = 1; /* set the refcount */
|
||
|
}
|
||
|
insertLeaf(gc, array, leaf);
|
||
|
mergeLeaf(gc, array, leaf);
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return GL_TRUE;
|
||
|
} else if (leaf->dataList) {
|
||
|
/*
|
||
|
** Simply update the appropriate entry in the lists array
|
||
|
*/
|
||
|
entry = name - leaf->start;
|
||
|
if (leaf->dataList[entry] != leaf->dataInfo->empty) {
|
||
|
ASSERTOPENGL(leaf->dataInfo->free != NULL,
|
||
|
"No free function\n");
|
||
|
(*leaf->dataInfo->free)(gc, leaf->dataList[entry]);
|
||
|
leaf->dataList[entry] = leaf->dataInfo->empty;
|
||
|
}
|
||
|
if (data) {
|
||
|
leaf->dataList[entry] = data;
|
||
|
(*(GLint *)data) = 1; /* set the refcount */
|
||
|
}
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return GL_TRUE;
|
||
|
} else {
|
||
|
if (!data) {
|
||
|
/*
|
||
|
** If there isn't really any list, we are done.
|
||
|
*/
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return GL_TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Allocate some or all of the lists in leaf. If only some, then
|
||
|
** leaf needs to be split into two or three leaves.
|
||
|
**
|
||
|
** First we decide what range of numbers to allocate an array for.
|
||
|
** (be careful of possible word wrap error)
|
||
|
*/
|
||
|
start = name - __GL_DLIST_MIN_ARRAY_BLOCK/2;
|
||
|
if (start < leaf->start || start > name) {
|
||
|
start = leaf->start;
|
||
|
}
|
||
|
end = start + __GL_DLIST_MIN_ARRAY_BLOCK - 1;
|
||
|
if (end > leaf->end || end < start) {
|
||
|
end = leaf->end;
|
||
|
}
|
||
|
|
||
|
if (start - leaf->start < (GLuint) __GL_DLIST_MIN_ARRAY_BLOCK) {
|
||
|
start = leaf->start;
|
||
|
}
|
||
|
if (leaf->end - end < (GLuint) __GL_DLIST_MIN_ARRAY_BLOCK) {
|
||
|
end = leaf->end;
|
||
|
}
|
||
|
|
||
|
if (start == leaf->start) {
|
||
|
if (end == leaf->end) {
|
||
|
/*
|
||
|
** Simply allocate the entire array.
|
||
|
*/
|
||
|
if (!allocLeafData(gc, leaf)) {
|
||
|
/*
|
||
|
** Whoa! No memory! Never mind!
|
||
|
*/
|
||
|
__glSetError(GL_OUT_OF_MEMORY);
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
{
|
||
|
GLint entry = name - leaf->start;
|
||
|
leaf->dataList[entry] = data;
|
||
|
(*(GLint *)data) = 1; /* set the refcount */
|
||
|
}
|
||
|
mergeLeaf(gc, array, leaf);
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return GL_TRUE;
|
||
|
} else {
|
||
|
/*
|
||
|
** Shrink the existing leaf, and create a new one to hold
|
||
|
** the new arrays (done outside the "if" statement).
|
||
|
*/
|
||
|
resizeLeaf(gc, leaf, end+1, leaf->end);
|
||
|
}
|
||
|
} else if (end == leaf->end) {
|
||
|
/*
|
||
|
** Shrink the existing leaf, and create a new one to hold
|
||
|
** the new arrays (done outside the "if" statement).
|
||
|
*/
|
||
|
resizeLeaf(gc, leaf, leaf->start, start-1);
|
||
|
} else {
|
||
|
/*
|
||
|
** Crud. The middle of the leaf was deleted. This is tough.
|
||
|
*/
|
||
|
newleaf = allocLeaf(gc, array);
|
||
|
|
||
|
newleaf->start = end+1;
|
||
|
newleaf->end = leaf->end;
|
||
|
resizeLeaf(gc, leaf, leaf->start, start-1);
|
||
|
insertLeaf(gc, array, newleaf);
|
||
|
}
|
||
|
leaf = allocLeaf(gc, array);
|
||
|
leaf->start = start;
|
||
|
leaf->end = end;
|
||
|
if (!allocLeafData(gc, leaf)) {
|
||
|
/*
|
||
|
** Whoa! No memory! Never mind!
|
||
|
*/
|
||
|
insertLeaf(gc, array, leaf);
|
||
|
mergeLeaf(gc, array, leaf);
|
||
|
__glSetError(GL_OUT_OF_MEMORY);
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return GL_FALSE;
|
||
|
}
|
||
|
{
|
||
|
GLint entry = name - leaf->start;
|
||
|
leaf->dataList[entry] = data;
|
||
|
(*(GLint *)data) = 1; /* set the refcount */
|
||
|
}
|
||
|
insertLeaf(gc, array, leaf);
|
||
|
mergeLeaf(gc, array, leaf);
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return GL_TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Lock the named data. Locking data both looks the data up,
|
||
|
** and guarantees that another thread will not delete the data out from
|
||
|
** under us. This data will be unlocked with __glNamesUnlockData().
|
||
|
**
|
||
|
** A return value of NULL indicates that no data with the specified name
|
||
|
** was found.
|
||
|
*/
|
||
|
void * FASTCALL __glNamesLockData(__GLcontext *gc, __GLnamesArray *array,
|
||
|
GLuint name)
|
||
|
{
|
||
|
__GLnamesLeaf *leaf;
|
||
|
void *data;
|
||
|
GLint offset;
|
||
|
|
||
|
__GL_NAMES_LOCK(array);
|
||
|
|
||
|
/*
|
||
|
** Lock access to data.
|
||
|
*/
|
||
|
leaf = findLeaf(array, name, GL_TRUE);
|
||
|
if (leaf == NULL || leaf->dataList == NULL) {
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return NULL;
|
||
|
}
|
||
|
offset = name - leaf->start;
|
||
|
data = leaf->dataList[offset];
|
||
|
if (data) {
|
||
|
(*(GLint *)data)++; /* Increment the refcount. */
|
||
|
}
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Lock all of the data in the user's names array. Locking data
|
||
|
** both looks the data up, and guarantees that another thread will not
|
||
|
** delete the data out from under us. These data structs will be unlocked
|
||
|
** with __glNamesUnlockDataList().
|
||
|
**
|
||
|
** All entries of the array are guaranteed to be non-NULL. This is
|
||
|
** accomplished by sticking an empty data structure in those slots where
|
||
|
** no data was set.
|
||
|
*/
|
||
|
void FASTCALL __glNamesLockDataList(__GLcontext *gc, __GLnamesArray *array,
|
||
|
GLsizei n, GLenum type, GLuint base,
|
||
|
const GLvoid *names, void *dataPtrs[])
|
||
|
{
|
||
|
__GLnamesLeaf *leaf;
|
||
|
void **data;
|
||
|
void *tempData;
|
||
|
void *empty;
|
||
|
GLuint curName;
|
||
|
|
||
|
__GL_NAMES_LOCK(array);
|
||
|
|
||
|
empty = array->dataInfo->empty;
|
||
|
|
||
|
data = dataPtrs;
|
||
|
|
||
|
/*
|
||
|
** Note that this code is designed to take advantage of coherence.
|
||
|
** After looking up (and locking) a single display list in
|
||
|
** listnums[], the next list is checked for in the same leaf that
|
||
|
** contained the previous. This will make typical uses of CallLists()
|
||
|
** quite fast (text, for example).
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
** Lock access to array.
|
||
|
*/
|
||
|
switch(type) {
|
||
|
case GL_BYTE:
|
||
|
/*
|
||
|
** Coded poorly for optimization purposes
|
||
|
*/
|
||
|
{
|
||
|
const GLbyte *p = (const GLbyte *) names;
|
||
|
|
||
|
Bstart:
|
||
|
if (--n >= 0) {
|
||
|
/* Optimization for possibly common font case */
|
||
|
curName = base + *p++;
|
||
|
Bfind:
|
||
|
leaf = findLeaf(array, curName, GL_TRUE);
|
||
|
if (leaf && leaf->dataList) {
|
||
|
GLint reldiff;
|
||
|
GLuint relend;
|
||
|
void **leafData;
|
||
|
|
||
|
leafData = leaf->dataList;
|
||
|
tempData = leafData[curName - leaf->start];
|
||
|
|
||
|
/* All possible display lists can be found here */
|
||
|
reldiff = base - leaf->start;
|
||
|
relend = leaf->end - leaf->start;
|
||
|
|
||
|
Bsave:
|
||
|
(*(GLint *)tempData)++; /* increment the refcount */
|
||
|
*data++ = tempData;
|
||
|
if (--n >= 0) {
|
||
|
curName = *p++ + reldiff;
|
||
|
if (curName <= relend) {
|
||
|
tempData = leafData[curName];
|
||
|
goto Bsave;
|
||
|
}
|
||
|
curName = curName + leaf->start;
|
||
|
goto Bfind;
|
||
|
}
|
||
|
} else {
|
||
|
(*(GLint *)empty)++; /* increment refcount */
|
||
|
*data++ = empty;
|
||
|
goto Bstart;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case GL_UNSIGNED_BYTE:
|
||
|
/*
|
||
|
** Coded poorly for optimization purposes
|
||
|
*/
|
||
|
{
|
||
|
const GLubyte *p = (const GLubyte *) names;
|
||
|
|
||
|
UBstart:
|
||
|
if (--n >= 0) {
|
||
|
/* Optimization for possibly common font case */
|
||
|
curName = base + *p++;
|
||
|
UBfind:
|
||
|
leaf = findLeaf(array, curName, GL_TRUE);
|
||
|
if (leaf && leaf->dataList) {
|
||
|
GLint reldiff;
|
||
|
GLuint relend;
|
||
|
void **leafData;
|
||
|
|
||
|
leafData = leaf->dataList;
|
||
|
tempData = leafData[curName - leaf->start];
|
||
|
|
||
|
/* All possible display lists can be found here */
|
||
|
reldiff = base - leaf->start;
|
||
|
relend = leaf->end - leaf->start;
|
||
|
|
||
|
UBsave:
|
||
|
(*(GLint *)tempData)++; /* increment the refcount */
|
||
|
*data++ = tempData;
|
||
|
if (--n >= 0) {
|
||
|
curName = *p++ + reldiff;
|
||
|
if (curName <= relend) {
|
||
|
tempData = leafData[curName];
|
||
|
goto UBsave;
|
||
|
}
|
||
|
curName = curName + leaf->start;
|
||
|
goto UBfind;
|
||
|
}
|
||
|
} else {
|
||
|
(*(GLint *)empty)++; /* increment refcount */
|
||
|
*data++ = empty;
|
||
|
goto UBstart;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case GL_SHORT:
|
||
|
{
|
||
|
const GLshort *p = (const GLshort *) names;
|
||
|
leaf = NULL;
|
||
|
while (--n >= 0) {
|
||
|
curName = base + *p++;
|
||
|
if (leaf==NULL || curName<leaf->start || curName>leaf->end) {
|
||
|
leaf = findLeaf(array, curName, GL_TRUE);
|
||
|
}
|
||
|
if (leaf && leaf->dataList) {
|
||
|
tempData = leaf->dataList[curName - leaf->start];
|
||
|
(*(GLint *)tempData)++; /* increment the refcount */
|
||
|
*data++ = tempData;
|
||
|
} else {
|
||
|
(*(GLint *)empty)++; /* increment refcount */
|
||
|
*data++ = empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case GL_UNSIGNED_SHORT:
|
||
|
{
|
||
|
const GLushort *p = (const GLushort *) names;
|
||
|
leaf = NULL;
|
||
|
while (--n >= 0) {
|
||
|
curName = base + *p++;
|
||
|
if (leaf==NULL || curName<leaf->start || curName>leaf->end) {
|
||
|
leaf = findLeaf(array, curName, GL_TRUE);
|
||
|
}
|
||
|
if (leaf && leaf->dataList) {
|
||
|
tempData = leaf->dataList[curName - leaf->start];
|
||
|
(*(GLint *)tempData)++; /* increment the refcount */
|
||
|
*data++ = tempData;
|
||
|
} else {
|
||
|
(*(GLint *)empty)++; /* increment refcount */
|
||
|
*data++ = empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case GL_INT:
|
||
|
{
|
||
|
const GLint *p = (const GLint *) names;
|
||
|
leaf = NULL;
|
||
|
while (--n >= 0) {
|
||
|
curName = base + *p++;
|
||
|
if (leaf==NULL || curName<leaf->start || curName>leaf->end) {
|
||
|
leaf = findLeaf(array, curName, GL_TRUE);
|
||
|
}
|
||
|
if (leaf && leaf->dataList) {
|
||
|
tempData = leaf->dataList[curName - leaf->start];
|
||
|
(*(GLint *)tempData)++; /* increment the refcount */
|
||
|
*data++ = tempData;
|
||
|
} else {
|
||
|
(*(GLint *)empty)++; /* increment refcount */
|
||
|
*data++ = empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case GL_UNSIGNED_INT:
|
||
|
{
|
||
|
const GLuint *p = (const GLuint *) names;
|
||
|
leaf = NULL;
|
||
|
while (--n >= 0) {
|
||
|
curName = base + *p++;
|
||
|
if (leaf==NULL || curName<leaf->start || curName>leaf->end) {
|
||
|
leaf = findLeaf(array, curName, GL_TRUE);
|
||
|
}
|
||
|
if (leaf && leaf->dataList) {
|
||
|
tempData = leaf->dataList[curName - leaf->start];
|
||
|
(*(GLint *)tempData)++; /* increment the refcount */
|
||
|
*data++ = tempData;
|
||
|
} else {
|
||
|
(*(GLint *)empty)++; /* increment refcount */
|
||
|
*data++ = empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case GL_FLOAT:
|
||
|
{
|
||
|
const GLfloat *p = (const GLfloat *) names;
|
||
|
leaf = NULL;
|
||
|
while (--n >= 0) {
|
||
|
curName = base + *p++;
|
||
|
if (leaf==NULL || curName<leaf->start || curName>leaf->end) {
|
||
|
leaf = findLeaf(array, curName, GL_TRUE);
|
||
|
}
|
||
|
if (leaf && leaf->dataList) {
|
||
|
tempData = leaf->dataList[curName - leaf->start];
|
||
|
(*(GLint *)tempData)++; /* increment the refcount */
|
||
|
*data++ = tempData;
|
||
|
} else {
|
||
|
(*(GLint *)empty)++; /* increment refcount */
|
||
|
*data++ = empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case GL_2_BYTES:
|
||
|
{
|
||
|
const GLubyte *p = (const GLubyte *) names;
|
||
|
leaf = NULL;
|
||
|
while (--n >= 0) {
|
||
|
curName = base + ((p[0] << 8) | p[1]);
|
||
|
p += 2;
|
||
|
if (leaf==NULL || curName<leaf->start || curName>leaf->end) {
|
||
|
leaf = findLeaf(array, curName, GL_TRUE);
|
||
|
}
|
||
|
if (leaf && leaf->dataList) {
|
||
|
tempData = leaf->dataList[curName - leaf->start];
|
||
|
(*(GLint *)tempData)++; /* increment the refcount */
|
||
|
*data++ = tempData;
|
||
|
} else {
|
||
|
(*(GLint *)empty)++; /* increment refcount */
|
||
|
*data++ = empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case GL_3_BYTES:
|
||
|
{
|
||
|
const GLubyte *p = (const GLubyte *) names;
|
||
|
leaf = NULL;
|
||
|
while (--n >= 0) {
|
||
|
curName = base + ((p[0] << 16) | (p[1] << 8) | p[2]);
|
||
|
p += 3;
|
||
|
if (leaf==NULL || curName<leaf->start || curName>leaf->end) {
|
||
|
leaf = findLeaf(array, curName, GL_TRUE);
|
||
|
}
|
||
|
if (leaf && leaf->dataList) {
|
||
|
tempData = leaf->dataList[curName - leaf->start];
|
||
|
(*(GLint *)tempData)++; /* increment the refcount */
|
||
|
*data++ = tempData;
|
||
|
} else {
|
||
|
(*(GLint *)empty)++; /* increment refcount */
|
||
|
*data++ = empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case GL_4_BYTES:
|
||
|
{
|
||
|
const GLubyte *p = (const GLubyte *) names;
|
||
|
leaf = NULL;
|
||
|
while (--n >= 0) {
|
||
|
curName = base + ((p[0] << 24) | (p[1] << 16) |
|
||
|
(p[2] << 8) | p[3]);
|
||
|
p += 4;
|
||
|
if (leaf==NULL || curName<leaf->start || curName>leaf->end) {
|
||
|
leaf = findLeaf(array, curName, GL_TRUE);
|
||
|
}
|
||
|
if (leaf && leaf->dataList) {
|
||
|
tempData = leaf->dataList[curName - leaf->start];
|
||
|
(*(GLint *)tempData)++; /* increment the refcount */
|
||
|
*data++ = tempData;
|
||
|
} else {
|
||
|
(*(GLint *)empty)++; /* increment refcount */
|
||
|
*data++ = empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
/* This should be impossible */
|
||
|
ASSERTOPENGL(FALSE, "Default hit\n");
|
||
|
}
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Unlocks data that was previously locked with __glNamesLockData().
|
||
|
*/
|
||
|
void FASTCALL __glNamesUnlockData(__GLcontext *gc, void *data,
|
||
|
__GLnamesCleanupFunc cleanup)
|
||
|
{
|
||
|
GLint *pRefcount;
|
||
|
ASSERTOPENGL(data, "No data to unlock\n");
|
||
|
|
||
|
pRefcount = data;
|
||
|
(*pRefcount)--; /* decrement the refcount */
|
||
|
ASSERTOPENGL(*pRefcount >= 0, "Invalid refcount\n");
|
||
|
if (*pRefcount == 0) {
|
||
|
/*
|
||
|
** We are the last person to see this list alive. Free it.
|
||
|
*/
|
||
|
(*cleanup)(gc, data);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Unlocks an array of named data that was previously locked with
|
||
|
** __glNamesLockDataList().
|
||
|
*/
|
||
|
void FASTCALL __glNamesUnlockDataList(__GLcontext *gc, GLsizei n,
|
||
|
void *dataList[],
|
||
|
__GLnamesCleanupFunc cleanup)
|
||
|
{
|
||
|
GLint i;
|
||
|
GLint *pRefcount;
|
||
|
|
||
|
/*
|
||
|
** The refcount comes first in all data definitions, so the
|
||
|
** data pointer also points to the refcount.
|
||
|
*/
|
||
|
for (i = 0; i < n; i++) {
|
||
|
pRefcount = (GLint *)(dataList[i]);
|
||
|
(*pRefcount) --; /* decrement the refcount */
|
||
|
ASSERTOPENGL(*pRefcount >= 0, "Invalid refcount\n");
|
||
|
if (*pRefcount == 0) {
|
||
|
/*
|
||
|
** We are the last person to see this list alive. Free it.
|
||
|
*/
|
||
|
(*cleanup)(gc, (void *)pRefcount);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
GLuint FASTCALL __glNamesGenRange(__GLcontext *gc, __GLnamesArray *array,
|
||
|
GLsizei range)
|
||
|
{
|
||
|
GLuint lastUsed;
|
||
|
GLuint nextUsed;
|
||
|
GLuint maxUsed;
|
||
|
__GLnamesLeaf *leaf;
|
||
|
__GLnamesLeaf *nextleaf;
|
||
|
__GLnamesLeaf *newleaf;
|
||
|
|
||
|
__GL_NAMES_LOCK(array);
|
||
|
|
||
|
/*
|
||
|
** First we check for possible memory problems, since it will be
|
||
|
** difficult to back out once we start.
|
||
|
*/
|
||
|
if (array->nbranches != __GL_DL_EXTRA_BRANCHES ||
|
||
|
array->nleaves != __GL_DL_EXTRA_LEAVES) {
|
||
|
if (!fixMemoryProblem(gc, array)) {
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
__glSetError(GL_OUT_OF_MEMORY);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
leaf = firstLeaf(array);
|
||
|
|
||
|
/*
|
||
|
** Can we possibly allocate the appropriate number before the first leaf?
|
||
|
*/
|
||
|
if (leaf && leaf->start > (GLuint)range) {
|
||
|
if (leaf->dataList == NULL) {
|
||
|
/*
|
||
|
** Ha! We can trivially extend leaf!
|
||
|
*/
|
||
|
leaf->start -= range;
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return leaf->start;
|
||
|
} else {
|
||
|
/*
|
||
|
** Must make a new leaf
|
||
|
*/
|
||
|
newleaf = allocLeaf(gc, array);
|
||
|
|
||
|
newleaf->start = 1;
|
||
|
newleaf->end = range;
|
||
|
insertLeaf(gc, array, newleaf);
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (leaf) {
|
||
|
nextleaf = nextLeaf(leaf);
|
||
|
if (!nextleaf) break;
|
||
|
|
||
|
lastUsed = leaf->end + 1;
|
||
|
nextUsed = nextleaf->start;
|
||
|
|
||
|
/* Room for (lastUsed) - (nextUsed-1) here */
|
||
|
if (nextUsed - lastUsed >= (GLuint)range) {
|
||
|
if (leaf->dataList == NULL) {
|
||
|
/* Trivial to expand 'leaf' */
|
||
|
leaf->end += range;
|
||
|
pushMaxVal((__GLnamesBranch *) leaf, leaf->end);
|
||
|
|
||
|
if (nextUsed - lastUsed == (GLuint)range && nextleaf->dataList == NULL) {
|
||
|
mergeLeaf(gc, array, leaf);
|
||
|
}
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return lastUsed;
|
||
|
} else if (nextleaf->dataList == NULL) {
|
||
|
/* Trivial to expand 'nextleaf' */
|
||
|
nextleaf->start -= range;
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return nextleaf->start;
|
||
|
} else {
|
||
|
newleaf = allocLeaf(gc, array);
|
||
|
|
||
|
newleaf->start = lastUsed;
|
||
|
newleaf->end = lastUsed + range - 1;
|
||
|
insertLeaf(gc, array, newleaf);
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return lastUsed;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
leaf = nextleaf;
|
||
|
}
|
||
|
|
||
|
if (leaf == NULL) {
|
||
|
newleaf = allocLeaf(gc, array);
|
||
|
|
||
|
newleaf->start = 1;
|
||
|
newleaf->end = range;
|
||
|
insertLeaf(gc, array, newleaf);
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return 1;
|
||
|
} else {
|
||
|
lastUsed = leaf->end;
|
||
|
maxUsed = lastUsed + range;
|
||
|
if (maxUsed < lastUsed) {
|
||
|
/* Word wrap! Ack! */
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return 0;
|
||
|
}
|
||
|
if (leaf->dataList == NULL) {
|
||
|
/* Trivial to expand 'leaf' */
|
||
|
leaf->end += range;
|
||
|
pushMaxVal((__GLnamesBranch *) leaf, leaf->end);
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return lastUsed + 1;
|
||
|
} else {
|
||
|
/* Need to make new leaf */
|
||
|
newleaf = allocLeaf(gc, array);
|
||
|
|
||
|
newleaf->start = lastUsed + 1;
|
||
|
newleaf->end = maxUsed;
|
||
|
insertLeaf(gc, array, newleaf);
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
return lastUsed + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FASTCALL __glNamesDeleteRange(__GLcontext *gc, __GLnamesArray *array,
|
||
|
GLuint name, GLsizei range)
|
||
|
{
|
||
|
__GLnamesLeaf *leaf;
|
||
|
/*LINTED nextleaf ok; lint doesn't understand for loops*/
|
||
|
__GLnamesLeaf *nextleaf;
|
||
|
__GLnamesLeaf *newleaf;
|
||
|
void *empty;
|
||
|
GLuint start, end, i;
|
||
|
GLuint firstdel, lastdel;
|
||
|
GLuint memoryProblem;
|
||
|
|
||
|
if (range == 0) return;
|
||
|
|
||
|
__GL_NAMES_LOCK(array);
|
||
|
|
||
|
/*
|
||
|
** First we check for possible memory problems, since it will be
|
||
|
** difficult to back out once we start. We note a possible problem,
|
||
|
** and check for it before fragmenting a leaf.
|
||
|
*/
|
||
|
memoryProblem = 0;
|
||
|
if (array->nbranches != __GL_DL_EXTRA_BRANCHES ||
|
||
|
array->nleaves != __GL_DL_EXTRA_LEAVES) {
|
||
|
memoryProblem = 1;
|
||
|
}
|
||
|
|
||
|
firstdel = name;
|
||
|
lastdel = name+range-1;
|
||
|
|
||
|
/*LINTED nextleaf ok; lint bug*/
|
||
|
for (leaf = findLeaf(array, name, GL_FALSE); leaf != NULL;
|
||
|
leaf = nextleaf) {
|
||
|
nextleaf = nextLeaf(leaf);
|
||
|
start = leaf->start;
|
||
|
end = leaf->end;
|
||
|
if (lastdel < start) break;
|
||
|
if (firstdel > end) continue;
|
||
|
|
||
|
if (firstdel > start) start = firstdel;
|
||
|
if (lastdel < end) end = lastdel;
|
||
|
|
||
|
/*
|
||
|
** Need to delete the range of lists from start to end.
|
||
|
*/
|
||
|
if (leaf->dataList) {
|
||
|
empty = array->dataInfo->empty;
|
||
|
for (i=start; i<=end; i++) {
|
||
|
if (leaf->dataList[i - leaf->start] != empty) {
|
||
|
(*leaf->dataInfo->free)(gc,
|
||
|
(void *)leaf->dataList[i - leaf->start]);
|
||
|
leaf->dataList[i - leaf->start] = empty;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (start == leaf->start) {
|
||
|
if (end == leaf->end) {
|
||
|
/* Bye bye leaf! */
|
||
|
deleteLeaf(gc, array, leaf);
|
||
|
freeLeaf(gc, leaf);
|
||
|
} else {
|
||
|
/* Shrink leaf */
|
||
|
resizeLeaf(gc, leaf, end+1, leaf->end);
|
||
|
}
|
||
|
} else if (end == leaf->end) {
|
||
|
/* Shrink leaf */
|
||
|
resizeLeaf(gc, leaf, leaf->start, start-1);
|
||
|
} else {
|
||
|
if (memoryProblem) {
|
||
|
if (!fixMemoryProblem(gc, array)) {
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
__glSetError(GL_OUT_OF_MEMORY);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
/* Crud. The middle of the leaf was deleted. This is tough. */
|
||
|
newleaf = allocLeaf(gc, array);
|
||
|
|
||
|
newleaf->start = end+1;
|
||
|
newleaf->end = leaf->end;
|
||
|
if (leaf->dataList) {
|
||
|
if (!allocLeafData(gc, newleaf)) {
|
||
|
/*
|
||
|
** Darn! We are in trouble. This is a bad spot for an
|
||
|
** out of memory error. It is also darn unlikely,
|
||
|
** because we just freed up some memory.
|
||
|
*/
|
||
|
freeLeaf(gc, newleaf);
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
__glSetError(GL_OUT_OF_MEMORY);
|
||
|
return;
|
||
|
}
|
||
|
copyLeafInfo(leaf, newleaf);
|
||
|
}
|
||
|
resizeLeaf(gc, leaf, leaf->start, start-1);
|
||
|
insertLeaf(gc, array, newleaf);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
}
|
||
|
|
||
|
GLboolean FASTCALL __glNamesIsName(__GLcontext *gc, __GLnamesArray *array,
|
||
|
GLuint name)
|
||
|
{
|
||
|
GLboolean isName;
|
||
|
|
||
|
__GL_NAMES_LOCK(array);
|
||
|
|
||
|
/*
|
||
|
** If the name retrieves a leaf, it is in the current name space.
|
||
|
*/
|
||
|
isName = findLeaf(array, name, GL_TRUE) != NULL;
|
||
|
|
||
|
__GL_NAMES_UNLOCK(array);
|
||
|
|
||
|
return isName;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** Generates a list of (not necessarily contiguous) names.
|
||
|
*/
|
||
|
void FASTCALL __glNamesGenNames(__GLcontext *gc, __GLnamesArray *array,
|
||
|
GLsizei n, GLuint* names)
|
||
|
{
|
||
|
GLuint start, nameVal;
|
||
|
int i;
|
||
|
|
||
|
if (NULL == names) return;
|
||
|
|
||
|
start = __glNamesGenRange(gc, array, n);
|
||
|
for (i=0, nameVal=start; i < n; i++, nameVal++) {
|
||
|
names[i] = nameVal;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
** Deletes a list of (not necessarily contiguous) names.
|
||
|
*/
|
||
|
void FASTCALL __glNamesDeleteNames(__GLcontext *gc, __GLnamesArray *array,
|
||
|
GLsizei n, const GLuint* names)
|
||
|
{
|
||
|
GLuint start, rangeVal, i;
|
||
|
|
||
|
/*
|
||
|
** Because of resizing leaves, etc, it is best to work in ranges
|
||
|
** as much as possible. So break the list into ranges
|
||
|
** and delete them that way. This degrades into deleting
|
||
|
** them one at a time if the list is disjoint or non-ascending.
|
||
|
** It also only calls DeleteRange once if the list is a
|
||
|
** contiguous range of names.
|
||
|
*/
|
||
|
start = rangeVal = names[0];
|
||
|
for (i=0; i < (GLuint)n; i++, rangeVal++) {
|
||
|
if (names[i] != rangeVal) {
|
||
|
__glNamesDeleteRange(gc,array,start,rangeVal-start);
|
||
|
start = rangeVal = names[i];
|
||
|
}
|
||
|
}
|
||
|
__glNamesDeleteRange(gc,array,start,rangeVal-start);
|
||
|
return;
|
||
|
}
|