Cleanup: style, use braces for render
[blender.git] / source / blender / render / intern / source / zbuf.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup render
22  */
23
24 /*---------------------------------------------------------------------------*/
25 /* Common includes                                                           */
26 /*---------------------------------------------------------------------------*/
27
28 #include <string.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BLI_math_base.h"
33
34 /* own includes */
35 #include "zbuf.h"
36
37 /* could enable at some point but for now there are far too many conversions */
38 #ifdef __GNUC__
39 #  pragma GCC diagnostic ignored "-Wdouble-promotion"
40 #endif
41
42 /* ****************** Spans ******************************* */
43
44 /* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */
45 void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty)
46 {
47   memset(zspan, 0, sizeof(ZSpan));
48
49   zspan->rectx = rectx;
50   zspan->recty = recty;
51
52   zspan->span1 = MEM_mallocN(recty * sizeof(float), "zspan");
53   zspan->span2 = MEM_mallocN(recty * sizeof(float), "zspan");
54 }
55
56 void zbuf_free_span(ZSpan *zspan)
57 {
58   if (zspan) {
59     if (zspan->span1) {
60       MEM_freeN(zspan->span1);
61     }
62     if (zspan->span2) {
63       MEM_freeN(zspan->span2);
64     }
65     zspan->span1 = zspan->span2 = NULL;
66   }
67 }
68
69 /* reset range for clipping */
70 static void zbuf_init_span(ZSpan *zspan)
71 {
72   zspan->miny1 = zspan->miny2 = zspan->recty + 1;
73   zspan->maxy1 = zspan->maxy2 = -1;
74   zspan->minp1 = zspan->maxp1 = zspan->minp2 = zspan->maxp2 = NULL;
75 }
76
77 static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
78 {
79   const float *minv, *maxv;
80   float *span;
81   float xx1, dx0, xs0;
82   int y, my0, my2;
83
84   if (v1[1] < v2[1]) {
85     minv = v1;
86     maxv = v2;
87   }
88   else {
89     minv = v2;
90     maxv = v1;
91   }
92
93   my0 = ceil(minv[1]);
94   my2 = floor(maxv[1]);
95
96   if (my2 < 0 || my0 >= zspan->recty) {
97     return;
98   }
99
100   /* clip top */
101   if (my2 >= zspan->recty) {
102     my2 = zspan->recty - 1;
103   }
104   /* clip bottom */
105   if (my0 < 0) {
106     my0 = 0;
107   }
108
109   if (my0 > my2) {
110     return;
111   }
112   /* if (my0>my2) should still fill in, that way we get spans that skip nicely */
113
114   xx1 = maxv[1] - minv[1];
115   if (xx1 > FLT_EPSILON) {
116     dx0 = (minv[0] - maxv[0]) / xx1;
117     xs0 = dx0 * (minv[1] - my2) + minv[0];
118   }
119   else {
120     dx0 = 0.0f;
121     xs0 = min_ff(minv[0], maxv[0]);
122   }
123
124   /* empty span */
125   if (zspan->maxp1 == NULL) {
126     span = zspan->span1;
127   }
128   else { /* does it complete left span? */
129     if (maxv == zspan->minp1 || minv == zspan->maxp1) {
130       span = zspan->span1;
131     }
132     else {
133       span = zspan->span2;
134     }
135   }
136
137   if (span == zspan->span1) {
138     //      printf("left span my0 %d my2 %d\n", my0, my2);
139     if (zspan->minp1 == NULL || zspan->minp1[1] > minv[1]) {
140       zspan->minp1 = minv;
141     }
142     if (zspan->maxp1 == NULL || zspan->maxp1[1] < maxv[1]) {
143       zspan->maxp1 = maxv;
144     }
145     if (my0 < zspan->miny1) {
146       zspan->miny1 = my0;
147     }
148     if (my2 > zspan->maxy1) {
149       zspan->maxy1 = my2;
150     }
151   }
152   else {
153     //      printf("right span my0 %d my2 %d\n", my0, my2);
154     if (zspan->minp2 == NULL || zspan->minp2[1] > minv[1]) {
155       zspan->minp2 = minv;
156     }
157     if (zspan->maxp2 == NULL || zspan->maxp2[1] < maxv[1]) {
158       zspan->maxp2 = maxv;
159     }
160     if (my0 < zspan->miny2) {
161       zspan->miny2 = my0;
162     }
163     if (my2 > zspan->maxy2) {
164       zspan->maxy2 = my2;
165     }
166   }
167
168   for (y = my2; y >= my0; y--, xs0 += dx0) {
169     /* xs0 is the xcoord! */
170     span[y] = xs0;
171   }
172 }
173
174 /*-----------------------------------------------------------*/
175 /* Functions                                                 */
176 /*-----------------------------------------------------------*/
177
178 /* Scanconvert for strand triangles, calls func for each x, y coordinate
179  * and gives UV barycentrics and z. */
180
181 void zspan_scanconvert(ZSpan *zspan,
182                        void *handle,
183                        float *v1,
184                        float *v2,
185                        float *v3,
186                        void (*func)(void *, int, int, float, float))
187 {
188   float x0, y0, x1, y1, x2, y2, z0, z1, z2;
189   float u, v, uxd, uyd, vxd, vyd, uy0, vy0, xx1;
190   const float *span1, *span2;
191   int i, j, x, y, sn1, sn2, rectx = zspan->rectx, my0, my2;
192
193   /* init */
194   zbuf_init_span(zspan);
195
196   /* set spans */
197   zbuf_add_to_span(zspan, v1, v2);
198   zbuf_add_to_span(zspan, v2, v3);
199   zbuf_add_to_span(zspan, v3, v1);
200
201   /* clipped */
202   if (zspan->minp2 == NULL || zspan->maxp2 == NULL) {
203     return;
204   }
205
206   my0 = max_ii(zspan->miny1, zspan->miny2);
207   my2 = min_ii(zspan->maxy1, zspan->maxy2);
208
209   //  printf("my %d %d\n", my0, my2);
210   if (my2 < my0) {
211     return;
212   }
213
214   /* ZBUF DX DY, in floats still */
215   x1 = v1[0] - v2[0];
216   x2 = v2[0] - v3[0];
217   y1 = v1[1] - v2[1];
218   y2 = v2[1] - v3[1];
219
220   z1 = 1.0f; /* (u1 - u2) */
221   z2 = 0.0f; /* (u2 - u3) */
222
223   x0 = y1 * z2 - z1 * y2;
224   y0 = z1 * x2 - x1 * z2;
225   z0 = x1 * y2 - y1 * x2;
226
227   if (z0 == 0.0f) {
228     return;
229   }
230
231   xx1 = (x0 * v1[0] + y0 * v1[1]) / z0 + 1.0f;
232   uxd = -(double)x0 / (double)z0;
233   uyd = -(double)y0 / (double)z0;
234   uy0 = ((double)my2) * uyd + (double)xx1;
235
236   z1 = -1.0f; /* (v1 - v2) */
237   z2 = 1.0f;  /* (v2 - v3) */
238
239   x0 = y1 * z2 - z1 * y2;
240   y0 = z1 * x2 - x1 * z2;
241
242   xx1 = (x0 * v1[0] + y0 * v1[1]) / z0;
243   vxd = -(double)x0 / (double)z0;
244   vyd = -(double)y0 / (double)z0;
245   vy0 = ((double)my2) * vyd + (double)xx1;
246
247   /* correct span */
248   span1 = zspan->span1 + my2;
249   span2 = zspan->span2 + my2;
250
251   for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) {
252
253     sn1 = floor(min_ff(*span1, *span2));
254     sn2 = floor(max_ff(*span1, *span2));
255     sn1++;
256
257     if (sn2 >= rectx) {
258       sn2 = rectx - 1;
259     }
260     if (sn1 < 0) {
261       sn1 = 0;
262     }
263
264     u = (((double)sn1 * uxd) + uy0) - (i * uyd);
265     v = (((double)sn1 * vxd) + vy0) - (i * vyd);
266
267     for (j = 0, x = sn1; x <= sn2; j++, x++) {
268       func(handle, x, y, u + (j * uxd), v + (j * vxd));
269     }
270   }
271 }
272
273 /* end of zbuf.c */