]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - meshqueue.c
Fix engine not starting on Windows if linked against SDL > 2.0.5
[xonotic/darkplaces.git] / meshqueue.c
index 6b6ff0761ac8732685a6c965f156a515952749b4..edd85c227ac83c14e8f19fc56b966d4ae228d15c 100644 (file)
@@ -2,10 +2,6 @@
 #include "quakedef.h"
 #include "meshqueue.h"
 
-cvar_t r_meshqueue_entries = {CVAR_SAVE, "r_meshqueue_entries", "16", "maximum number of meshes to batch together and sort before issuing render calls (unused)"};
-cvar_t r_meshqueue_immediaterender = {0, "r_meshqueue_immediaterender", "0", "immediately render non-transparent meshes rather than batching"};
-cvar_t r_meshqueue_sort = {0, "r_meshqueue_sort", "0", "whether to sort meshes in a batch before issuing calls"};
-
 typedef struct meshqueue_s
 {
        struct meshqueue_s *next;
@@ -14,158 +10,129 @@ typedef struct meshqueue_s
        int surfacenumber;
        const rtlight_t *rtlight;
        float dist;
+       dptransparentsortcategory_t category;
 }
 meshqueue_t;
 
+int trans_sortarraysize;
+meshqueue_t **trans_hash = NULL;
+meshqueue_t ***trans_hashpointer = NULL;
+
 float mqt_viewplanedist;
 float mqt_viewmaxdist;
-meshqueue_t *mq_array, *mqt_array, *mq_listhead;
-int mq_count, mqt_count;
-int mq_total, mqt_total;
+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);
-
-       mq_total = 0;
-       mqt_total = 0;
-       mq_array = NULL;
-       mqt_array = NULL;
+       mqt_count = 0;
+       mqt_viewplanedist = DotProduct(r_refdef.view.origin, r_refdef.view.forward);
+       mqt_viewmaxdist = 0;
 }
 
-void R_MeshQueue_Render(void)
+void R_MeshQueue_AddTransparent(dptransparentsortcategory_t category, 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)
 {
-       // this is only used by one piece of code in prvm_cmds, why is it used at all?
        meshqueue_t *mq;
-       if (!mq_count)
-               return;
-       for (mq = mq_listhead;mq;mq = mq->next)
-               mq->callback(mq->ent, mq->rtlight, 1, &mq->surfacenumber);
-       mq_count = 0;
-       mq_listhead = NULL;
-}
-
-static void R_MeshQueue_EnlargeTransparentArray(int newtotal)
-{
-       meshqueue_t *newarray;
-       newarray = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, newtotal * sizeof(meshqueue_t));
-       if (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)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
-{
-       // this is only used by one piece of code in prvm_cmds, why is it used at all?
-       meshqueue_t *mq, **mqnext;
-       if (r_meshqueue_immediaterender.integer)
-       {
-               callback(ent, rtlight, 1, &surfacenumber);
-               return;
-       }
-       if (mq_count >= mq_total)
-               R_MeshQueue_Render();
-       mq = &mq_array[mq_count++];
-       mq->callback = callback;
-       mq->ent = ent;
-       mq->surfacenumber = surfacenumber;
-       mq->rtlight = rtlight;
-
-       if (r_meshqueue_sort.integer)
+       if (mqt_count >= mqt_total || !mqt_array)
        {
-               // bubble-insert sort into meshqueue
-               for(mqnext = &mq_listhead;*mqnext;mqnext = &(*mqnext)->next)
+               int newtotal = max(1024, mqt_total * 2);
+               meshqueue_t *newarray = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, newtotal * sizeof(meshqueue_t));
+               if (mqt_array)
                {
-                       if (mq->callback == (*mqnext)->callback)
-                       {
-                               if (mq->ent == (*mqnext)->ent)
-                               {
-                                       if (mq->surfacenumber == (*mqnext)->surfacenumber)
-                                       {
-                                               if (mq->rtlight <= (*mqnext)->rtlight)
-                                                       break;
-                                       }
-                                       else if (mq->surfacenumber < (*mqnext)->surfacenumber)
-                                               break;
-                               }
-                               else if (mq->ent < (*mqnext)->ent)
-                                       break;
-                       }
-                       else if (mq->callback < (*mqnext)->callback)
-                               break;
+                       memcpy(newarray, mqt_array, mqt_total * sizeof(meshqueue_t));
+                       Mem_Free(mqt_array);
                }
+               mqt_array = newarray;
+               mqt_total = newtotal;
        }
-       else
-       {
-               // maintain the order
-               for(mqnext = &mq_listhead;*mqnext;mqnext = &(*mqnext)->next);
-       }
-       mq->next = *mqnext;
-       *mqnext = mq;
-}
-
-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;
-       if (mqt_count >= mqt_total)
-               R_MeshQueue_EnlargeTransparentArray(mqt_total + 100);
        mq = &mqt_array[mqt_count++];
        mq->callback = callback;
        mq->ent = ent;
        mq->surfacenumber = surfacenumber;
        mq->rtlight = rtlight;
-       mq->dist = DotProduct(center, r_viewforward) - mqt_viewplanedist;
+       mq->category = category;
+       if (r_transparent_useplanardistance.integer)
+               mq->dist = DotProduct(center, r_refdef.view.forward) - mqt_viewplanedist;
+       else
+               mq->dist = VectorDistance(center, r_refdef.view.origin);
        mq->next = NULL;
        mqt_viewmaxdist = max(mqt_viewmaxdist, mq->dist);
 }
 
 void R_MeshQueue_RenderTransparent(void)
 {
-       int i;
-       int hashdist;
-       int batchnumsurfaces;
+       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], **hashpointer[4096];
-       int batchsurfaceindex[256];
-       if (mq_count)
-               R_MeshQueue_Render();
+
        if (!mqt_count)
                return;
-       memset(hash, 0, sizeof(hash));
-       for (i = 0;i < 4096;i++)
-               hashpointer[i] = &hash[i];
-       distscale = 4095.0f / max(mqt_viewmaxdist, 4095);
-       for (i = 0, mqt = mqt_array;i < mqt_count;i++, mqt++)
+
+       // 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_sortmindist.integer < 1 || r_transparent_sortmindist.integer >= r_transparent_sortmaxdist.integer)
+               Cvar_SetValueQuick(&r_transparent_sortmindist, 0);
+       if (r_transparent_sortmaxdist.integer < r_transparent_sortmindist.integer || r_transparent_sortmaxdist.integer > 32768)
+               Cvar_SetValueQuick(&r_transparent_sortmaxdist, bound(r_transparent_sortmindist.integer, r_transparent_sortmaxdist.integer, 32768));
+
+       // update hash array
+       if (trans_sortarraysize != r_transparent_sortarraysize.integer)
+       {
+               trans_sortarraysize = r_transparent_sortarraysize.integer;
+               if (trans_hash)
+                       Mem_Free(trans_hash);
+               trans_hash = (meshqueue_t **)Mem_Alloc(cls.permanentmempool, sizeof(meshqueue_t *) * trans_sortarraysize); 
+               if (trans_hashpointer)
+                       Mem_Free(trans_hashpointer);
+               trans_hashpointer = (meshqueue_t ***)Mem_Alloc(cls.permanentmempool, sizeof(meshqueue_t **) * trans_sortarraysize); 
+       }
+
+       // build index
+       memset(trans_hash, 0, sizeof(meshqueue_t *) * 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++)
        {
-               // generate index
-               hashdist = (int) (mqt->dist * distscale);
-               hashdist = bound(0, hashdist, 4095);
+               switch(mqt->category)
+               {
+               default:
+               case TRANSPARENTSORT_HUD:
+                       hashindex = 0;
+                       break;
+               case TRANSPARENTSORT_DISTANCE:
+                       // this could use a reduced range if we need more categories
+                       hashindex = bound(0, (int)(bound(0, mqt->dist - r_transparent_sortmindist.integer, r_transparent_sortmaxdist.integer) * distscale), maxhashindex);
+                       break;
+               case TRANSPARENTSORT_SKY:
+                       hashindex = maxhashindex;
+                       break;
+               }
                // link to tail of hash chain (to preserve render order)
                mqt->next = NULL;
-               *hashpointer[hashdist] = mqt;
-               hashpointer[hashdist] = &mqt->next;
+               *trans_hashpointer[hashindex] = mqt;
+               trans_hashpointer[hashindex] = &mqt->next;
        }
        callback = NULL;
        ent = NULL;
        rtlight = NULL;
        batchnumsurfaces = 0;
-       for (i = 4095;i >= 0;i--)
+
+       // draw
+       for (i = maxhashindex; i >= 0; i--)
        {
-               if (hash[i])
+               if (trans_hash[i])
                {
-                       for (mqt = hash[i];mqt;mqt = mqt->next)
+                       for (mqt = trans_hash[i]; mqt; mqt = mqt->next)
                        {
-                               if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= 256)
+                               if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= MESHQUEUE_TRANSPARENT_BATCHSIZE)
                                {
                                        if (batchnumsurfaces)
                                                callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex);
@@ -182,43 +149,3 @@ void R_MeshQueue_RenderTransparent(void)
                callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex);
        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 (mq_total != r_meshqueue_entries.integer || mq_array == NULL)
-       {
-               mq_total = r_meshqueue_entries.integer;
-               if (mq_array)
-                       Mem_Free(mq_array);
-               mq_array = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, mq_total * sizeof(meshqueue_t));
-       }
-
-       if (mqt_array == NULL)
-               mqt_array = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, mqt_total * sizeof(meshqueue_t));
-
-       mq_count = 0;
-       mqt_count = 0;
-       mq_listhead = NULL;
-       mqt_viewplanedist = DotProduct(r_vieworigin, r_viewforward);
-       mqt_viewmaxdist = 0;
-}
-
-void R_MeshQueue_EndScene(void)
-{
-       if (mq_count)
-       {
-               Con_Printf("R_MeshQueue_EndScene: main mesh queue still has %i items left, flushing\n", mq_count);
-               R_MeshQueue_Render();
-       }
-       if (mqt_count)
-       {
-               Con_Printf("R_MeshQueue_EndScene: transparent mesh queue still has %i items left, flushing\n", mqt_count);
-               R_MeshQueue_RenderTransparent();
-       }
-}
-