eliminated qbyte type, now uses unsigned char throughout the engine for this purpose
[divverent/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 void R_MeshQueue_Init(void)
25 {
26         Cvar_RegisterVariable(&r_meshqueue_entries);
27         Cvar_RegisterVariable(&r_meshqueue_immediaterender);
28         Cvar_RegisterVariable(&r_meshqueue_sort);
29
30         mq_total = 0;
31         mqt_total = 0;
32         mq_array = NULL;
33         mqt_array = NULL;
34 }
35
36 void R_MeshQueue_Render(void)
37 {
38         meshqueue_t *mq;
39         if (!mq_count)
40                 return;
41         for (mq = mq_listhead;mq;mq = mq->next)
42                 mq->callback(mq->data1, mq->data2);
43         mq_count = 0;
44         mq_listhead = NULL;
45 }
46
47 static void R_MeshQueue_EnlargeTransparentArray(int newtotal)
48 {
49         meshqueue_t *newarray;
50         newarray = (meshqueue_t *)Mem_Alloc(cl_mempool, newtotal * sizeof(meshqueue_t));
51         if (mqt_array)
52         {
53                 memcpy(newarray, mqt_array, mqt_total * sizeof(meshqueue_t));
54                 Mem_Free(mqt_array);
55         }
56         mqt_array = newarray;
57         mqt_total = newtotal;
58 }
59
60 void R_MeshQueue_Add(void (*callback)(const void *data1, int data2), const void *data1, int data2)
61 {
62         meshqueue_t *mq, **mqnext;
63         if (r_meshqueue_immediaterender.integer)
64         {
65                 callback(data1, data2);
66                 return;
67         }
68         if (mq_count >= mq_total)
69                 R_MeshQueue_Render();
70         mq = &mq_array[mq_count++];
71         mq->callback = callback;
72         mq->data1 = data1;
73         mq->data2 = data2;
74
75         if (r_meshqueue_sort.integer)
76         {
77                 // bubble-insert sort into meshqueue
78                 for(mqnext = &mq_listhead;*mqnext;mqnext = &(*mqnext)->next)
79                 {
80                         if (mq->callback == (*mqnext)->callback)
81                         {
82                                 if (mq->data1 == (*mqnext)->data1)
83                                 {
84                                         if (mq->data2 <= (*mqnext)->data2)
85                                                 break;
86                                 }
87                                 else if (mq->data1 < (*mqnext)->data1)
88                                         break;
89                         }
90                         else if (mq->callback < (*mqnext)->callback)
91                                 break;
92                 }
93         }
94         else
95         {
96                 // maintain the order
97                 for(mqnext = &mq_listhead;*mqnext;mqnext = &(*mqnext)->next);
98         }
99         mq->next = *mqnext;
100         *mqnext = mq;
101 }
102
103 void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const void *data1, int data2), const void *data1, int data2)
104 {
105         meshqueue_t *mq;
106         if (mqt_count >= mqt_total)
107                 R_MeshQueue_EnlargeTransparentArray(mqt_total + 100);
108         mq = &mqt_array[mqt_count++];
109         mq->callback = callback;
110         mq->data1 = data1;
111         mq->data2 = data2;
112         mq->dist = DotProduct(center, r_viewforward) - mqt_viewplanedist;
113         mq->next = NULL;
114 }
115
116 void R_MeshQueue_RenderTransparent(void)
117 {
118         int i;
119         int hashdist;
120         meshqueue_t *mqt;
121         meshqueue_t *hash[4096], **hashpointer[4096];
122         if (mq_count)
123                 R_MeshQueue_Render();
124         if (!mqt_count)
125                 return;
126         memset(hash, 0, sizeof(hash));
127         for (i = 0;i < 4096;i++)
128                 hashpointer[i] = &hash[i];
129         for (i = 0, mqt = mqt_array;i < mqt_count;i++, mqt++)
130         {
131                 // generate index
132                 hashdist = (int) (mqt->dist);
133                 hashdist = bound(0, hashdist, 4095);
134                 // link to tail of hash chain (to preserve render order)
135                 mqt->next = NULL;
136                 *hashpointer[hashdist] = mqt;
137                 hashpointer[hashdist] = &mqt->next;
138         }
139         for (i = 4095;i >= 0;i--)
140                 if (hash[i])
141                         for (mqt = hash[i];mqt;mqt = mqt->next)
142                                 mqt->callback(mqt->data1, mqt->data2);
143         mqt_count = 0;
144 }
145
146 void R_MeshQueue_BeginScene(void)
147 {
148         if (r_meshqueue_entries.integer < 1)
149                 Cvar_SetValueQuick(&r_meshqueue_entries, 1);
150         if (r_meshqueue_entries.integer > 65536)
151                 Cvar_SetValueQuick(&r_meshqueue_entries, 65536);
152
153         if (mq_total != r_meshqueue_entries.integer || mq_array == NULL)
154         {
155                 mq_total = r_meshqueue_entries.integer;
156                 if (mq_array)
157                         Mem_Free(mq_array);
158                 mq_array = (meshqueue_t *)Mem_Alloc(cl_mempool, mq_total * sizeof(meshqueue_t));
159         }
160
161         if (mqt_array == NULL)
162                 mqt_array = (meshqueue_t *)Mem_Alloc(cl_mempool, mqt_total * sizeof(meshqueue_t));
163
164         mq_count = 0;
165         mqt_count = 0;
166         mq_listhead = NULL;
167         mqt_viewplanedist = DotProduct(r_vieworigin, r_viewforward);
168 }
169
170 void R_MeshQueue_EndScene(void)
171 {
172         if (mq_count)
173         {
174                 Con_Printf("R_MeshQueue_EndScene: main mesh queue still has %i items left, flushing\n", mq_count);
175                 R_MeshQueue_Render();
176         }
177         if (mqt_count)
178         {
179                 Con_Printf("R_MeshQueue_EndScene: transparent mesh queue still has %i items left, flushing\n", mqt_count);
180                 R_MeshQueue_RenderTransparent();
181         }
182 }
183