~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Tina4/src/tv/tv_zbuff_lowl.c

Version: ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /**@(#)
  2 low level drawing routines (usually called through tv_zbuff_draw_routines)
  3 **/
  4 #include <math.h>
  5 #include <values.h>
  6 #include <tina/sys.h>
  7 #include <tina/sysfuncs.h>
  8 #include <tina/math.h>
  9 #include <tina/mathfuncs.h>
 10 #include <tina/vision.h>
 11 #include <tina/visionfuncs.h>
 12 #include <tina/tv.h>
 13 #include <tina/tvfuncs.h>
 14 
 15 /* z-buffer draw point */
 16 Bool    tv_zbuff_point(Tv * tv, Ipos pos, int z)
 17 {
 18     Bool    flag = tv_zbuff(tv, pos, z);
 19 
 20     if (flag)
 21         tv_point(tv, pos);
 22     return (flag);
 23 }
 24 
 25 /* z-buffer draw segment of 3D-curve */
 26 void    tv_zbuff_seg3(Tv * tv, Vec3(*curve) (), void *data, double t1, double t2, Bool drawend)
 27 {
 28     Ipos    pos1 =
 29     {Ipos_id};
 30     Ipos    pos2 =
 31     {Ipos_id};
 32     int     z1, z2;
 33     int     dist;
 34 
 35     if (tv == NULL || curve == NULL)
 36         return;
 37 
 38     pos1 = tv_zbuff_proj3(tv, curve(data, t1), &z1);
 39     pos2 = tv_zbuff_proj3(tv, curve(data, t2), &z2);
 40     if ((dist = ipos_maxabs(pos1, pos2)) == 0)
 41     {
 42         if (drawend)
 43             (void) tv_zbuff_point(tv, pos1, z1);
 44     } else if (dist == 1)
 45     {
 46         (void) tv_zbuff_point(tv, pos1, z1);
 47         if (drawend)
 48             (void) tv_zbuff_point(tv, pos2, z2);
 49     } else
 50     {
 51         double  tm = 0.5 * (t1 + t2);
 52 
 53         tv_zbuff_seg3(tv, curve, data, t1, tm, false);
 54         tv_zbuff_seg3(tv, curve, data, tm, t2, true);
 55     }
 56 }
 57 
 58 /* z-buffer draw interpolated intensities in general polygon */
 59 void    tv_zbuff_interp_general_poly(Tv * tv, int n, Ipos * p, int *z, double *g)
 60 {
 61     int     i, j, k;
 62     int     ly = MAXINT, uy = -MAXINT;
 63 
 64     for (i = 0; i < n; ++i)
 65     {
 66         if (ipos_y(p[i]) < ly)
 67             ly = ipos_y(p[i]);
 68         if (ipos_y(p[i]) > uy)
 69             uy = ipos_y(p[i]);
 70     }
 71 
 72     for (i = ly; i <= uy; i++)
 73     {
 74         int     lx = MAXINT, ux = -MAXINT;
 75         double  lg = 0.0;
 76         double  ug = 0.0;
 77         double  lz = 0.0;
 78         double  uz = 0.0;
 79         double  dz = 0.0;
 80         double  dg = 0.0;
 81 
 82         for (j = 0; j < n; ++j)
 83         {
 84             k = (j + 1) % n;
 85             if (ipos_y(p[j]) == i && ipos_y(p[k]) == i)
 86             {
 87                 if (ipos_x(p[j]) < lx)
 88                 {
 89                     lx = ipos_x(p[j]);
 90                     lg = g[j];
 91                     lz = z[j];
 92                 }
 93                 if (ipos_x(p[k]) < lx)
 94                 {
 95                     lx = ipos_x(p[k]);
 96                     lg = g[k];
 97                     lz = z[k];
 98                 }
 99                 if (ipos_x(p[j]) > ux)
100                 {
101                     ux = ipos_x(p[j]);
102                     ug = g[j];
103                     uz = z[j];
104                 }
105                 if (ipos_x(p[k]) > ux)
106                 {
107                     ux = ipos_x(p[k]);
108                     ug = g[k];
109                     uz = z[k];
110                 }
111             } else if (ipos_y(p[j]) == i)
112             {
113                 if (ipos_x(p[j]) < lx)
114                 {
115                     lx = ipos_x(p[j]);
116                     lg = g[j];
117                     lz = z[j];
118                 }
119                 if (ipos_x(p[j]) > ux)
120                 {
121                     ux = ipos_x(p[j]);
122                     ug = g[j];
123                     uz = z[j];
124                 }
125             } else if (ipos_y(p[k]) == i)
126             {
127                 if (ipos_x(p[k]) < lx)
128                 {
129                     lx = ipos_x(p[k]);
130                     lg = g[k];
131                     lz = z[k];
132                 }
133                 if (ipos_x(p[k]) > ux)
134                 {
135                     ux = ipos_x(p[k]);
136                     ug = g[k];
137                     uz = z[k];
138                 }
139             } else if (BETWEEN(i, ipos_y(p[j]), ipos_y(p[k])))
140             {
141                 double  scale;
142                 double  x_val, g_val, z_val;
143                 int     x_round;
144 
145                 scale =
146                     (double) (i - ipos_y(p[j])) / (ipos_y(p[k]) - ipos_y(p[j]));
147                 x_val = ipos_x(p[j]) + (ipos_x(p[k]) - ipos_x(p[j])) * scale;
148                 g_val = g[j] + (g[k] - g[j]) * scale;
149                 z_val = z[j] + (z[k] - z[j]) * scale;
150 
151                 x_round = ROUND(x_val);
152 
153                 if (x_round < lx)
154                 {
155                     lx = x_round;
156                     lg = g_val;
157                     lz = z_val;
158                 }
159                 if (x_round > ux)
160                 {
161                     ux = x_round;
162                     ug = g_val;
163                     uz = z_val;
164                 }
165             }
166         }
167 
168         if (ux != lx)
169         {
170             dz = (uz - lz) / (ux - lx);
171             dg = (ug - lg) / (ux - lx);
172         } else
173             dz = dg = 0.0;
174         for (j = lx; j <= ux; j++, lz += dz, lg += dg)
175         {
176             tv_color_set(tv, tv->zbuff->color(lg));
177             (void) tv_zbuff_point(tv, ipos(j, i), ROUND(lz));
178         }
179     }
180 }
181 
182 /* z-buffer draw interpolated intensities in convex polygon */
183 void    tv_zbuff_interp_convex_poly(Tv * tv, int n, Ipos * p, int *z, double *g)
184 {
185     int     i, j, k;
186     int     ly = MAXINT, uy = -MAXINT;
187 
188     /* cheap test for visibility; better one required */
189     for (i = 0; i < n; ++i)
190         if (tv_ipos_within(tv, p[i]))
191             break;
192     if (i == n)                 /* polygon not within tv */
193         return;
194 
195     for (i = 0; i < n; ++i)
196     {
197         if (ipos_y(p[i]) < ly)
198             ly = ipos_y(p[i]);
199         if (ipos_y(p[i]) > uy)
200             uy = ipos_y(p[i]);
201     }
202 
203     for (i = ly; i <= uy; i++)
204     {
205         int     lx = MAXINT, ux = -MAXINT;
206         double  lg = 0.0;
207         double  ug = 0.0;
208         double  lz = 0.0;
209         double  uz = 0.0;
210         double  dz = 0.0;
211         double  dg = 0.0;
212 
213         for (j = 0; j < n; ++j)
214         {
215             k = (j + 1) % n;
216             if (ipos_y(p[j]) == i && ipos_y(p[k]) == i)
217             {
218                 if (ipos_x(p[j]) < lx)
219                 {
220                     lx = ipos_x(p[j]);
221                     lg = g[j];
222                     lz = z[j];
223                 }
224                 if (ipos_x(p[k]) < lx)
225                 {
226                     lx = ipos_x(p[k]);
227                     lg = g[k];
228                     lz = z[k];
229                 }
230                 if (ipos_x(p[j]) > ux)
231                 {
232                     ux = ipos_x(p[j]);
233                     ug = g[j];
234                     uz = z[j];
235                 }
236                 if (ipos_x(p[k]) > ux)
237                 {
238                     ux = ipos_x(p[k]);
239                     ug = g[k];
240                     uz = z[k];
241                 }
242             } else if (ipos_y(p[j]) == i)
243             {
244                 if (ipos_x(p[j]) < lx)
245                 {
246                     lx = ipos_x(p[j]);
247                     lg = g[j];
248                     lz = z[j];
249                 }
250                 if (ipos_x(p[j]) > ux)
251                 {
252                     ux = ipos_x(p[j]);
253                     ug = g[j];
254                     uz = z[j];
255                 }
256             } else if (ipos_y(p[k]) == i)
257             {
258                 if (ipos_x(p[k]) < lx)
259                 {
260                     lx = ipos_x(p[k]);
261                     lg = g[k];
262                     lz = z[k];
263                 }
264                 if (ipos_x(p[k]) > ux)
265                 {
266                     ux = ipos_x(p[k]);
267                     ug = g[k];
268                     uz = z[k];
269                 }
270             } else if (BETWEEN(i, ipos_y(p[j]), ipos_y(p[k])))
271             {
272                 double  scale;
273                 double  x_val, g_val, z_val;
274                 int     x_round;
275 
276                 scale = (double) (i - ipos_y(p[j])) / (ipos_y(p[k]) - ipos_y(p[j]));
277                 x_val = ipos_x(p[j]) + (ipos_x(p[k]) - ipos_x(p[j])) * scale;
278                 g_val = g[j] + (g[k] - g[j]) * scale;
279                 z_val = z[j] + (z[k] - z[j]) * scale;
280 
281                 x_round = ROUND(x_val);
282 
283                 if (x_round < lx)
284                 {
285                     lx = x_round;
286                     lg = g_val;
287                     lz = z_val;
288                 }
289                 if (x_round > ux)
290                 {
291                     ux = x_round;
292                     ug = g_val;
293                     uz = z_val;
294                 }
295             }
296         }
297 
298         if (ux != lx)
299         {
300             dz = (uz - lz) / (ux - lx);
301             dg = (ug - lg) / (ux - lx);
302         } else
303             dz = dg = 0.0;
304         for (j = lx; j <= ux; j++, lz += dz, lg += dg)
305         {
306             tv_color_set(tv, tv->zbuff->color(lg));
307             (void) tv_zbuff_point(tv, ipos(j, i), ROUND(lz));
308         }
309     }
310 }
311 
312 /* z-buffer draw interpolated image intensities in convex polygon */
313 void    tv_zbuff_image_convex_poly(Tv * tv, int n, Ipos * p, int *z, float *r, float *c, Imrect * im)
314 {
315     int     i, j, k;
316     int     ly = MAXINT, uy = -MAXINT;
317 
318     /* cheap test for visibility; better one required */
319     for (i = 0; i < n; ++i)
320         if (tv_ipos_within(tv, p[i]))
321             break;
322     if (i == n)                 /* polygon not within tv */
323         return;
324 
325     for (i = 0; i < n; ++i)
326     {
327         if (ipos_y(p[i]) < ly)
328             ly = ipos_y(p[i]);
329         if (ipos_y(p[i]) > uy)
330             uy = ipos_y(p[i]);
331     }
332 
333     for (i = ly; i <= uy; i++)
334     {
335         int     lx = MAXINT, ux = -MAXINT;
336         double  lr = 0.0;
337         double  ur = 0.0;
338         double  lc = 0.0;
339         double  uc = 0.0;
340         double  lz = 0.0;
341         double  uz = 0.0;
342         double  dz = 0.0;
343         double  dr = 0.0;
344         double  dc = 0.0;
345 
346         for (j = 0; j < n; ++j)
347         {
348             k = (j + 1) % n;
349             if (ipos_y(p[j]) == i && ipos_y(p[k]) == i)
350             {
351                 if (ipos_x(p[j]) < lx)
352                 {
353                     lx = ipos_x(p[j]);
354                     lr = r[j];
355                     lc = c[j];
356                     lz = z[j];
357                 }
358                 if (ipos_x(p[k]) < lx)
359                 {
360                     lx = ipos_x(p[k]);
361                     lr = r[k];
362                     lc = c[k];
363                     lz = z[k];
364                 }
365                 if (ipos_x(p[j]) > ux)
366                 {
367                     ux = ipos_x(p[j]);
368                     ur = r[j];
369                     uc = c[j];
370                     uz = z[j];
371                 }
372                 if (ipos_x(p[k]) > ux)
373                 {
374                     ux = ipos_x(p[k]);
375                     ur = r[k];
376                     uc = c[k];
377                     uz = z[k];
378                 }
379             } else if (ipos_y(p[j]) == i)
380             {
381                 if (ipos_x(p[j]) < lx)
382                 {
383                     lx = ipos_x(p[j]);
384                     lr = r[j];
385                     lc = c[j];
386                     lz = z[j];
387                 }
388                 if (ipos_x(p[j]) > ux)
389                 {
390                     ux = ipos_x(p[j]);
391                     ur = r[j];
392                     uc = c[j];
393                     uz = z[j];
394                 }
395             } else if (ipos_y(p[k]) == i)
396             {
397                 if (ipos_x(p[k]) < lx)
398                 {
399                     lx = ipos_x(p[k]);
400                     lr = r[k];
401                     lc = c[k];
402                     lz = z[k];
403                 }
404                 if (ipos_x(p[k]) > ux)
405                 {
406                     ux = ipos_x(p[k]);
407                     ur = r[k];
408                     uc = c[k];
409                     uz = z[k];
410                 }
411             } else if (BETWEEN(i, ipos_y(p[j]), ipos_y(p[k])))
412             {
413                 double  scale;
414                 double  x_val, r_val, c_val, z_val;
415                 int     x_round;
416 
417                 scale = (double) (i - ipos_y(p[j])) / (ipos_y(p[k]) - ipos_y(p[j]));
418                 x_val = ipos_x(p[j]) + (ipos_x(p[k]) - ipos_x(p[j])) * scale;
419                 r_val = r[j] + (r[k] - r[j]) * scale;
420                 c_val = c[j] + (c[k] - c[j]) * scale;
421                 z_val = z[j] + (z[k] - z[j]) * scale;
422 
423                 x_round = ROUND(x_val);
424 
425                 if (x_round < lx)
426                 {
427                     lx = x_round;
428                     lr = r_val;
429                     lc = c_val;
430                     lz = z_val;
431                 }
432                 if (x_round > ux)
433                 {
434                     ux = x_round;
435                     ur = r_val;
436                     uc = c_val;
437                     uz = z_val;
438                 }
439             }
440         }
441 
442         if (ux != lx)
443         {
444             dz = (uz - lz) / (ux - lx);
445             dr = (ur - lr) / (ux - lx);
446             dc = (uc - lc) / (ux - lx);
447         } else
448             dz = dr = dc = 0.0;
449         for (j = lx; j <= ux; j++, lz += dz, lr += dr, lc += dc)
450         {
451             int     gl = im_sub_pix(im, lr, lc);
452 
453             if (gl > 255)
454                 gl = 255;
455             if (gl < 0)
456                 gl = 0;
457             tv_color_set(tv, gl);
458             (void) tv_zbuff_point(tv, ipos(j, i), ROUND(lz));
459         }
460     }
461 }
462 
463 /* z-buffer draw interpolated intensities in convex quadrilateral */
464 void    tv_zbuff_interp_quad(Tv * tv, Ipos p00, Ipos p10, Ipos p01, Ipos p11, int z00, int z10, int z01, int z11, double g00, double g10, double g01, double g11)
465 {
466     Ipos    p[4] =
467     {
468         {Ipos_id},
469         {Ipos_id},
470         {Ipos_id},
471     {Ipos_id}};
472     int     z[4];
473     double  g[4];
474 
475     p[0] = p00;
476     p[1] = p10;
477     p[3] = p01;
478     p[2] = p11;
479     z[0] = z00;
480     z[1] = z10;
481     z[3] = z01;
482     z[2] = z11;
483     g[0] = g00;
484     g[1] = g10;
485     g[3] = g01;
486     g[2] = g11;
487 
488     tv_zbuff_interp_convex_poly(tv, 4, p, z, g);
489 }
490 
491 /* recursive patch drawing code */
492 /* was static - SMC 28/9/93 */
493 Tv_patch patch_make(double u1, double v1, double u2, double v2)
494 {
495     int     i, j;
496     Tv_patch patch =
497     {Tv_patch_id};
498 
499     patch.u[0] = u1;
500     patch.u[1] = 0.5 * (u1 + u2);
501     patch.u[2] = u2;
502     patch.v[0] = v1;
503     patch.v[1] = 0.5 * (v1 + v2);
504     patch.v[2] = v2;
505     for (i = 0; i < 3; i++)
506         for (j = 0; j < 3; j++)
507         {
508             patch.flag[i][j] = 0;
509             patch.pos[i][j] = ipos_zero();      /* SMC 28/9/93 */
510         }
511     return (patch);
512 }
513 
514 static Bool drawdiscontinuities = true;
515 void    tv_drawdiscontinuities_set(Tv * tv, Bool flag)
516 {
517     drawdiscontinuities = flag;
518 }
519 
520 /* recusively divide patch (up to limit ni calls) until patch edges and
521  * grey levels are well approximated (called by tv_zbuff_patch3) */
522 static void tv_zbuff_patch(Tv * tv, Vec3(*surf) (), Vec3(*normal) (), void *data, Tv_patch patch, int ni)
523 {
524     Ipos   *pos[3];
525     double  u[3], v[3];
526     double *g[3];
527     int    *z[3], *flag[3];
528     Bool    splitu = true, splitv = true, back = tv->zbuff->backdraw;
529     double  egray = 0.01;
530     int     epos = 2, i, j;
531     int     d1, d2, d3, d4;
532 
533     for (i = 0; i < 3; i++)
534     {
535         pos[i] = &patch.pos[i][0];
536         u[i] = patch.u[i];
537         v[i] = patch.v[i];
538         flag[i] = &patch.flag[i][0];
539         z[i] = &patch.z[i][0];
540         g[i] = &patch.g[i][0];
541     }
542 
543     if (flag[0][0] &&
544         !(IN_TV(tv, pos[0][0]) || IN_TV(tv, pos[2][0]) ||
545           IN_TV(tv, pos[0][2]) || IN_TV(tv, pos[2][2])))
546         return;
547 
548     for (i = 0; i < 3; i++)
549         for (j = 0; j < 3; j++)
550             if (!flag[i][j])
551             {
552                 Vec3    x =
553                 {Vec3_id};
554                 Vec3    n =
555                 {Vec3_id};
556 
557                 x = surf(data, u[i], v[j]);
558                 if (normal == NULL)
559                     n = interp_normal(surf, data, u[i], v[j], x);
560                 else
561                     n = normal(data, u[i], v[j]);
562                 pos[i][j] = tv_zbuff_proj3(tv, x, &z[i][j]);
563                 g[i][j] = tv->zbuff->shade(tv, n, x);
564             }
565     /** facing away **/
566     if (!back && g[0][0] < 0 && g[0][1] < 0 && g[0][2] < 0 &&
567         g[1][0] < 0 && g[1][1] < 0 && g[1][2] < 0 &&
568         g[2][0] < 0 && g[2][1] < 0 && g[2][2])
569         return;
570 
571     for (i = 0; i < 3; i++)
572         for (j = 0; j < 3; j++)
573             g[i][j] = fabs(g[i][j]);
574 
575 
576     d1 = ipos_manhattan(pos[0][0], pos[2][0]);
577     d2 = ipos_manhattan(pos[0][2], pos[2][2]);
578     d3 = ipos_manhattan(pos[0][0], pos[0][2]);
579     d4 = ipos_manhattan(pos[2][0], pos[2][2]);
580     if (d1 < 4 && d2 < 4)
581         splitu = false;
582     if (d3 < 4 && d4 < 4)
583         splitv = false;
584 
585     if (splitu &&
586         ipos_maxabs(pos[1][0], ipos_midpoint(pos[0][0], pos[2][0])) < epos &&
587         fabs(g[1][0] - 0.5 * (g[0][0] + g[2][0])) < egray &&
588         ipos_maxabs(pos[1][2], ipos_midpoint(pos[0][2], pos[2][2])) < epos &&
589         fabs(g[1][2] - 0.5 * (g[0][2] + g[2][2])) < egray)
590         splitu = false;
591 
592     if (splitv &&
593         ipos_maxabs(pos[0][1], ipos_midpoint(pos[0][0], pos[0][2])) < epos &&
594         fabs(g[0][1] - 0.5 * (g[0][0] + g[0][2])) < egray &&
595         ipos_maxabs(pos[2][1], ipos_midpoint(pos[2][0], pos[2][2])) < epos &&
596         fabs(g[2][1] - 0.5 * (g[2][0] + g[2][2])) < egray)
597         splitv = false;
598 
599     if (ni <= 0)
600     {
601         if (drawdiscontinuities == false)
602             return;
603         else
604             splitu = splitv = false;
605     }
606     if (splitu && splitv)
607     {
608         for (i = 0; i < 2; i++)
609             for (j = 0; j < 2; j++)
610             {
611                 Tv_patch q = {Tv_patch_id};
612                 int     oi, oj;
613 
614                 q = patch_make(u[i], v[j], u[i + 1], v[j + 1]);
615                 for (oi = 0; oi < 2; oi++)
616                 {
617                     int     oi2 = 2 * oi;
618 
619                     for (oj = 0; oj < 2; oj++)
620                     {
621                         int     oj2 = 2 * oj;
622 
623                         q.flag[oi2][oj2] = 1;
624                         q.pos[oi2][oj2] = pos[i + oi][j + oj];
625                         q.z[oi2][oj2] = z[i + oi][j + oj];
626                         q.g[oi2][oj2] = g[i + oi][j + oj];
627                     }
628                 }
629                 tv_zbuff_patch(tv, surf, normal, data, q, ni - 1);
630             }
631     } else if (splitu)
632     {
633         for (i = 0; i < 2; i++)
634         {
635             Tv_patch q =
636             {Tv_patch_id};
637             int     oi, oj;
638 
639             q = patch_make(u[i], v[0], u[i + 1], v[2]);
640             for (oi = 0; oi < 2; oi++)
641             {
642                 int     oi2 = 2 * oi;
643 
644                 for (oj = 0; oj < 3; oj++)
645                 {
646                     q.flag[oi2][oj] = 1;
647                     q.pos[oi2][oj] = pos[i + oi][oj];
648                     q.z[oi2][oj] = z[i + oi][oj];
649                     q.g[oi2][oj] = g[i + oi][oj];
650                 }
651             }
652             tv_zbuff_patch(tv, surf, normal, data, q, ni - 1);
653         }
654     } else if (splitv)
655     {
656         for (j = 0; j < 2; j++)
657         {
658             Tv_patch q =
659             {Tv_patch_id};
660             int     oi, oj;
661 
662             q = patch_make(u[0], v[j], u[2], v[j + 1]);
663             for (oi = 0; oi < 3; oi++)
664             {
665                 for (oj = 0; oj < 2; oj++)
666                 {
667                     int     oj2 = 2 * oj;
668 
669                     q.flag[oi][oj2] = 1;
670                     q.pos[oi][oj2] = pos[oi][j + oj];
671                     q.z[oi][oj2] = z[oi][j + oj];
672                     q.g[oi][oj2] = g[oi][j + oj];
673                 }
674             }
675             tv_zbuff_patch(tv, surf, normal, data, q, ni - 1);
676         }
677     } else
678     {
679         for (i = 0; i < 2; i++)
680             for (j = 0; j < 2; j++)
681                 tv_zbuff_interp_quad(tv,
682                                      pos[i][j], pos[i + 1][j], pos[i][j + 1], pos[i + 1][j + 1],
683                    z[i][j], z[i + 1][j], z[i][j + 1], z[i + 1][j + 1],
684                   g[i][j], g[i + 1][j], g[i][j + 1], g[i + 1][j + 1]);
685     }
686 }
687 
688 /* z-buffer draw  patch (up to limit ni sub-divisions) surf(u, v)
689  * returns surface point norm(u, v) returns surface normal */
690 void    tv_zbuff_patch3(Tv * tv, Vec3(*surf) (), Vec3(*normal) (), void *data, double u1, double v1, double u2, double v2, int ni)
691 {
692     Tv_patch patch =
693     {Tv_patch_id};
694 
695     if (tv == NULL || surf == NULL)
696         return;
697     patch = patch_make(u1, v1, u2, v2);
698     tv_zbuff_patch(tv, surf, normal, data, patch, ni);
699 }
700 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.