X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=meshqueue.c;h=d21ba627aec464dc0e7fa359d06e169319b5bb9f;hp=e75bddd112ac0fbcb57ae90dd470e875901fee6b;hb=c9b9e2d6bd061e255c0418b44f8ec3e251642c16;hpb=c0f7a1b5470bc222b7a1d01ca95205c1825a5c6a diff --git a/meshqueue.c b/meshqueue.c index e75bddd1..d21ba627 100644 --- a/meshqueue.c +++ b/meshqueue.c @@ -2,174 +2,132 @@ #include "quakedef.h" #include "meshqueue.h" -cvar_t r_meshqueue_entries = {CVAR_SAVE, "r_meshqueue_entries", "16"}; -cvar_t r_meshqueue_immediaterender = {0, "r_meshqueue_immediaterender", "0"}; -cvar_t r_meshqueue_sort = {0, "r_meshqueue_sort", "0"}; - typedef struct meshqueue_s { struct meshqueue_s *next; - void (*callback)(void *data1, int data2); - void *data1; - int data2; + void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices); + const entity_render_t *ent; + int surfacenumber; + const rtlight_t *rtlight; float dist; } meshqueue_t; -float mqt_viewplanedist; -meshqueue_t *mq_array, *mqt_array, *mq_listhead; -int mq_count, mqt_count; -int mq_total, mqt_total; +int trans_sortarraysize; +meshqueue_t **trans_hash = NULL; +meshqueue_t ***trans_hashpointer = NULL; +extern cvar_t r_transparent_sortarraysize; +extern cvar_t r_transparent_sortmaxdist; -mempool_t *meshqueuemempool; +float mqt_viewplanedist; +float mqt_viewmaxdist; +meshqueue_t *mqt_array; +int mqt_count; +int mqt_total; -void R_MeshQueue_Init(void) +void R_MeshQueue_BeginScene(void) { - Cvar_RegisterVariable(&r_meshqueue_entries); - Cvar_RegisterVariable(&r_meshqueue_immediaterender); - Cvar_RegisterVariable(&r_meshqueue_sort); - - meshqueuemempool = Mem_AllocPool("R_MeshQueue"); - mq_total = 0; - mqt_total = 1000; - mq_array = NULL; - mqt_array = NULL; + mqt_count = 0; + mqt_viewplanedist = DotProduct(r_refdef.view.origin, r_refdef.view.forward); + mqt_viewmaxdist = 0; } -static void R_MeshQueue_Render(void) +void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight) { meshqueue_t *mq; - for (mq = mq_listhead;mq;mq = mq->next) - mq->callback(mq->data1, mq->data2); - mq_count = 0; - mq_listhead = NULL; -} - -static void R_MeshQueue_EnlargeTransparentArray(int newtotal) -{ - meshqueue_t *newarray; - newarray = Mem_Alloc(meshqueuemempool, newtotal * sizeof(meshqueue_t)); - if (mqt_array) + if (mqt_count >= mqt_total || !mqt_array) { - memcpy(newarray, mqt_array, mqt_total * sizeof(meshqueue_t)); - Mem_Free(mqt_array); - } - mqt_array = newarray; - mqt_total = newtotal; -} - -void R_MeshQueue_Add(void (*callback)(void *data1, int data2), void *data1, int data2) -{ - meshqueue_t *mq, **mqnext; - if (r_meshqueue_immediaterender.integer) - { - callback(data1, data2); - return; - } - if (mq_count >= mq_total) - R_MeshQueue_Render(); - mq = &mq_array[mq_count++]; - mq->callback = callback; - mq->data1 = data1; - mq->data2 = data2; - - // bubble-insert sort into meshqueue - mqnext = &mq_listhead; - if (r_meshqueue_sort.integer) - { - for(;;) + int newtotal = max(1024, mqt_total * 2); + meshqueue_t *newarray = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, newtotal * sizeof(meshqueue_t)); + if (mqt_array) { - if (*mqnext) - { - if (mq->callback == (*mqnext)->callback) - { - if (mq->data1 == (*mqnext)->data1) - { - if (mq->data2 <= (*mqnext)->data2) - break; - } - else if (mq->data1 < (*mqnext)->data1) - break; - } - else if (mq->callback < (*mqnext)->callback) - break; - } - else - break; - mqnext = &(*mqnext)->next; + memcpy(newarray, mqt_array, mqt_total * sizeof(meshqueue_t)); + Mem_Free(mqt_array); } + mqt_array = newarray; + mqt_total = newtotal; } - mq->next = *mqnext; - *mqnext = mq; -} - -void R_MeshQueue_AddTransparent(vec3_t center, void (*callback)(void *data1, int data2), void *data1, int data2) -{ - meshqueue_t *mq; - if (mqt_count >= mqt_total) - R_MeshQueue_EnlargeTransparentArray(mqt_total + 100); mq = &mqt_array[mqt_count++]; mq->callback = callback; - mq->data1 = data1; - mq->data2 = data2; - mq->dist = DotProduct(center, vpn) - mqt_viewplanedist; + mq->ent = ent; + mq->surfacenumber = surfacenumber; + mq->rtlight = rtlight; + mq->dist = DotProduct(center, r_refdef.view.forward) - mqt_viewplanedist; mq->next = NULL; + mqt_viewmaxdist = max(mqt_viewmaxdist, mq->dist); } -static void R_MeshQueue_RenderTransparent(void) +void R_MeshQueue_RenderTransparent(void) { - int i; - int hashdist; + int i, hashindex, maxhashindex, batchnumsurfaces; + float distscale; + const entity_render_t *ent; + const rtlight_t *rtlight; + void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices); + int batchsurfaceindex[MESHQUEUE_TRANSPARENT_BATCHSIZE]; meshqueue_t *mqt; - meshqueue_t *hash[4096]; - memset(hash, 0, 4096 * sizeof(meshqueue_t *)); - for (i = 0, mqt = mqt_array;i < mqt_count;i++, mqt++) - { - // generate index - hashdist = (int) (mqt->dist); - hashdist = bound(0, hashdist, 4095); - // reversed to simplify render loop - hashdist = 4095 - hashdist; - // link into hash chain - mqt->next = hash[hashdist]; - hash[hashdist] = mqt; - } - for (i = 0;i < 4096;i++) - if (hash[i]) - for (mqt = hash[i];mqt;mqt = mqt->next) - R_MeshQueue_Add(mqt->callback, mqt->data1, mqt->data2); - mqt_count = 0; -} -void R_MeshQueue_BeginScene(void) -{ - if (r_meshqueue_entries.integer < 1) - Cvar_SetValueQuick(&r_meshqueue_entries, 1); - if (r_meshqueue_entries.integer > 65536) - Cvar_SetValueQuick(&r_meshqueue_entries, 65536); + if (!mqt_count) + return; - if (mq_total != r_meshqueue_entries.integer || mq_array == NULL) + // check for bad cvars + if (r_transparent_sortarraysize.integer < 1 || r_transparent_sortarraysize.integer > 32768) + Cvar_SetValueQuick(&r_transparent_sortarraysize, bound(1, r_transparent_sortarraysize.integer, 32768)); + if (r_transparent_sortmaxdist.integer < 1 || r_transparent_sortmaxdist.integer > 32768) + Cvar_SetValueQuick(&r_transparent_sortmaxdist, bound(1, r_transparent_sortmaxdist.integer, 32768)); + + // update hash array + if (trans_sortarraysize != r_transparent_sortarraysize.integer) { - mq_total = r_meshqueue_entries.integer; - if (mq_array) - Mem_Free(mq_array); - mq_array = Mem_Alloc(meshqueuemempool, mq_total * sizeof(meshqueue_t)); + trans_sortarraysize = r_transparent_sortarraysize.integer; + if (trans_hash) + Mem_Free(trans_hash); + trans_hash = (meshqueue_t **)Mem_Alloc(cls.permanentmempool, sizeof(trans_hash) * trans_sortarraysize); + if (trans_hashpointer) + Mem_Free(trans_hashpointer); + trans_hashpointer = (meshqueue_t ***)Mem_Alloc(cls.permanentmempool, sizeof(trans_hashpointer) * trans_sortarraysize); } - if (mqt_array == NULL) - mqt_array = Mem_Alloc(meshqueuemempool, mqt_total * sizeof(meshqueue_t)); + // build index + memset(trans_hash, 0, sizeof(trans_hash) * trans_sortarraysize); + for (i = 0; i < trans_sortarraysize; i++) + trans_hashpointer[i] = &trans_hash[i]; + distscale = (trans_sortarraysize - 1) / min(mqt_viewmaxdist, r_transparent_sortmaxdist.integer); + maxhashindex = trans_sortarraysize - 1; + for (i = 0, mqt = mqt_array; i < mqt_count; i++, mqt++) + { + hashindex = bound(0, (int)(min(mqt->dist, r_transparent_sortmaxdist.integer) * distscale), maxhashindex); + // link to tail of hash chain (to preserve render order) + mqt->next = NULL; + *trans_hashpointer[hashindex] = mqt; + trans_hashpointer[hashindex] = &mqt->next; + } + callback = NULL; + ent = NULL; + rtlight = NULL; + batchnumsurfaces = 0; - mq_count = 0; + // draw + for (i = maxhashindex; i >= 0; i--) + { + if (trans_hash[i]) + { + for (mqt = trans_hash[i]; mqt; mqt = mqt->next) + { + if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= MESHQUEUE_TRANSPARENT_BATCHSIZE) + { + if (batchnumsurfaces) + callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex); + batchnumsurfaces = 0; + ent = mqt->ent; + rtlight = mqt->rtlight; + callback = mqt->callback; + } + batchsurfaceindex[batchnumsurfaces++] = mqt->surfacenumber; + } + } + } + if (batchnumsurfaces) + callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex); mqt_count = 0; - mq_listhead = NULL; - mqt_viewplanedist = DotProduct(r_origin, vpn); -} - -void R_MeshQueue_EndScene(void) -{ - if (mqt_count) - R_MeshQueue_RenderTransparent(); - if (mq_count) - R_MeshQueue_Render(); } -