22bb395305
Fixed svc_setangles and sv_bigcoords. Model code is now responsible for transforming traces instead of it being generic. This fixes rotating things getting stuck in players in hexen2. The renderer now generates a list of surfaces to draw. Backend now performs rotations/scaling per entity. This fixes sorting order, at least when not using realtime lights. Hidden items in the hexen2 inventory that you do not have. Added colourmapping for hexen2. Should be easier to click on menu items for hexen2. git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3602 fc73d0e0-1445-4013-8a0c-d673dee63da5
292 lines
5.4 KiB
C
292 lines
5.4 KiB
C
#include "hash.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifndef _WIN32
|
|
#ifndef stricmp
|
|
#define stricmp strcasecmp
|
|
#endif
|
|
#endif
|
|
|
|
// hash init assumes we get clean memory
|
|
void Hash_InitTable(hashtable_t *table, unsigned int numbucks, void *mem)
|
|
{
|
|
table->numbuckets = numbucks;
|
|
table->bucket = (bucket_t **)mem;
|
|
}
|
|
|
|
unsigned int Hash_Key(const char *name, unsigned int modulus)
|
|
{ //fixme: optimize.
|
|
unsigned int key;
|
|
for (key=0;*name; name++)
|
|
key += ((key<<3) + (key>>28) + *name);
|
|
|
|
return (key%modulus);
|
|
}
|
|
unsigned int Hash_KeyInsensative(const char *name, unsigned int modulus)
|
|
{ //fixme: optimize.
|
|
unsigned int key;
|
|
for (key=0;*name; name++)
|
|
{
|
|
if (*name >= 'A' && *name <= 'Z')
|
|
key += ((key<<3) + (key>>28) + (*name-'A'+'a'));
|
|
else
|
|
key += ((key<<3) + (key>>28) + *name);
|
|
}
|
|
|
|
return (key%modulus);
|
|
}
|
|
|
|
void *Hash_Get(hashtable_t *table, const char *name)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (!STRCMP(name, buck->key.string))
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
void *Hash_GetInsensative(hashtable_t *table, const char *name)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensative(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (!stricmp(name, buck->key.string))
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
void *Hash_GetKey(hashtable_t *table, unsigned int key)
|
|
{
|
|
unsigned int bucknum = key%table->numbuckets;
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (buck->key.value == key)
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*Does _NOT_ support items that are added with two names*/
|
|
void *Hash_GetNextKey(hashtable_t *table, unsigned int key, void *old)
|
|
{
|
|
unsigned int bucknum = key%table->numbuckets;
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (buck->data == old) //found the old one
|
|
break;
|
|
buck = buck->next;
|
|
}
|
|
if (!buck)
|
|
return NULL;
|
|
|
|
buck = buck->next;//don't return old
|
|
while(buck)
|
|
{
|
|
if (buck->key.value == key)
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*Does _NOT_ support items that are added with two names*/
|
|
void *Hash_GetNext(hashtable_t *table, const char *name, void *old)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (buck->data == old) //found the old one
|
|
// if (!STRCMP(name, buck->key.string))
|
|
break;
|
|
buck = buck->next;
|
|
}
|
|
if (!buck)
|
|
return NULL;
|
|
|
|
buck = buck->next;//don't return old
|
|
while(buck)
|
|
{
|
|
if (!STRCMP(name, buck->key.string))
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
/*Does _NOT_ support items that are added with two names*/
|
|
void *Hash_GetNextInsensative(hashtable_t *table, const char *name, void *old)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensative(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
while(buck)
|
|
{
|
|
if (buck->data == old) //found the old one
|
|
{
|
|
// if (!stricmp(name, buck->key.string))
|
|
break;
|
|
}
|
|
|
|
buck = buck->next;
|
|
}
|
|
if (!buck)
|
|
return NULL;
|
|
|
|
buck = buck->next;//don't return old
|
|
while(buck)
|
|
{
|
|
if (!stricmp(name, buck->key.string))
|
|
return buck->data;
|
|
|
|
buck = buck->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void *Hash_Add(hashtable_t *table, const char *name, void *data, bucket_t *buck)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
|
|
buck->data = data;
|
|
buck->key.string = name;
|
|
buck->next = table->bucket[bucknum];
|
|
table->bucket[bucknum] = buck;
|
|
|
|
return buck;
|
|
}
|
|
void *Hash_AddInsensative(hashtable_t *table, const char *name, void *data, bucket_t *buck)
|
|
{
|
|
unsigned int bucknum = Hash_KeyInsensative(name, table->numbuckets);
|
|
|
|
buck->data = data;
|
|
buck->key.string = name;
|
|
buck->next = table->bucket[bucknum];
|
|
table->bucket[bucknum] = buck;
|
|
|
|
return buck;
|
|
}
|
|
void *Hash_AddKey(hashtable_t *table, unsigned int key, void *data, bucket_t *buck)
|
|
{
|
|
unsigned int bucknum = key%table->numbuckets;
|
|
|
|
buck->data = data;
|
|
buck->key.value = key;
|
|
buck->next = table->bucket[bucknum];
|
|
table->bucket[bucknum] = buck;
|
|
|
|
return buck;
|
|
}
|
|
|
|
void Hash_Remove(hashtable_t *table, const char *name)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
if (!STRCMP(name, buck->key.string))
|
|
{
|
|
table->bucket[bucknum] = buck->next;
|
|
return;
|
|
}
|
|
|
|
|
|
while(buck->next)
|
|
{
|
|
if (!STRCMP(name, buck->next->key.string))
|
|
{
|
|
buck->next = buck->next->next;
|
|
return;
|
|
}
|
|
|
|
buck = buck->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void Hash_RemoveData(hashtable_t *table, const char *name, void *data)
|
|
{
|
|
unsigned int bucknum = Hash_Key(name, table->numbuckets);
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
if (buck->data == data)
|
|
if (!STRCMP(name, buck->key.string))
|
|
{
|
|
table->bucket[bucknum] = buck->next;
|
|
return;
|
|
}
|
|
|
|
|
|
while(buck->next)
|
|
{
|
|
if (buck->next->data == data)
|
|
if (!STRCMP(name, buck->next->key.string))
|
|
{
|
|
buck->next = buck->next->next;
|
|
return;
|
|
}
|
|
|
|
buck = buck->next;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void Hash_RemoveKey(hashtable_t *table, unsigned int key)
|
|
{
|
|
unsigned int bucknum = key%table->numbuckets;
|
|
bucket_t *buck;
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
if (buck->key.value == key)
|
|
{
|
|
table->bucket[bucknum] = buck->next;
|
|
return;
|
|
}
|
|
|
|
|
|
while(buck->next)
|
|
{
|
|
if (buck->next->key.value == key)
|
|
{
|
|
buck->next = buck->next->next;
|
|
return;
|
|
}
|
|
|
|
buck = buck->next;
|
|
}
|
|
return;
|
|
}
|