cmd: Reduce duplicate code with command lookup
[xonotic/darkplaces.git] / meshqueue.c
1 #include "quakedef.h"
2 #include "meshqueue.h"
3
4 typedef struct meshqueue_s
5 {
6         struct meshqueue_s *next;
7         void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices);
8         const entity_render_t *ent;
9         int surfacenumber;
10         const rtlight_t *rtlight;
11         float dist;
12         dptransparentsortcategory_t category;
13 }
14 meshqueue_t;
15
16 int trans_sortarraysize;
17 meshqueue_t **trans_hash = NULL;
18 meshqueue_t ***trans_hashpointer = NULL;
19
20 float mqt_viewplanedist;
21 float mqt_viewmaxdist;
22 meshqueue_t *mqt_array;
23 int mqt_count;
24 int mqt_total;
25
26 void R_MeshQueue_BeginScene(void)
27 {
28         mqt_count = 0;
29         mqt_viewplanedist = DotProduct(r_refdef.view.origin, r_refdef.view.forward);
30         mqt_viewmaxdist = 0;
31 }
32
33 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)
34 {
35         meshqueue_t *mq;
36         if (mqt_count >= mqt_total || !mqt_array)
37         {
38                 int newtotal = max(1024, mqt_total * 2);
39                 meshqueue_t *newarray = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, newtotal * sizeof(meshqueue_t));
40                 if (mqt_array)
41                 {
42                         memcpy(newarray, mqt_array, mqt_total * sizeof(meshqueue_t));
43                         Mem_Free(mqt_array);
44                 }
45                 mqt_array = newarray;
46                 mqt_total = newtotal;
47         }
48         mq = &mqt_array[mqt_count++];
49         mq->callback = callback;
50         mq->ent = ent;
51         mq->surfacenumber = surfacenumber;
52         mq->rtlight = rtlight;
53         mq->category = category;
54         if (r_transparent_useplanardistance.integer)
55                 mq->dist = DotProduct(center, r_refdef.view.forward) - mqt_viewplanedist;
56         else
57                 mq->dist = VectorDistance(center, r_refdef.view.origin);
58         mq->next = NULL;
59         mqt_viewmaxdist = max(mqt_viewmaxdist, mq->dist);
60 }
61
62 void R_MeshQueue_RenderTransparent(void)
63 {
64         int i, hashindex, maxhashindex, batchnumsurfaces;
65         float distscale;
66         const entity_render_t *ent;
67         const rtlight_t *rtlight;
68         void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices);
69         int batchsurfaceindex[MESHQUEUE_TRANSPARENT_BATCHSIZE];
70         meshqueue_t *mqt;
71
72         if (!mqt_count)
73                 return;
74
75         // check for bad cvars
76         if (r_transparent_sortarraysize.integer < 1 || r_transparent_sortarraysize.integer > 32768)
77                 Cvar_SetValueQuick(&r_transparent_sortarraysize, bound(1, r_transparent_sortarraysize.integer, 32768));
78         if (r_transparent_sortmindist.integer < 0 || r_transparent_sortmindist.integer >= r_transparent_sortmaxdist.integer)
79                 Cvar_SetValueQuick(&r_transparent_sortmindist, 0);
80         if (r_transparent_sortmaxdist.integer < r_transparent_sortmindist.integer || r_transparent_sortmaxdist.integer > 32768)
81                 Cvar_SetValueQuick(&r_transparent_sortmaxdist, bound(r_transparent_sortmindist.integer, r_transparent_sortmaxdist.integer, 32768));
82
83         // update hash array
84         if (trans_sortarraysize != r_transparent_sortarraysize.integer)
85         {
86                 trans_sortarraysize = r_transparent_sortarraysize.integer;
87                 if (trans_hash)
88                         Mem_Free(trans_hash);
89                 trans_hash = (meshqueue_t **)Mem_Alloc(cls.permanentmempool, sizeof(meshqueue_t *) * trans_sortarraysize); 
90                 if (trans_hashpointer)
91                         Mem_Free(trans_hashpointer);
92                 trans_hashpointer = (meshqueue_t ***)Mem_Alloc(cls.permanentmempool, sizeof(meshqueue_t **) * trans_sortarraysize); 
93         }
94
95         // build index
96         memset(trans_hash, 0, sizeof(meshqueue_t *) * trans_sortarraysize);
97         for (i = 0; i < trans_sortarraysize; i++)
98                 trans_hashpointer[i] = &trans_hash[i];
99         distscale = (trans_sortarraysize - 1) / min(mqt_viewmaxdist, r_transparent_sortmaxdist.integer);
100         maxhashindex = trans_sortarraysize - 1;
101         for (i = 0, mqt = mqt_array; i < mqt_count; i++, mqt++)
102         {
103                 switch(mqt->category)
104                 {
105                 default:
106                 case TRANSPARENTSORT_HUD:
107                         hashindex = 0;
108                         break;
109                 case TRANSPARENTSORT_DISTANCE:
110                         // this could use a reduced range if we need more categories
111                         hashindex = bound(0, (int)(bound(0, mqt->dist - r_transparent_sortmindist.integer, r_transparent_sortmaxdist.integer) * distscale), maxhashindex);
112                         break;
113                 case TRANSPARENTSORT_SKY:
114                         hashindex = maxhashindex;
115                         break;
116                 }
117                 // link to tail of hash chain (to preserve render order)
118                 mqt->next = NULL;
119                 *trans_hashpointer[hashindex] = mqt;
120                 trans_hashpointer[hashindex] = &mqt->next;
121         }
122         callback = NULL;
123         ent = NULL;
124         rtlight = NULL;
125         batchnumsurfaces = 0;
126
127         // draw
128         for (i = maxhashindex; i >= 0; i--)
129         {
130                 if (trans_hash[i])
131                 {
132                         for (mqt = trans_hash[i]; mqt; mqt = mqt->next)
133                         {
134                                 if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= MESHQUEUE_TRANSPARENT_BATCHSIZE)
135                                 {
136                                         if (batchnumsurfaces)
137                                                 callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex);
138                                         batchnumsurfaces = 0;
139                                         ent = mqt->ent;
140                                         rtlight = mqt->rtlight;
141                                         callback = mqt->callback;
142                                 }
143                                 batchsurfaceindex[batchnumsurfaces++] = mqt->surfacenumber;
144                         }
145                 }
146         }
147         if (batchnumsurfaces)
148                 callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex);
149         mqt_count = 0;
150 }