]> git.xonotic.org Git - xonotic/darkplaces.git/blob - meshqueue.c
optimizing R_DrawSurfaces and WorldNode functions
[xonotic/darkplaces.git] / meshqueue.c
1
2 #include "quakedef.h"
3 #include "meshqueue.h"
4
5 cvar_t r_meshqueue_entries = {CVAR_SAVE, "r_meshqueue_entries", "16"};
6 cvar_t r_meshqueue_immediaterender = {0, "r_meshqueue_immediaterender", "0"};
7 cvar_t r_meshqueue_sort = {0, "r_meshqueue_sort", "0"};
8
9 typedef struct meshqueue_s
10 {
11         struct meshqueue_s *next;
12         void (*callback)(const void *data1, int data2);
13         const void *data1;
14         int data2;
15         float dist;
16 }
17 meshqueue_t;
18
19 float mqt_viewplanedist;
20 meshqueue_t *mq_array, *mqt_array, *mq_listhead;
21 int mq_count, mqt_count;
22 int mq_total, mqt_total;
23
24 mempool_t *meshqueuemempool;
25
26 void R_MeshQueue_Init(void)
27 {
28         Cvar_RegisterVariable(&r_meshqueue_entries);
29         Cvar_RegisterVariable(&r_meshqueue_immediaterender);
30         Cvar_RegisterVariable(&r_meshqueue_sort);
31
32         meshqueuemempool = Mem_AllocPool("R_MeshQueue");
33         mq_total = 0;
34         mqt_total = 1000;
35         mq_array = NULL;
36         mqt_array = NULL;
37 }
38
39 void R_MeshQueue_Render(void)
40 {
41         meshqueue_t *mq;
42         if (!mq_count)
43                 return;
44         for (mq = mq_listhead;mq;mq = mq->next)
45                 mq->callback(mq->data1, mq->data2);
46         mq_count = 0;
47         mq_listhead = NULL;
48 }
49
50 static void R_MeshQueue_EnlargeTransparentArray(int newtotal)
51 {
52         meshqueue_t *newarray;
53         newarray = Mem_Alloc(meshqueuemempool, newtotal * sizeof(meshqueue_t));
54         if (mqt_array)
55         {
56                 memcpy(newarray, mqt_array, mqt_total * sizeof(meshqueue_t));
57                 Mem_Free(mqt_array);
58         }
59         mqt_array = newarray;
60         mqt_total = newtotal;
61 }
62
63 void R_MeshQueue_Add(void (*callback)(const void *data1, int data2), const void *data1, int data2)
64 {
65         meshqueue_t *mq, **mqnext;
66         if (r_meshqueue_immediaterender.integer)
67         {
68                 callback(data1, data2);
69                 return;
70         }
71         if (mq_count >= mq_total)
72                 R_MeshQueue_Render();
73         mq = &mq_array[mq_count++];
74         mq->callback = callback;
75         mq->data1 = data1;
76         mq->data2 = data2;
77
78         if (r_meshqueue_sort.integer)
79         {
80                 // bubble-insert sort into meshqueue
81                 for(mqnext = &mq_listhead;*mqnext;mqnext = &(*mqnext)->next)
82                 {
83                         if (mq->callback == (*mqnext)->callback)
84                         {
85                                 if (mq->data1 == (*mqnext)->data1)
86                                 {
87                                         if (mq->data2 <= (*mqnext)->data2)
88                                                 break;
89                                 }
90                                 else if (mq->data1 < (*mqnext)->data1)
91                                         break;
92                         }
93                         else if (mq->callback < (*mqnext)->callback)
94                                 break;
95                 }
96         }
97         else
98         {
99                 // maintain the order
100                 for(mqnext = &mq_listhead;*mqnext;mqnext = &(*mqnext)->next);
101         }
102         mq->next = *mqnext;
103         *mqnext = mq;
104 }
105
106 void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const void *data1, int data2), const void *data1, int data2)
107 {
108         meshqueue_t *mq;
109         if (mqt_count >= mqt_total)
110                 R_MeshQueue_EnlargeTransparentArray(mqt_total + 100);
111         mq = &mqt_array[mqt_count++];
112         mq->callback = callback;
113         mq->data1 = data1;
114         mq->data2 = data2;
115         mq->dist = DotProduct(center, vpn) - mqt_viewplanedist;
116         mq->next = NULL;
117 }
118
119 void R_MeshQueue_RenderTransparent(void)
120 {
121         int i;
122         int hashdist;
123         meshqueue_t *mqt;
124         meshqueue_t *hash[4096], **hashpointer[4096];
125         if (mq_count)
126                 R_MeshQueue_Render();
127         if (!mqt_count)
128                 return;
129         memset(hash, 0, sizeof(hash));
130         for (i = 0;i < 4096;i++)
131                 hashpointer[i] = &hash[i];
132         for (i = 0, mqt = mqt_array;i < mqt_count;i++, mqt++)
133         {
134                 // generate index
135                 hashdist = (int) (mqt->dist);
136                 hashdist = bound(0, hashdist, 4095);
137                 // link to tail of hash chain (to preserve render order)
138                 mqt->next = NULL;
139                 *hashpointer[hashdist] = mqt;
140                 hashpointer[hashdist] = &mqt->next;
141         }
142         for (i = 4095;i >= 0;i--)
143                 if (hash[i])
144                         for (mqt = hash[i];mqt;mqt = mqt->next)
145                                 mqt->callback(mqt->data1, mqt->data2);
146         mqt_count = 0;
147 }
148
149 void R_MeshQueue_BeginScene(void)
150 {
151         if (r_meshqueue_entries.integer < 1)
152                 Cvar_SetValueQuick(&r_meshqueue_entries, 1);
153         if (r_meshqueue_entries.integer > 65536)
154                 Cvar_SetValueQuick(&r_meshqueue_entries, 65536);
155
156         if (mq_total != r_meshqueue_entries.integer || mq_array == NULL)
157         {
158                 mq_total = r_meshqueue_entries.integer;
159                 if (mq_array)
160                         Mem_Free(mq_array);
161                 mq_array = Mem_Alloc(meshqueuemempool, mq_total * sizeof(meshqueue_t));
162         }
163
164         if (mqt_array == NULL)
165                 mqt_array = Mem_Alloc(meshqueuemempool, mqt_total * sizeof(meshqueue_t));
166
167         mq_count = 0;
168         mqt_count = 0;
169         mq_listhead = NULL;
170         mqt_viewplanedist = DotProduct(r_origin, vpn);
171 }
172
173 void R_MeshQueue_EndScene(void)
174 {
175         if (mq_count)
176         {
177                 Con_Printf("R_MeshQueue_EndScene: main mesh queue still has %i items left, flushing\n", mq_count);
178                 R_MeshQueue_Render();
179         }
180         if (mqt_count)
181         {
182                 Con_Printf("R_MeshQueue_EndScene: transparent mesh queue still has %i items left, flushing\n", mqt_count);
183                 R_MeshQueue_RenderTransparent();
184         }
185 }
186