5 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)"};
6 cvar_t r_meshqueue_immediaterender = {0, "r_meshqueue_immediaterender", "0", "immediately render non-transparent meshes rather than batching"};
7 cvar_t r_meshqueue_sort = {0, "r_meshqueue_sort", "0", "whether to sort meshes in a batch before issuing calls"};
9 typedef struct meshqueue_s
11 struct meshqueue_s *next;
12 void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices);
13 const entity_render_t *ent;
15 const rtlight_t *rtlight;
20 float mqt_viewplanedist;
21 float mqt_viewmaxdist;
22 meshqueue_t *mq_array, *mqt_array, *mq_listhead;
23 int mq_count, mqt_count;
24 int mq_total, mqt_total;
26 void R_MeshQueue_Init(void)
28 Cvar_RegisterVariable(&r_meshqueue_entries);
29 Cvar_RegisterVariable(&r_meshqueue_immediaterender);
30 Cvar_RegisterVariable(&r_meshqueue_sort);
38 void R_MeshQueue_Render(void)
40 // this is only used by one piece of code in prvm_cmds, why is it used at all?
44 for (mq = mq_listhead;mq;mq = mq->next)
45 mq->callback(mq->ent, mq->rtlight, 1, &mq->surfacenumber);
50 static void R_MeshQueue_EnlargeTransparentArray(int newtotal)
52 meshqueue_t *newarray;
53 newarray = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, newtotal * sizeof(meshqueue_t));
56 memcpy(newarray, mqt_array, mqt_total * sizeof(meshqueue_t));
63 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)
65 // this is only used by one piece of code in prvm_cmds, why is it used at all?
66 meshqueue_t *mq, **mqnext;
67 if (r_meshqueue_immediaterender.integer)
69 callback(ent, rtlight, 1, &surfacenumber);
72 if (mq_count >= mq_total)
74 mq = &mq_array[mq_count++];
75 mq->callback = callback;
77 mq->surfacenumber = surfacenumber;
78 mq->rtlight = rtlight;
80 if (r_meshqueue_sort.integer)
82 // bubble-insert sort into meshqueue
83 for(mqnext = &mq_listhead;*mqnext;mqnext = &(*mqnext)->next)
85 if (mq->callback == (*mqnext)->callback)
87 if (mq->ent == (*mqnext)->ent)
89 if (mq->surfacenumber == (*mqnext)->surfacenumber)
91 if (mq->rtlight <= (*mqnext)->rtlight)
94 else if (mq->surfacenumber < (*mqnext)->surfacenumber)
97 else if (mq->ent < (*mqnext)->ent)
100 else if (mq->callback < (*mqnext)->callback)
106 // maintain the order
107 for(mqnext = &mq_listhead;*mqnext;mqnext = &(*mqnext)->next);
113 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)
116 if (mqt_count >= mqt_total)
117 R_MeshQueue_EnlargeTransparentArray(mqt_total + 100);
118 mq = &mqt_array[mqt_count++];
119 mq->callback = callback;
121 mq->surfacenumber = surfacenumber;
122 mq->rtlight = rtlight;
123 mq->dist = DotProduct(center, r_viewforward) - mqt_viewplanedist;
125 mqt_viewmaxdist = max(mqt_viewmaxdist, mq->dist);
128 void R_MeshQueue_RenderTransparent(void)
132 int batchnumsurfaces;
134 const entity_render_t *ent;
135 const rtlight_t *rtlight;
136 void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices);
138 meshqueue_t *hash[4096], **hashpointer[4096];
139 int batchsurfaceindex[256];
141 R_MeshQueue_Render();
144 memset(hash, 0, sizeof(hash));
145 for (i = 0;i < 4096;i++)
146 hashpointer[i] = &hash[i];
147 distscale = 4095.0f / max(mqt_viewmaxdist, 4095);
148 for (i = 0, mqt = mqt_array;i < mqt_count;i++, mqt++)
151 hashdist = (int) (mqt->dist * distscale);
152 hashdist = bound(0, hashdist, 4095);
153 // link to tail of hash chain (to preserve render order)
155 *hashpointer[hashdist] = mqt;
156 hashpointer[hashdist] = &mqt->next;
161 batchnumsurfaces = 0;
162 for (i = 4095;i >= 0;i--)
166 for (mqt = hash[i];mqt;mqt = mqt->next)
168 if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= 256)
170 if (batchnumsurfaces)
171 callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex);
172 batchnumsurfaces = 0;
174 rtlight = mqt->rtlight;
175 callback = mqt->callback;
177 batchsurfaceindex[batchnumsurfaces++] = mqt->surfacenumber;
181 if (batchnumsurfaces)
182 callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex);
186 void R_MeshQueue_BeginScene(void)
188 if (r_meshqueue_entries.integer < 1)
189 Cvar_SetValueQuick(&r_meshqueue_entries, 1);
190 if (r_meshqueue_entries.integer > 65536)
191 Cvar_SetValueQuick(&r_meshqueue_entries, 65536);
193 if (mq_total != r_meshqueue_entries.integer || mq_array == NULL)
195 mq_total = r_meshqueue_entries.integer;
198 mq_array = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, mq_total * sizeof(meshqueue_t));
201 if (mqt_array == NULL)
202 mqt_array = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, mqt_total * sizeof(meshqueue_t));
207 mqt_viewplanedist = DotProduct(r_vieworigin, r_viewforward);
211 void R_MeshQueue_EndScene(void)
215 Con_Printf("R_MeshQueue_EndScene: main mesh queue still has %i items left, flushing\n", mq_count);
216 R_MeshQueue_Render();
220 Con_Printf("R_MeshQueue_EndScene: transparent mesh queue still has %i items left, flushing\n", mqt_count);
221 R_MeshQueue_RenderTransparent();