ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/tonemap.c
(Generate patch)

Comparing ray/src/common/tonemap.c (file contents):
Revision 3.1 by greg, Tue Apr 15 16:53:01 1997 UTC vs.
Revision 3.8 by gwlarson, Mon Aug 17 17:58:47 1998 UTC

# Line 1 | Line 1
1 < /* Copyright (c) 1997 Regents of the University of California */
1 > /* Copyright (c) 1998 Silicon Graphics, Inc. */
2  
3   #ifndef lint
4 < static char SCCSid[] = "$SunId$ LBL";
4 > static char SCCSid[] = "$SunId$ SGI";
5   #endif
6  
7   /*
# Line 18 | Line 18 | static char SCCSid[] = "$SunId$ LBL";
18  
19   struct tmStruct *tmTop = NULL;          /* current tone mapping stack */
20  
21 +                                        /* our list of conversion packages */
22 + struct tmPackage        *tmPkg[TM_MAXPKG];
23 + int     tmNumPkgs = 0;                  /* number of registered packages */
24  
25 + int     tmLastError;                    /* last error incurred by library */
26 + char    *tmLastFunction;                /* error-generating function name */
27 +
28 +
29   int
30   tmErrorReturn(func, err)                /* error return (with message) */
31   char    *func;
32   int     err;
33   {
34 <        if (tmTop != NULL && tmTop->flags & TM_F_NOERRS)
34 >        tmLastFunction = func;
35 >        tmLastError = err;
36 >        if (tmTop != NULL && tmTop->flags & TM_F_NOSTDERR)
37                  return(err);
38          fputs(func, stderr);
39          fputs(": ", stderr);
# Line 62 | Line 71 | double gamval;
71                  tmnew->clf[GRN] = cmat[1][1];
72                  tmnew->clf[BLU] = cmat[1][2];
73          }
65        tmnew->clfb[RED] = 256.*tmnew->clf[RED] + .5;
66        tmnew->clfb[GRN] = 256.*tmnew->clf[GRN] + .5;
67        tmnew->clfb[BLU] = 256.*tmnew->clf[BLU] + .5;
68        tmnew->clfb[EXP] = COLXS;
74                                                  /* set gamma value */
75          if (gamval < MINGAM)
76                  tmnew->mongam = DEFGAM;
77          else
78                  tmnew->mongam = gamval;
79 <        for (i = TM_GAMTSZ; i--; )
80 <                tmnew->gamb[i] = 256.*pow((i+.5)/TM_GAMTSZ, 1./tmnew->mongam);
79 >                                                /* set color divisors */
80 >        for (i = 0; i < 3; i++)
81 >                tmnew->cdiv[i] = 256.*pow(tmnew->clf[i], 1./tmnew->mongam);
82 >
83                                                  /* set input transform */
84          tmnew->inppri = tmnew->monpri;
85          tmnew->cmat[0][0] = tmnew->cmat[1][1] = tmnew->cmat[2][2] =
86                          tmnew->inpsf = WHTEFFICACY;
80        tmnew->inpsfb = TM_BRTSCALE*log(tmnew->inpsf) + .5;
87          tmnew->cmat[0][1] = tmnew->cmat[0][2] = tmnew->cmat[1][0] =
88          tmnew->cmat[1][2] = tmnew->cmat[2][0] = tmnew->cmat[2][1] = 0.;
89 <        tmnew->flags &= ~TM_F_NEEDMAT;
84 <        tmnew->brmin = tmnew->brmax = 0;
89 >        tmnew->hbrmin = tmnew->hbrmax = 0;
90          tmnew->histo = NULL;
91 +        tmnew->mbrmin = tmnew->mbrmax = 0;
92          tmnew->lumap = NULL;
93 <        tmnew->tmprev = NULL;
94 <
95 <        tmnew->flags |= TM_F_INITED;
96 <                                                /* make it current */
93 >                                                /* zero private data */
94 >        for (i = TM_MAXPKG; i--; )
95 >                tmnew->pd[i] = NULL;
96 >                                                /* make tmnew current */
97          tmnew->tmprev = tmTop;
98          return(tmTop = tmnew);
99   }
# Line 110 | Line 116 | double sf;
116                  returnOK;
117          tmTop->inppri = pri;                    /* let's set it */
118          tmTop->inpsf = sf;
113        tmTop->inpsfb = TM_BRTSCALE*log(sf) + (sf>=1. ? .5 : -.5);
119  
120          if (tmTop->flags & TM_F_BW) {           /* color doesn't matter */
121                  tmTop->monpri = tmTop->inppri;          /* eliminate xform */
122                  if (tmTop->inppri == TM_XYZPRIM) {
123                          tmTop->clf[CIEX] = tmTop->clf[CIEZ] = 0.;
124                          tmTop->clf[CIEY] = 1.;
120                        tmTop->clfb[CIEX] = tmTop->clfb[CIEZ] = 0;
121                        tmTop->clfb[CIEY] = 255;
125                  } else {
126                          comprgb2xyzmat(tmTop->cmat, tmTop->monpri);
127                          tmTop->clf[RED] = tmTop->cmat[1][0];
# Line 142 | Line 145 | double sf;
145          for (i = 0; i < 3; i++)
146                  for (j = 0; j < 3; j++)
147                          tmTop->cmat[i][j] *= tmTop->inpsf;
148 <        if (tmTop->inppri != tmTop->monpri)
149 <                tmTop->flags |= TM_F_NEEDMAT;
150 <        else
151 <                tmTop->flags &= ~TM_F_NEEDMAT;
148 >                                                /* set color divisors */
149 >        for (i = 0; i < 3; i++)
150 >                if (tmTop->clf[i] > .001)
151 >                        tmTop->cdiv[i] =
152 >                                256.*pow(tmTop->clf[i], 1./tmTop->mongam);
153 >                else
154 >                        tmTop->cdiv[i] = 1;
155 >                                                /* notify packages */
156 >        for (i = tmNumPkgs; i--; )
157 >                if (tmTop->pd[i] != NULL && tmPkg[i]->NewSpace != NULL)
158 >                        (*tmPkg[i]->NewSpace)(tmTop);
159          returnOK;
160   }
161  
# Line 155 | Line 165 | tmClearHisto()                 /* clear current histogram */
165   {
166          if (tmTop == NULL || tmTop->histo == NULL)
167                  return;
168 <        free((char *)tmTop->histo);
168 >        free((MEM_PTR)tmTop->histo);
169          tmTop->histo = NULL;
170   }
171  
# Line 168 | Line 178 | COLOR  *scan;
178   int     len;
179   {
180          static char     funcName[] = "tmCvColors";
181 +        static COLOR    csmall = {1e-6, 1e-6, 1e-6};
182          COLOR   cmon;
183          double  lum, slum;
184          register double d;
# Line 175 | Line 186 | int    len;
186  
187          if (tmTop == NULL)
188                  returnErr(TM_E_TMINVAL);
189 <        if (ls == NULL | scan == NULL | len <= 0)
189 >        if (ls == NULL | scan == NULL | len < 0)
190                  returnErr(TM_E_ILLEGAL);
191          for (i = len; i--; ) {
192 <                if (tmTop->flags & TM_F_NEEDMAT)        /* get monitor RGB */
192 >                if (tmNeedMatrix(tmTop))                /* get monitor RGB */
193                          colortrans(cmon, tmTop->cmat, scan[i]);
194                  else {
195                          cmon[RED] = tmTop->inpsf*scan[i][RED];
# Line 190 | Line 201 | int    len;
201                          tmTop->clf[GRN]*cmon[GRN] +
202                          tmTop->clf[BLU]*cmon[BLU] ;
203                                                          /* check range */
204 <                if (clipgamut(cmon, lum, CGAMUT_LOWER, cblack, cwhite))
204 >                if (clipgamut(cmon, lum, CGAMUT_LOWER, csmall, cwhite))
205                          lum =   tmTop->clf[RED]*cmon[RED] +
206                                  tmTop->clf[GRN]*cmon[GRN] +
207                                  tmTop->clf[BLU]*cmon[BLU] ;
# Line 223 | Line 234 | int    len;
234                          cmon[RED] = cmon[GRN] = cmon[BLU] = lum;
235                  }
236                  d = tmTop->clf[RED]*cmon[RED]/lum;
237 <                /* cs[3*i  ] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */
238 <                cs[3*i  ] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)];
237 >                cs[3*i  ] = d>=.999 ? 255 :
238 >                                (int)(256.*pow(d, 1./tmTop->mongam));
239                  d = tmTop->clf[GRN]*cmon[GRN]/lum;
240 <                /* cs[3*i+1] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */
241 <                cs[3*i+1] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)];
240 >                cs[3*i+1] = d>=.999 ? 255 :
241 >                                (int)(256.*pow(d, 1./tmTop->mongam));
242                  d = tmTop->clf[BLU]*cmon[BLU]/lum;
243 <                /* cs[3*i+2] = d>.999 ? 255 : 256.*pow(d, 1./tmTop->mongam); */
244 <                cs[3*i+2] = d>.999 ? 255 : tmTop->gamb[(int)(d*TM_GAMTSZ)];
243 >                cs[3*i+2] = d>=.999 ? 255 :
244 >                                (int)(256.*pow(d, 1./tmTop->mongam));
245          }
246          returnOK;
247   }
# Line 243 | Line 254 | int    len;
254   int     wt;
255   {
256          static char     funcName[] = "tmAddHisto";
257 <        int     sum, oldorig, oldlen, horig, hlen;
257 >        int     oldorig, oldlen, horig, hlen;
258          register int    i, j;
259  
249        if (len <= 0)
250                returnErr(TM_E_ILLEGAL);
260          if (tmTop == NULL)
261                  returnErr(TM_E_TMINVAL);
262 +        if (len < 0)
263 +                returnErr(TM_E_ILLEGAL);
264 +        if (len == 0)
265 +                returnOK;
266                                                  /* first, grow limits */
267          if (tmTop->histo == NULL) {
268                  for (i = len; i-- && ls[i] < MINBRT; )
269                          ;
270                  if (i < 0)
271                          returnOK;
272 <                tmTop->brmin = tmTop->brmax = ls[i];
272 >                tmTop->hbrmin = tmTop->hbrmax = ls[i];
273                  oldlen = 0;
274          } else {
275 <                oldorig = (tmTop->brmin-MINBRT)/HISTEP;
276 <                oldlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - oldorig;
275 >                oldorig = (tmTop->hbrmin-MINBRT)/HISTEP;
276 >                oldlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - oldorig;
277          }
278          for (i = len; i--; ) {
279                  if ((j = ls[i]) < MINBRT)
280                          continue;
281 <                if (j < tmTop->brmin)
282 <                        tmTop->brmin = j;
283 <                else if (j > tmTop->brmax)
284 <                        tmTop->brmax = j;
281 >                if (j < tmTop->hbrmin)
282 >                        tmTop->hbrmin = j;
283 >                else if (j > tmTop->hbrmax)
284 >                        tmTop->hbrmax = j;
285          }
286 <        horig = (tmTop->brmin-MINBRT)/HISTEP;
287 <        hlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - horig;
286 >        horig = (tmTop->hbrmin-MINBRT)/HISTEP;
287 >        hlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - horig;
288          if (hlen > oldlen) {                    /* (re)allocate histogram */
289                  register int    *newhist = (int *)calloc(hlen, sizeof(int));
290                  if (newhist == NULL)
291                          returnErr(TM_E_NOMEM);
292                  if (oldlen) {                   /* copy and free old */
293 <                        for (i = oldlen, j = i+oldorig-horig; i--; )
294 <                                newhist[--j] = tmTop->histo[i];
295 <                        free((char *)tmTop->histo);
293 >                        for (i = oldlen, j = i+oldorig-horig; i; )
294 >                                newhist[--j] = tmTop->histo[--i];
295 >                        free((MEM_PTR)tmTop->histo);
296                  }
297                  tmTop->histo = newhist;
285                if (tmTop->lumap != NULL) {     /* invalid tone map */
286                        free((char *)tmTop->lumap);
287                        tmTop->lumap = NULL;
288                }
298          }
299          if (wt == 0)
300                  returnOK;
# Line 343 | Line 352 | double Ldmax;
352          Ldmin = Ldmax/Lddyn;
353          logLddyn = log(Lddyn);
354          Ldavg = sqrt(Ldmax*Ldmin);
355 <        i = (tmTop->brmin-MINBRT)/HISTEP;
355 >        i = (tmTop->hbrmin-MINBRT)/HISTEP;
356          brt0 = MINBRT + HISTEP/2 + i*HISTEP;
357 <        histlen = (tmTop->brmax-MINBRT)/HISTEP + 1 - i;
349 <                                        /* allocate temporary tables */
350 <        histo = (int *)malloc(histlen*sizeof(int));
351 <        cumf = (float *)malloc((histlen+1)*sizeof(float));
352 <        if (histo == NULL | cumf == NULL)
353 <                returnErr(TM_E_NOMEM);
357 >        histlen = (tmTop->hbrmax-MINBRT)/HISTEP + 1 - i;
358                                          /* histogram total and mean */
359          histot = 0; sum = 0;
360          j = brt0 + histlen*HISTEP;
361          for (i = histlen; i--; ) {
362 <                histot += (histo[i] = tmTop->histo[i]);
363 <                sum += (j -= HISTEP) * histo[i];
362 >                histot += tmTop->histo[i];
363 >                sum += (j -= HISTEP) * tmTop->histo[i];
364          }
365          threshold = histot*.025 + .5;
366          if (threshold < 4)
367                  returnErr(TM_E_TMFAIL);
368          Lwavg = tmLuminance( (double)sum / histot );
369 <        do {                            /* iterate to solution */
370 <                sum = 0;                /* compute cumulative probability */
371 <                for (i = 0; i < histlen; i++) {
372 <                        cumf[i] = (double)sum/histot;
373 <                        sum += histo[i];
374 <                }
375 <                cumf[i] = 1.;
376 <                Tr = histot * (double)(tmTop->brmax - tmTop->brmin) /
369 >        if (!(tmTop->flags & TM_F_LINEAR)) {    /* clamp histogram */
370 >                histo = (int *)malloc(histlen*sizeof(int));
371 >                cumf = (float *)malloc((histlen+1)*sizeof(float));
372 >                if (histo == NULL | cumf == NULL)
373 >                        returnErr(TM_E_NOMEM);
374 >                for (i = histlen; i--; )        /* make malleable copy */
375 >                        histo[i] = tmTop->histo[i];
376 >                do {                            /* iterate to solution */
377 >                        sum = 0;                /* cumulative probability */
378 >                        for (i = 0; i < histlen; i++) {
379 >                                cumf[i] = (double)sum/histot;
380 >                                sum += histo[i];
381 >                        }
382 >                        cumf[i] = 1.;
383 >                        Tr = histot * (double)(tmTop->hbrmax - tmTop->hbrmin) /
384                                  ((double)histlen*TM_BRTSCALE) / logLddyn;
385 <                ceiling = Tr + 1.;
386 <                trimmings = 0;                  /* clip to envelope */
387 <                for (i = histlen; i--; ) {
388 <                        if (tmTop->flags & TM_F_HCONTR) {
389 <                                Lw = tmLuminance(brt0 + i*HISTEP);
390 <                                Ld = Ldmin * exp( logLddyn *
385 >                        ceiling = Tr + 1.;
386 >                        trimmings = 0;                  /* clip to envelope */
387 >                        for (i = histlen; i--; ) {
388 >                                if (tmTop->flags & TM_F_HCONTR) {
389 >                                        Lw = tmLuminance(brt0 + i*HISTEP);
390 >                                        Ld = Ldmin * exp( logLddyn *
391                                                  .5*(cumf[i]+cumf[i+1]) );
392 <                                ceiling = Tr * (htcontrs(Ld) * Lw) /
392 >                                        ceiling = Tr * (htcontrs(Ld) * Lw) /
393                                                  (htcontrs(Lw) * Ld) + 1.;
394 +                                }
395 +                                if (histo[i] > ceiling) {
396 +                                        trimmings += histo[i] - ceiling;
397 +                                        histo[i] = ceiling;
398 +                                }
399                          }
400 <                        if (histo[i] > ceiling) {
401 <                                trimmings += histo[i] - ceiling;
386 <                                histo[i] = ceiling;
387 <                        }
388 <                }
389 <        } while ((histot -= trimmings) > threshold && trimmings > threshold);
390 <
391 <        if (tmTop->lumap == NULL) {             /* allocate luminance map */
392 <                tmTop->lumap = (unsigned short *)malloc(
393 <                        (tmTop->brmax-tmTop->brmin+1)*sizeof(unsigned short) );
394 <                if (tmTop->lumap == NULL)
395 <                        returnErr(TM_E_NOMEM);
400 >                } while ((histot -= trimmings) > threshold &&
401 >                                                trimmings > threshold);
402          }
403 +                                                /* allocate luminance map */
404 +        if (tmTop->lumap != NULL)
405 +                free((MEM_PTR)tmTop->lumap);
406 +        tmTop->mbrmin = tmTop->hbrmin;
407 +        tmTop->mbrmax = tmTop->hbrmax;
408 +        tmTop->lumap = (unsigned short *)malloc(
409 +                (tmTop->mbrmax-tmTop->mbrmin+1)*sizeof(unsigned short) );
410 +        if (tmTop->lumap == NULL)
411 +                returnErr(TM_E_NOMEM);
412          if (tmTop->flags & TM_F_LINEAR || histot <= threshold) {
413                                                  /* linear tone mapping */
414                  if (tmTop->flags & TM_F_HCONTR)
# Line 401 | Line 416 | double Ldmax;
416                  else
417                          d = Ldavg / Lwavg;
418                  d = log(d/Ldmax);
419 <                for (i = tmTop->brmax-tmTop->brmin+1; i--; )
419 >                for (i = tmTop->mbrmax-tmTop->mbrmin+1; i--; )
420                          tmTop->lumap[i] = 256. * exp(
421 <                                ( d + (tmTop->brmin+i)/(double)TM_BRTSCALE )
421 >                                ( d + (tmTop->mbrmin+i)/(double)TM_BRTSCALE )
422                                  / gamval );
423          } else {
424                                                  /* histogram adjustment */
425 <                for (i = tmTop->brmax-tmTop->brmin+1; i--; ) {
426 <                        j = d = (double)i/(tmTop->brmax-tmTop->brmin)*histlen;
425 >                for (i = tmTop->mbrmax-tmTop->mbrmin+1; i--; ) {
426 >                        j = d = (double)i/(tmTop->mbrmax-tmTop->mbrmin)*histlen;
427                          d -= (double)j;
428                          Ld = Ldmin*exp(logLddyn*((1.-d)*cumf[j]+d*cumf[j+1]));
429                          d = (Ld - Ldmin)/(Ldmax - Ldmin);
430                          tmTop->lumap[i] = 256.*pow(d, 1./gamval);
431                  }
432          }
433 <        free((char *)histo);
434 <        free((char *)cumf);
433 >        if (!(tmTop->flags & TM_F_LINEAR)) {
434 >                free((MEM_PTR)histo);
435 >                free((MEM_PTR)cumf);
436 >        }
437          returnOK;
438   }
439  
# Line 429 | Line 446 | register BYTE  *cs;
446   int     len;
447   {
448          static char     funcName[] = "tmMapPixels";
449 <        int     rdiv, gdiv, bdiv;
433 <        register int    li, pv;
449 >        register int4   li, pv;
450  
451          if (tmTop == NULL || tmTop->lumap == NULL)
452                  returnErr(TM_E_TMINVAL);
453 <        if (ps == NULL | ls == NULL | len <= 0)
453 >        if (ps == NULL | ls == NULL | len < 0)
454                  returnErr(TM_E_ILLEGAL);
439        rdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[RED])>>8];
440        gdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[GRN])>>8];
441        bdiv = tmTop->gamb[((int4)TM_GAMTSZ*tmTop->clfb[BLU])>>8];
455          while (len--) {
456 <                if ((li = *ls++) < tmTop->brmin)
457 <                        li = tmTop->brmin;
458 <                else if (li > tmTop->brmax)
459 <                        li = tmTop->brmax;
460 <                li = tmTop->lumap[li - tmTop->brmin];
456 >                if ((li = *ls++) < tmTop->mbrmin)
457 >                        li = tmTop->mbrmin;
458 >                else if (li > tmTop->mbrmax)
459 >                        li = tmTop->mbrmax;
460 >                li = tmTop->lumap[li - tmTop->mbrmin];
461                  if (cs == TM_NOCHROM)
462                          *ps++ = li>255 ? 255 : li;
463                  else {
464 <                        pv = *cs++ * li / rdiv;
464 >                        pv = *cs++ * li / tmTop->cdiv[RED];
465                          *ps++ = pv>255 ? 255 : pv;
466 <                        pv = *cs++ * li / gdiv;
466 >                        pv = *cs++ * li / tmTop->cdiv[GRN];
467                          *ps++ = pv>255 ? 255 : pv;
468 <                        pv = *cs++ * li / bdiv;
468 >                        pv = *cs++ * li / tmTop->cdiv[BLU];
469                          *ps++ = pv>255 ? 255 : pv;
470                  }
471          }
# Line 494 | Line 507 | register struct tmStruct       *tms;
507   }
508  
509  
510 + struct tmStruct *
511 + tmDup()                         /* duplicate top tone mapping */
512 + {
513 +        int     len;
514 +        register int    i;
515 +        register struct tmStruct        *tmnew;
516 +
517 +        if (tmTop == NULL)              /* anything to duplicate? */
518 +                return(NULL);
519 +        tmnew = (struct tmStruct *)malloc(sizeof(struct tmStruct));
520 +        if (tmnew == NULL)
521 +                return(NULL);
522 +        *tmnew = *tmTop;                /* copy everything */
523 +        if (tmnew->histo != NULL) {     /* duplicate histogram */
524 +                len = (tmnew->hbrmax-MINBRT)/HISTEP + 1 -
525 +                                (tmnew->hbrmin-MINBRT)/HISTEP;
526 +                tmnew->histo = (int *)malloc(len*sizeof(int));
527 +                if (tmnew->histo != NULL)
528 +                        for (i = len; i--; )
529 +                                tmnew->histo[i] = tmTop->histo[i];
530 +        }
531 +        if (tmnew->lumap != NULL) {     /* duplicate luminance mapping */
532 +                len = tmnew->mbrmax-tmnew->mbrmin+1;
533 +                tmnew->lumap = (unsigned short *)malloc(
534 +                                                len*sizeof(unsigned short) );
535 +                if (tmnew->lumap != NULL)
536 +                        for (i = len; i--; )
537 +                                tmnew->lumap[i] = tmTop->lumap[i];
538 +        }
539 +                                        /* clear package data */
540 +        for (i = tmNumPkgs; i--; )
541 +                tmnew->pd[i] = NULL;
542 +        tmnew->tmprev = tmTop;          /* make copy current */
543 +        return(tmTop = tmnew);
544 + }
545 +
546 +
547   int
548   tmPush(tms)                     /* push tone mapping on top of stack */
549   register struct tmStruct        *tms;
550   {
551          static char     funcName[] = "tmPush";
552                                          /* check validity */
553 <        if (tms == NULL || !(tms->flags & TM_F_INITED))
553 >        if (tms == NULL)
554                  returnErr(TM_E_ILLEGAL);
555          if (tms == tmTop)               /* check necessity */
556                  returnOK;
# Line 517 | Line 567 | void
567   tmDone(tms)                     /* done with tone mapping -- destroy it */
568   register struct tmStruct        *tms;
569   {
570 +        register int    i;
571                                          /* NULL arg. is equiv. to tmTop */
572          if (tms == NULL && (tms = tmTop) == NULL)
573                  return;
# Line 524 | Line 575 | register struct tmStruct       *tms;
575          (void)tmPull(tms);
576                                          /* free tables */
577          if (tms->histo != NULL)
578 <                free((char *)tms->histo);
578 >                free((MEM_PTR)tms->histo);
579          if (tms->lumap != NULL)
580 <                free((char *)tms->lumap);
581 <        tms->flags = 0;
582 <        free((char *)tms);              /* free basic structure */
580 >                free((MEM_PTR)tms->lumap);
581 >                                        /* free private data */
582 >        for (i = tmNumPkgs; i--; )
583 >                if (tms->pd[i] != NULL)
584 >                        (*tmPkg[i]->Free)(tms->pd[i]);
585 >        free((MEM_PTR)tms);             /* free basic structure */
586   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines