+ //R_Mesh_CacheArray_ValidateState(3);
+ // calculate a hashindex to choose a cache chain
+ r->data = NULL;
+ hashindex = CRC_Block((void *)r, sizeof(*r)) % RCACHEARRAY_HASHSIZE;
+
+ // is it already cached?
+ for (lhead = &r_mesh_rcachechain[hashindex], l = lhead->next;l != lhead;l = l->next)
+ {
+ if (!memcmp(&l->data->request, r, sizeof(l->data->request)))
+ {
+ // we have it cached already
+ r->data = r_mesh_rcachedata + l->data->offset;
+ return false;
+ }
+ }
+
+ // we need to add a new cache item, this means finding a place for the new
+ // data and making sure we have a free item available, lots of work...
+
+ // check if buffer needs to wrap
+ if (r_mesh_rcachedata_offset + r->data_size > r_mesh_rcachedata_size)
+ {
+ /*
+ if (r->data_size * 10 > r_mesh_rcachedata_size)
+ {
+ // realloc whole cache
+ }
+ */
+ // reset back to start
+ r_mesh_rcachedata_offset = 0;
+ r_mesh_rcachesequentialchain_current = &r_mesh_rcachesequentialchain;
+ }
+ offset = r_mesh_rcachedata_offset;
+ r_mesh_rcachedata_offset += r->data_size;
+ offsetend = r_mesh_rcachedata_offset;
+ //R_Mesh_CacheArray_ValidateState(4);
+
+ /*
+ {
+ int n;
+ for (lhead = &r_mesh_rcachesequentialchain, l = lhead->next, n = 0;l != lhead;l = l->next, n++);
+ Con_Printf("R_Mesh_CacheArray: new data range %i:%i, %i items are already linked\n", offset, offsetend, n);
+ }
+ */
+
+ // make room for the new data (remove old items)
+ lhead = &r_mesh_rcachesequentialchain;
+ l = r_mesh_rcachesequentialchain_current;
+ if (l == lhead)
+ l = l->next;
+ while (l != lhead && l->data->offset < offsetend && l->data->offset + l->data->request.data_size > offset)
+ {
+ //r_mesh_rcachesequentialchain_current = l;
+ //R_Mesh_CacheArray_ValidateState(8);
+ lnext = l->next;
+ // if at the end of the chain, wrap around
+ if (lnext == lhead)
+ lnext = lnext->next;
+ //r_mesh_rcachesequentialchain_current = lnext;
+ //R_Mesh_CacheArray_ValidateState(10);
+
+ // unlink from sequential chain
+ l->next->prev = l->prev;
+ l->prev->next = l->next;
+ //R_Mesh_CacheArray_ValidateState(11);
+ // link into free chain
+ l->next = &r_mesh_rcachefreechain;
+ l->prev = l->next->prev;
+ l->next->prev = l->prev->next = l;
+ //R_Mesh_CacheArray_ValidateState(12);
+
+ l = &l->data->hashlink;
+ // unlink from hash chain
+ l->next->prev = l->prev;
+ l->prev->next = l->next;
+
+ l = lnext;
+ //r_mesh_rcachesequentialchain_current = l;
+ //R_Mesh_CacheArray_ValidateState(9);
+ }
+ //r_mesh_rcachesequentialchain_current = l;
+ //R_Mesh_CacheArray_ValidateState(5);
+ // gobble an extra item if we have no free items available
+ if (r_mesh_rcachefreechain.next == &r_mesh_rcachefreechain)
+ {
+ lnext = l->next;
+
+ // unlink from sequential chain
+ l->next->prev = l->prev;
+ l->prev->next = l->next;
+ // link into free chain
+ l->next = &r_mesh_rcachefreechain;
+ l->prev = l->next->prev;
+ l->next->prev = l->prev->next = l;
+
+ l = &l->data->hashlink;
+ // unlink from hash chain
+ l->next->prev = l->prev;
+ l->prev->next = l->next;
+
+ l = lnext;
+ }
+ r_mesh_rcachesequentialchain_current = l;
+ //R_Mesh_CacheArray_ValidateState(6);
+
+ // now take an item from the free chain
+ l = r_mesh_rcachefreechain.next;
+ // set it up
+ d = l->data;
+ d->request = *r;
+ d->offset = offset;
+ // unlink
+ l->next->prev = l->prev;
+ l->prev->next = l->next;
+ // relink to sequential
+ l->next = r_mesh_rcachesequentialchain_current->prev;
+ l->prev = l->next->prev;
+ while (l->next->data && l->data && l->next->data->offset <= d->offset)
+ {
+ //Con_Printf(">\n");
+ l->next = l->next->next;
+ l->prev = l->prev->next;
+ }
+ while (l->prev->data && l->data && l->prev->data->offset >= d->offset)
+ {
+ //Con_Printf("<\n");
+ l->prev = l->prev->prev;
+ l->next = l->next->prev;
+ }
+ l->next->prev = l->prev->next = l;
+ // also link into hash chain
+ l = &l->data->hashlink;
+ l->next = &r_mesh_rcachechain[hashindex];
+ l->prev = l->next->prev;
+ l->prev->next = l;
+ l->next->prev = l->prev->next = l;
+
+
+ //r_mesh_rcachesequentialchain_current = d->sequentiallink.next;
+
+ //R_Mesh_CacheArray_ValidateState(7);
+ // and finally set the data pointer
+ r->data = r_mesh_rcachedata + d->offset;
+ // and tell the caller to fill the array
+ return true;