Panda3D
 All Classes Functions Variables Enumerations
zbuffer.cxx
1 /*
2 
3  * Z buffer: 16 bits Z / 32 bits color
4  *
5  */
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <assert.h>
9 #include <string.h>
10 #include "zbuffer.h"
11 #include "pnotify.h"
12 
13 #ifdef DO_PSTATS
14 int pixel_count_white_untextured;
15 int pixel_count_flat_untextured;
16 int pixel_count_smooth_untextured;
17 int pixel_count_white_textured;
18 int pixel_count_flat_textured;
19 int pixel_count_smooth_textured;
20 int pixel_count_white_perspective;
21 int pixel_count_flat_perspective;
22 int pixel_count_smooth_perspective;
23 int pixel_count_smooth_multitex2;
24 int pixel_count_smooth_multitex3;
25 #endif // DO_PSTATS
26 
27 ZBuffer *
28 ZB_open(int xsize, int ysize, int mode,
29  int nb_colors,
30  unsigned char *color_indexes,
31  unsigned int *color_table,
32  void *frame_buffer) {
33  ZBuffer *zb;
34  int size;
35 
36  zb = (ZBuffer *)gl_malloc(sizeof(ZBuffer));
37  if (zb == NULL)
38  return NULL;
39  memset(zb, 0, sizeof(ZBuffer));
40 
41  /* xsize must be a multiple of 4 */
42  xsize = (xsize + 3) & ~3;
43 
44  zb->xsize = xsize;
45  zb->ysize = ysize;
46  zb->mode = mode;
47  zb->linesize = (xsize * PSZB + 3) & ~3;
48 
49  switch (mode) {
50 #ifdef TGL_FEATURE_8_BITS
51  case ZB_MODE_INDEX:
52  ZB_initDither(zb, nb_colors, color_indexes, color_table);
53  break;
54 #endif
55 #ifdef TGL_FEATURE_32_BITS
56  case ZB_MODE_RGBA:
57 #endif
58 #ifdef TGL_FEATURE_24_BITS
59  case ZB_MODE_RGB24:
60 #endif
61  case ZB_MODE_5R6G5B:
62  zb->nb_colors = 0;
63  break;
64  default:
65  goto error;
66  }
67 
68  size = zb->xsize * zb->ysize * sizeof(ZPOINT);
69 
70  zb->zbuf = (ZPOINT *)gl_malloc(size);
71  if (zb->zbuf == NULL)
72  goto error;
73 
74  if (frame_buffer == NULL) {
75  zb->pbuf = (PIXEL *)gl_malloc(zb->ysize * zb->linesize);
76  if (zb->pbuf == NULL) {
77  gl_free(zb->zbuf);
78  goto error;
79  }
80  zb->frame_buffer_allocated = 1;
81  } else {
82  zb->frame_buffer_allocated = 0;
83  zb->pbuf = (PIXEL *)frame_buffer;
84  }
85 
86  return zb;
87  error:
88  gl_free(zb);
89  return NULL;
90 }
91 
92 void
93 ZB_close(ZBuffer * zb) {
94 #ifdef TGL_FEATURE_8_BITS
95  if (zb->mode == ZB_MODE_INDEX)
96  ZB_closeDither(zb);
97 #endif
98 
99  if (zb->frame_buffer_allocated)
100  gl_free(zb->pbuf);
101 
102  gl_free(zb->zbuf);
103  gl_free(zb);
104 }
105 
106 void
107 ZB_resize(ZBuffer * zb, void *frame_buffer, int xsize, int ysize) {
108  int size;
109 
110  nassertv(zb != NULL);
111 
112  /* xsize must be a multiple of 4 */
113  xsize = (xsize + 3) & ~3;
114 
115  zb->xsize = xsize;
116  zb->ysize = ysize;
117  zb->linesize = (xsize * PSZB + 3) & ~3;
118 
119  size = zb->xsize * zb->ysize * sizeof(ZPOINT);
120  gl_free(zb->zbuf);
121  zb->zbuf = (ZPOINT *)gl_malloc(size);
122 
123  if (zb->frame_buffer_allocated)
124  gl_free(zb->pbuf);
125 
126  if (frame_buffer == NULL) {
127  zb->pbuf = (PIXEL *)gl_malloc(zb->ysize * zb->linesize);
128  zb->frame_buffer_allocated = 1;
129  } else {
130  zb->pbuf = (PIXEL *)frame_buffer;
131  zb->frame_buffer_allocated = 0;
132  }
133 }
134 
135 static void
136 ZB_copyBuffer(const ZBuffer * zb,
137  void *buf,
138  int linesize) {
139  unsigned char *p1;
140  PIXEL *q;
141  int y, n;
142 
143  q = zb->pbuf;
144  p1 = (unsigned char *)buf;
145  n = zb->xsize * PSZB;
146  for (y = 0; y < zb->ysize; y++) {
147  memcpy(p1, q, n);
148  p1 += linesize;
149  q = (PIXEL *) ((char *) q + zb->linesize);
150  }
151 }
152 
153 static void
154 ZB_copyBufferNoAlpha(const ZBuffer * zb, void *buf, int linesize) {
155  const PIXEL *q = zb->pbuf;
156  PIXEL *p = (PIXEL *)buf;
157  int xsize = zb->xsize;
158  for (int y = 0; y < zb->ysize; ++y) {
159  const PIXEL *q1 = q;
160  PIXEL *p1 = p;
161  PIXEL *p2 = p1 + xsize;
162  while (p1 < p2) {
163  // Make sure the alpha bits are set to 0xff.
164 #ifdef WORDS_BIGENDIAN
165  *p1 = *q1 | 0x000000ff;
166 #else
167  *p1 = *q1 | 0xff000000;
168 #endif
169  ++p1;
170  ++q1;
171  }
172  p = (PIXEL *) ((char *) p + linesize);
173  q = (const PIXEL *) ((const char *) q + zb->linesize);
174  }
175 }
176 
177 #define RGB32_TO_RGB16(v) \
178  (((v >> 8) & 0xf800) | (((v) >> 5) & 0x07e0) | (((v) & 0xff) >> 3))
179 
180 /* XXX: not optimized */
181 static void ZB_copyFrameBuffer5R6G5B(const ZBuffer * zb,
182  void *buf, int linesize)
183 {
184  PIXEL *q;
185  unsigned short *p, *p1;
186  int y, n;
187 
188  q = zb->pbuf;
189  p1 = (unsigned short *) buf;
190 
191  for (y = 0; y < zb->ysize; y++) {
192  p = p1;
193  n = zb->xsize >> 2;
194  do {
195  p[0] = RGB32_TO_RGB16(q[0]);
196  p[1] = RGB32_TO_RGB16(q[1]);
197  p[2] = RGB32_TO_RGB16(q[2]);
198  p[3] = RGB32_TO_RGB16(q[3]);
199  q += 4;
200  p += 4;
201  } while (--n > 0);
202  p1 = (unsigned short *)((char *)p1 + linesize);
203  }
204 }
205 
206 /* XXX: not optimized */
207 static void ZB_copyFrameBufferRGB24(const ZBuffer * zb,
208  void *buf, int linesize)
209 {
210  PIXEL *q;
211  unsigned char *p, *p1;
212  int y, n;
213 
214  fprintf(stderr, "copyFrameBufferRGB24\n");
215 
216  q = zb->pbuf;
217  p1 = (unsigned char *) buf;
218 
219  for (y = 0; y < zb->ysize; y++) {
220  p = p1;
221  n = zb->xsize;
222  do {
223  p[0] = q[0];
224  p[1] = q[1];
225  p[2] = q[2];
226  q += 4;
227  p += 3;
228  } while (--n > 0);
229  p1 += linesize;
230  }
231 }
232 
233 void
234 ZB_copyFrameBuffer(const ZBuffer * zb, void *buf,
235  int linesize) {
236  switch (zb->mode) {
237 #ifdef TGL_FEATURE_16_BITS
238  case ZB_MODE_5R6G5B:
239  ZB_copyFrameBuffer5R6G5B(zb, buf, linesize);
240  break;
241 #endif
242 #ifdef TGL_FEATURE_24_BITS
243  case ZB_MODE_RGB24:
244  ZB_copyFrameBufferRGB24(zb, buf, linesize);
245  break;
246 #endif
247 #ifdef TGL_FEATURE_32_BITS
248  case ZB_MODE_RGBA:
249  ZB_copyBuffer(zb, buf, linesize);
250  break;
251 #endif
252  default:
253  assert(0);
254  }
255 }
256 
257 void
258 ZB_copyFrameBufferNoAlpha(const ZBuffer * zb, void *buf,
259  int linesize) {
260  switch (zb->mode) {
261 #ifdef TGL_FEATURE_16_BITS
262  case ZB_MODE_5R6G5B:
263  ZB_copyFrameBuffer5R6G5B(zb, buf, linesize);
264  break;
265 #endif
266 #ifdef TGL_FEATURE_24_BITS
267  case ZB_MODE_RGB24:
268  ZB_copyFrameBufferRGB24(zb, buf, linesize);
269  break;
270 #endif
271 #ifdef TGL_FEATURE_32_BITS
272  case ZB_MODE_RGBA:
273  ZB_copyBufferNoAlpha(zb, buf, linesize);
274  break;
275 #endif
276  default:
277  assert(0);
278  }
279 }
280 
281 // Copy from (source_xmin,source_ymin)+(source_xsize,source_ysize) to
282 // (dest_xmin,dest_ymin)+(dest_xsize,dest_ysize).
283 void ZB_zoomFrameBuffer(ZBuffer *dest, int dest_xmin, int dest_ymin, int dest_xsize, int dest_ysize,
284  const ZBuffer *source, int source_xmin, int source_ymin, int source_xsize, int source_ysize) {
285  int tyinc = dest->linesize / PSZB;
286  int fyinc = source->linesize / PSZB;
287 
288  int fyt = 0;
289  for (int ty = 0; ty < dest_ysize; ++ty) {
290  int fy = fyt / dest_ysize;
291  fyt += source_ysize;
292 
293  PIXEL *tp = dest->pbuf + dest_xmin + (dest_ymin + ty) * tyinc;
294  PIXEL *fp = source->pbuf + source_xmin + (source_ymin + fy) * fyinc;
295  ZPOINT *tz = dest->zbuf + dest_xmin + (dest_ymin + ty) * dest->xsize;
296  ZPOINT *fz = source->zbuf + source_xmin + (source_ymin + fy) * source->xsize;
297  int fxt = 0;
298  for (int tx = 0; tx < dest_xsize; ++tx) {
299  int fx = fxt / dest_xsize;
300  fxt += source_xsize;
301 
302  tp[tx] = fp[fx];
303  tz[tx] = fz[fx];
304  }
305  }
306 }
307 
308 
309 /*
310  * adr must be aligned on an 'int'
311  */
312 void
313 memset_s(void *adr, int val, int count) {
314  int i, n, v;
315  unsigned int *p;
316  unsigned short *q;
317 
318  p = (unsigned int *)adr;
319  v = val | (val << 16);
320 
321  n = count >> 3;
322  for (i = 0; i < n; i++) {
323  p[0] = v;
324  p[1] = v;
325  p[2] = v;
326  p[3] = v;
327  p += 4;
328  }
329 
330  q = (unsigned short *) p;
331  n = count & 7;
332  for (i = 0; i < n; i++)
333  *q++ = val;
334 }
335 
336 void
337 memset_l(void *adr, int val, int count) {
338  int i, n, v;
339  unsigned int *p;
340 
341  p = (unsigned int *)adr;
342  v = val;
343  n = count >> 2;
344  for (i = 0; i < n; i++) {
345  p[0] = v;
346  p[1] = v;
347  p[2] = v;
348  p[3] = v;
349  p += 4;
350  }
351 
352  n = count & 3;
353  for (i = 0; i < n; i++)
354  *p++ = val;
355 }
356 
357 /* count must be a multiple of 4 and >= 4 */
358 void
359 memset_RGB24(void *adr,int r, int v, int b,long count) {
360  long i, n;
361  long v1,v2,v3,*pt=(long *)(adr);
362  unsigned char *p,R=(unsigned char)r,V=(unsigned char)v,B=(unsigned char)b;
363 
364  p=(unsigned char *)adr;
365  *p++=R;
366  *p++=V;
367  *p++=B;
368  *p++=R;
369  *p++=V;
370  *p++=B;
371  *p++=R;
372  *p++=V;
373  *p++=B;
374  *p++=R;
375  *p++=V;
376  *p++=B;
377  v1=*pt++;
378  v2=*pt++;
379  v3=*pt++;
380  n = count >> 2;
381  for(i=1;i<n;i++) {
382  *pt++=v1;
383  *pt++=v2;
384  *pt++=v3;
385  }
386 }
387 
388 void
389 ZB_clear(ZBuffer * zb, int clear_z, ZPOINT z, int clear_color, PIXEL color) {
390  int y;
391  PIXEL *pp;
392 
393  if (clear_z) {
394  memset(zb->zbuf, 0, zb->xsize * zb->ysize * sizeof(ZPOINT));
395  }
396  if (clear_color) {
397  pp = zb->pbuf;
398  for (y = 0; y < zb->ysize; y++) {
399  memset_l(pp, color, zb->xsize);
400  pp = (PIXEL *) ((char *) pp + zb->linesize);
401  }
402  }
403 }
404 
405 void
406 ZB_clear_viewport(ZBuffer * zb, int clear_z, ZPOINT z, int clear_color, PIXEL color,
407  int xmin, int ymin, int xsize, int ysize) {
408  int y;
409  PIXEL *pp;
410  ZPOINT *zz;
411 
412  nassertv(xmin >= 0 && xmin < zb->xsize &&
413  ymin >= 0 && ymin < zb->ysize &&
414  xmin + xsize >= 0 && xmin + xsize <= zb->xsize &&
415  ymin + ysize >= 0 && ymin + ysize <= zb->ysize);
416 
417  if (clear_z) {
418  zz = zb->zbuf + xmin + ymin * zb->xsize;
419  for (y = 0; y < ysize; ++y) {
420  memset(zz, 0, xsize * sizeof(ZPOINT));
421  zz += zb->xsize;
422  }
423  }
424  if (clear_color) {
425  pp = zb->pbuf + xmin + ymin * (zb->linesize / PSZB);
426  for (y = 0; y < ysize; ++y) {
427  memset_l(pp, color, xsize);
428  pp += zb->xsize;
429  }
430  }
431 }
432 
433 #define ZB_ST_FRAC_HIGH (1 << ZB_POINT_ST_FRAC_BITS)
434 #define ZB_ST_FRAC_MASK (ZB_ST_FRAC_HIGH - 1)
435 
436 #define LINEAR_FILTER_BITSIZE(c1, c2, f, bitsize) \
437  ((((c2) * (f)) >> bitsize) + (((c1) * ((1 << bitsize) - (f))) >> bitsize))
438 
439 #define LINEAR_FILTER(c1, c2, f) \
440  LINEAR_FILTER_BITSIZE(c1, c2, f, ZB_POINT_ST_FRAC_BITS)
441 
442 #define BILINEAR_FILTER(c1, c2, c3, c4, sf, tf) \
443  (LINEAR_FILTER(LINEAR_FILTER(c1, c2, sf), LINEAR_FILTER(c3, c4, sf), tf))
444 
445 // Grab the nearest texel from the base level. This is also
446 // implemented inline as ZB_LOOKUP_TEXTURE_NEAREST.
447 PIXEL
448 lookup_texture_nearest(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
449  return ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s, t);
450 }
451 
452 // Bilinear filter four texels in the base level.
453 PIXEL
454 lookup_texture_bilinear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
455  PIXEL p1, p2, p3, p4;
456  int sf, tf;
457  int r, g, b, a;
458 
459  p1 = ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH);
460  p2 = ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH);
461  sf = s & ZB_ST_FRAC_MASK;
462 
463  p3 = ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t);
464  p4 = ZB_LOOKUP_TEXTURE_NEAREST(texture_def, s, t);
465  tf = t & ZB_ST_FRAC_MASK;
466 
467  r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
468  g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
469  b = BILINEAR_FILTER(PIXEL_B(p1), PIXEL_B(p2), PIXEL_B(p3), PIXEL_B(p4), sf, tf);
470  a = BILINEAR_FILTER(PIXEL_A(p1), PIXEL_A(p2), PIXEL_A(p3), PIXEL_A(p4), sf, tf);
471 
472  return RGBA_TO_PIXEL(r, g, b, a);
473 }
474 
475 // Grab the nearest texel from the nearest mipmap level. This is also
476 // implemented inline as ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST.
477 PIXEL
478 lookup_texture_mipmap_nearest(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
479  return ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level);
480 }
481 
482 // Linear filter the two texels from the two nearest mipmap levels.
483 PIXEL
484 lookup_texture_mipmap_linear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
485  PIXEL p1, p2;
486  int r, g, b, a;
487 
488  p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level);
489  level = max((int)level - 1, 0);
490  p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level);
491 
492  unsigned int bitsize = level + ZB_POINT_ST_FRAC_BITS;
493  r = LINEAR_FILTER_BITSIZE(PIXEL_R(p2), PIXEL_R(p1), level_dx, bitsize);
494  g = LINEAR_FILTER_BITSIZE(PIXEL_G(p2), PIXEL_G(p1), level_dx, bitsize);
495  b = LINEAR_FILTER_BITSIZE(PIXEL_B(p2), PIXEL_B(p1), level_dx, bitsize);
496  a = LINEAR_FILTER_BITSIZE(PIXEL_A(p2), PIXEL_A(p1), level_dx, bitsize);
497 
498  return RGBA_TO_PIXEL(r, g, b, a);
499 }
500 
501 // Bilinear filter four texels in the nearest mipmap level.
502 PIXEL
503 lookup_texture_mipmap_bilinear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
504  PIXEL p1, p2, p3, p4;
505  int sf, tf;
506  int r, g, b, a;
507 
508  p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH, level);
509  p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH, level);
510  sf = (s >> level) & ZB_ST_FRAC_MASK;
511 
512  p3 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t, level);
513  p4 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level);
514  tf = (t >> level) & ZB_ST_FRAC_MASK;
515 
516  r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
517  g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
518  b = BILINEAR_FILTER(PIXEL_B(p1), PIXEL_B(p2), PIXEL_B(p3), PIXEL_B(p4), sf, tf);
519  a = BILINEAR_FILTER(PIXEL_A(p1), PIXEL_A(p2), PIXEL_A(p3), PIXEL_A(p4), sf, tf);
520 
521  return RGBA_TO_PIXEL(r, g, b, a);
522 }
523 
524 // Bilinear filter four texels in each of the nearest two mipmap
525 // levels, then linear filter them together.
526 PIXEL
527 lookup_texture_mipmap_trilinear(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
528  PIXEL p1a, p2a;
529 
530  {
531  PIXEL p1, p2, p3, p4;
532  int sf, tf;
533  int r, g, b, a;
534 
535  p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH, level);
536  p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH, level);
537  sf = (s >> level) & ZB_ST_FRAC_MASK;
538 
539  p3 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t, level);
540  p4 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level);
541  tf = (t >> level) & ZB_ST_FRAC_MASK;
542 
543  r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
544  g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
545  b = BILINEAR_FILTER(PIXEL_B(p1), PIXEL_B(p2), PIXEL_B(p3), PIXEL_B(p4), sf, tf);
546  a = BILINEAR_FILTER(PIXEL_A(p1), PIXEL_A(p2), PIXEL_A(p3), PIXEL_A(p4), sf, tf);
547  p1a = RGBA_TO_PIXEL(r, g, b, a);
548  }
549 
550  level = max((int)level - 1, 0);
551 
552  {
553  PIXEL p1, p2, p3, p4;
554  int sf, tf;
555  int r, g, b, a;
556 
557  p1 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t - ZB_ST_FRAC_HIGH, level);
558  p2 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t - ZB_ST_FRAC_HIGH, level);
559  sf = (s >> level) & ZB_ST_FRAC_MASK;
560 
561  p3 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s - ZB_ST_FRAC_HIGH, t, level);
562  p4 = ZB_LOOKUP_TEXTURE_MIPMAP_NEAREST(texture_def, s, t, level);
563  tf = (t >> level) & ZB_ST_FRAC_MASK;
564 
565  r = BILINEAR_FILTER(PIXEL_R(p1), PIXEL_R(p2), PIXEL_R(p3), PIXEL_R(p4), sf, tf);
566  g = BILINEAR_FILTER(PIXEL_G(p1), PIXEL_G(p2), PIXEL_G(p3), PIXEL_G(p4), sf, tf);
567  b = BILINEAR_FILTER(PIXEL_B(p1), PIXEL_B(p2), PIXEL_B(p3), PIXEL_B(p4), sf, tf);
568  a = BILINEAR_FILTER(PIXEL_A(p1), PIXEL_A(p2), PIXEL_A(p3), PIXEL_A(p4), sf, tf);
569  p2a = RGBA_TO_PIXEL(r, g, b, a);
570  }
571 
572  int r, g, b, a;
573  unsigned int bitsize = level + ZB_POINT_ST_FRAC_BITS;
574  r = LINEAR_FILTER_BITSIZE(PIXEL_R(p2a), PIXEL_R(p1a), level_dx, bitsize);
575  g = LINEAR_FILTER_BITSIZE(PIXEL_G(p2a), PIXEL_G(p1a), level_dx, bitsize);
576  b = LINEAR_FILTER_BITSIZE(PIXEL_B(p2a), PIXEL_B(p1a), level_dx, bitsize);
577  a = LINEAR_FILTER_BITSIZE(PIXEL_A(p2a), PIXEL_A(p1a), level_dx, bitsize);
578 
579  return RGBA_TO_PIXEL(r, g, b, a);
580 }
581 
582 
583 // Apply the wrap mode to s and t coordinates by calling the generic
584 // wrap mode function.
585 PIXEL
586 apply_wrap_general_minfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
587  s = (*texture_def->tex_wrap_u_func)(s, texture_def->s_max);
588  t = (*texture_def->tex_wrap_v_func)(t, texture_def->t_max);
589  return (*texture_def->tex_minfilter_func_impl)(texture_def, s, t, level, level_dx);
590 }
591 
592 PIXEL
593 apply_wrap_general_magfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
594  s = (*texture_def->tex_wrap_u_func)(s, texture_def->s_max);
595  t = (*texture_def->tex_wrap_v_func)(t, texture_def->t_max);
596  return (*texture_def->tex_magfilter_func_impl)(texture_def, s, t, level, level_dx);
597 }
598 
599 // Outside the legal range of s and t, return just the texture's
600 // border color.
601 PIXEL
602 apply_wrap_border_color_minfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
603  if (s < 0 || t < 0 || s > texture_def->s_max || t > texture_def->t_max) {
604  return texture_def->border_color;
605  }
606  return (*texture_def->tex_minfilter_func_impl)(texture_def, s, t, level, level_dx);
607 }
608 
609 PIXEL
610 apply_wrap_border_color_magfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
611  if (s < 0 || t < 0 || s > texture_def->s_max || t > texture_def->t_max) {
612  return texture_def->border_color;
613  }
614  return (*texture_def->tex_magfilter_func_impl)(texture_def, s, t, level, level_dx);
615 }
616 
617 // Outside the legal range of s and t, clamp s and t to the edge.
618 // This is also duplicated by texcoord_clamp(), but using these
619 // functions instead saves two additional function calls per pixel.
620 PIXEL
621 apply_wrap_clamp_minfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
622  s = min(max(s, 0), texture_def->s_max);
623  t = min(max(t, 0), texture_def->t_max);
624  return (*texture_def->tex_minfilter_func_impl)(texture_def, s, t, level, level_dx);
625 }
626 
627 PIXEL
628 apply_wrap_clamp_magfilter(ZTextureDef *texture_def, int s, int t, unsigned int level, unsigned int level_dx) {
629  s = min(max(s, 0), texture_def->s_max);
630  t = min(max(t, 0), texture_def->t_max);
631  return (*texture_def->tex_magfilter_func_impl)(texture_def, s, t, level, level_dx);
632 }
633 
634 int
635 texcoord_clamp(int coord, int max_coord) {
636  return min(max(coord, 0), max_coord);
637 }
638 
639 int
640 texcoord_repeat(int coord, int max_coord) {
641  return coord;
642 }
643 
644 int
645 texcoord_mirror(int coord, int max_coord) {
646  if ((coord & ((max_coord << 1) - 1)) > max_coord) {
647  coord = (max_coord << 1) - coord;
648  }
649  return coord;
650 }
651 
652 int
653 texcoord_mirror_once(int coord, int max_coord) {
654  if (coord > max_coord) {
655  coord = (max_coord << 1) - coord;
656  }
657  return max(coord, 0);
658 }