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