/* fut_free_otbl_p This function is passed a fut_otbl_t pointer and handle. If the ref count is zero, the table and the fut_otbl_t is freed. Otherwise the ref count is decremented and the lock state of the fut_otbl_t is returned to it's state on entry. */ static void fut_free_otbl_p ( fut_otbl_p otblPtr, KpHandle_t otblHdl) { fut_otbl_p otbl = otblPtr; if (otblHdl == NULL) { return; } if (otbl == NULL) { /* otbl is unlocked on entry */ otbl = lockBuffer(otblHdl); } if (IS_OTBL(otbl)) { if (otbl->ref == 0) { /* last reference being freed */ freeBuffer(otbl->tblHandle); otbl->magic = 0; freeBufferPtr ((KpGenericPtr_t)otbl); } else { if (otbl->ref > 0) { /* still other references */ otbl->ref--; /* leave in original lock state */ if (otblPtr == NULL) { unlockBuffer(otblHdl); } } } } }
/* fut_size_otbl returns the size in bytes of an output table */ static KpInt32_t fut_size_otbl ( fut_otbl_p otbl) { if ( ! IS_OTBL (otbl)) return (0); return ((sizeof (KpInt32_t)*3) + (sizeof (fut_otbldat_t)*FUT_OUTTBL_ENT)); }
/* fut_copy_otbl makes an exact copy of an existing fut_otbl_t */ fut_otbl_p fut_copy_otbl (fut_otbl_p otbl) { fut_otbl_p new_otbl; KpHandle_t h; /* check for valid otbl */ if ( ! IS_OTBL(otbl) ) { return (FUT_NULL_OTBL); } /* allocate the new otbl structure */ new_otbl = fut_alloc_otbl (); if ( new_otbl == FUT_NULL_OTBL ) { DIAG("fut_copy_otbl: can't alloc output table struct.\n", 0); return (FUT_NULL_OTBL); } h = new_otbl->handle; /* save handle before copying over old otbl */ *new_otbl = *otbl; /* copy entire struct except reference count */ new_otbl->handle = h; new_otbl->ref = 0; /* first reference */ if (otbl->tbl != NULL) { /* copy fixed otbl data */ new_otbl->tbl = fut_alloc_otbldat (new_otbl); if ( new_otbl->tbl == NULL ) { DIAG("fut_copy_otbl: can't alloc output table array.\n", 0); goto ErrOut; } new_otbl->tblHandle = getHandleFromPtr((KpGenericPtr_t)new_otbl->tbl); /* copy the table entries */ KpMemCpy (new_otbl->tbl, otbl->tbl, FUT_OUTTBL_ENT * sizeof (fut_otbldat_t)); } if (otbl->refTbl != NULL) { /* copy reference otbl data */ new_otbl->refTbl = fut_alloc_omftdat (new_otbl, new_otbl->refTblEntries); if (new_otbl->refTbl == NULL ) { DIAG("fut_copy_otbl: can't alloc output table array.\n", 0); goto ErrOut; } /* copy the table entries */ KpMemCpy (new_otbl->refTbl, otbl->refTbl, new_otbl->refTblEntries * sizeof (mf2_tbldat_t)); } return (new_otbl); ErrOut: fut_free_otbl (new_otbl); return (FUT_NULL_OTBL); }
void fut_free_otbldat ( fut_otbl_p otbl, fut_freeMode_t mode) { if ( IS_OTBL(otbl) ) { if ((mode == freeTable) || ((mode == freeData) && (otbl->refTbl != NULL))) { freeBuffer (otbl->tblHandle); otbl->tbl = NULL; otbl->tblHandle = NULL; } } }
void fut_free_otbl (fut_otbl_p otbl) { if ( ! IS_OTBL(otbl)) { /* defined? */ return; } if (otbl->ref != 0) { /* last reference? */ otbl->ref--; } else { fut_free_omftdat (otbl, freeTable); /* free the data */ fut_free_otbldat (otbl, freeTable); otbl->magic = 0; freeBufferPtr ((KpGenericPtr_t)otbl); } }
/* fut_calc_otbl computes the values of an output table from a user defined * function. Ofun must be a pointer to a function accepting accepting a * double and returning a double, both in the range (0.0,1.0). (NULL is a * legal value - it just returns, leaving the table uninitialized). * fut_calc_otbl returns 0 (FALSE) if an error occurs (ofun returned * value out of range) and 1 (TRUE) otherwise. */ KpInt32_t fut_calc_otblEx ( fut_otbl_p otbl, fut_ofunc_t ofun, fut_calcData_p data) { KpInt32_t i, mftData; mf2_tbldat_p theOtbl; double val, indexNorm, indexInc, mftMaxData = MF2_TBL_MAXVAL; fData_t fDataL; fut_calcData_p fDataP; if ( ! IS_OTBL(otbl) ) { return (0); } if (ofun != NULL) { otbl->id = fut_unique_id(); if (data == NULL) { fDataP = &fDataL.std; fDataL.scale = 1.0; } else { fDataP = data; } theOtbl = otbl->refTbl; indexInc = 1.0 / (double) (otbl->refTblEntries -1); for (i = 0, indexNorm = 0.0; i < otbl->refTblEntries; i++, indexNorm += indexInc) { val = (*ofun) (indexNorm, fDataP); MFT_QUANT(val, mftData) theOtbl[i] = (mf2_tbldat_t)mftData; } } return (1); }
/* check the input and output data class of a PT * if a color space is known and the data class is not known, * set the data class to correspond to the color space */ void checkDataClass (PTRefNum_t PTRefNum) { KpInt32_t i1; KpHandle_t PTData; fut_p fut; fut_chan_p chan; fut_otbl_p otbl; PTDataClass_t iDataClass, oDataClass; iDataClass = getPTDataClass (PTRefNum, KCM_IN_SPACE); oDataClass = getPTDataClass (PTRefNum, KCM_OUT_SPACE); PTData = getPTData (PTRefNum); fut = fut_lock_fut (PTData); if ( ! IS_FUT(fut)) return; /* bummer */ checkInDataClass (iDataClass, fut->itbl); /* check the data class of each shared input table */ for (i1 = 0; i1 < FUT_NOCHAN; i1++) { chan = fut->chan[i1]; if (IS_CHAN(chan)) { checkInDataClass (iDataClass, chan->itbl); /* check the data class of each input table */ if (oDataClass != KCP_UNKNOWN) { /* check the data class of each output table */ otbl = chan->otbl; if ((IS_OTBL(otbl)) && (otbl->dataClass == KCP_UNKNOWN)) { otbl->dataClass = oDataClass; } } } } fut_unlock_fut (fut); }
/* fut_new_chan allocates and initializes a fut_chan_t data structure. * If a required input table is missing, a ramp of the proper grid size * will be created. If a supplied itbl is not required, it will not be * inserted into the channel's private itbl list. All tables which are * actually used are copied and so the caller is responsible for * freeing the passed tables if necessary. * * If VARARGS is used, the list of input tables may be relaced by a * single array of fut_itbl_t pointers. This array must then be followed * by a fut_gtbl_p and a fut_otbl_p. */ fut_chan_p fut_new_chan ( KpInt32_t iomask, fut_itbl_p FAR* itbls, fut_gtbl_p gtbl, fut_otbl_p otbl) { fut_itbl_p itbl[FUT_NCHAN]; fut_chan_p chan; KpInt32_t imask, i, tIndex; /* get input mask */ imask = (KpInt32_t)FUT_IMASK(iomask); /* get args specified by imask */ for ( i=0, tIndex = 0; i<FUT_NCHAN; i++ ) { itbl[i] = ((imask & FUT_BIT(i)) && (itbls != NULL)) ? itbls[tIndex++] : NULL; } /* allocate and clear the fut_chan_t structure */ chan = fut_alloc_chan (); if ( ! IS_CHAN(chan)) { return (NULL); } /* check for valid grid and output tables */ if (( ! IS_GTBL(gtbl)) || ((otbl != NULL) && ( ! IS_OTBL(otbl))) ) { DIAG("fut_new_chan: invalid grid or output table.\n", 0); fut_free_chan (chan); return (NULL); } /* get required input channels from gtbl */ chan->imask = fut_gtbl_imask(gtbl); /* insert the required input tables */ for ( i=0; i<FUT_NICHAN; i++ ) { if ( (chan->imask & FUT_BIT(i)) == 0 ) continue; if ( itbl[i] == FUT_NULL_ITBL ) { chan->itbl[i] = fut_new_itblEx (KCP_REF_TABLES, KCP_FIXED_RANGE, gtbl->size[i], fut_irampEx, NULL); if ( chan->itbl[i] == NULL) { DIAG("fut_new_chan: can't create itbl.\n",0); fut_free_chan (chan); return (NULL); } chan->itblHandle[i] = chan->itbl[i]->handle; } else { if ( ! IS_ITBL (itbl[i])) { DIAG("fut_new_chan: invalid input table.\n", 0); fut_free_chan (chan); return (NULL); } else { if ( itbl[i]->size != gtbl->size[i] ) { DIAG("fut_new_chan: gtbl-itbl size mismatch.\n", 0); fut_free_chan (chan); return (NULL); } else { chan->itbl[i] = fut_share_itbl(itbl[i]); /* share the input table */ chan->itblHandle[i] = chan->itbl[i]->handle; } } } } /* insert grid and output tables */ chan->gtbl = fut_share_gtbl (gtbl); chan->gtblHandle = (IS_GTBL(chan->gtbl)) ? chan->gtbl->handle : FUT_NULL_HANDLE; if (IS_OTBL(otbl)) { chan->otbl = fut_share_otbl (otbl); } else { chan->otbl = fut_alloc_otbl(); } chan->otblHandle = (IS_OTBL(chan->otbl)) ? chan->otbl->handle : FUT_NULL_HANDLE; return (chan); }
void evalTh1gen ( imagePtr_p inp, KpInt32_p inStride, KpUInt32_t dataTypeI, imagePtr_p outp, KpInt32_p outStride, KpUInt32_t dataTypeO, KpInt32_t n, PTTable_p PTTableP) { imagePtr_t inData[FUT_NICHAN], outData[FUT_NOCHAN]; KpInt32_t inStrideL[FUT_NICHAN], outStrideL[FUT_NOCHAN]; KpInt32_t i1, separableFut, numInputs, numOutputs, gDimSize[FUT_NOCHAN], oTblEntries[FUT_NOCHAN]; division_t iIndexFactor[FUT_NICHAN], gIndexFactor[FUT_NICHAN], oIndexFactor[FUT_NOCHAN]; KpInt32_t oDataShift, oDataRound, oDataFactor, dataMax, oDataBits; fut_p fut; fut_itbl_p iTbl[FUT_NICHAN], theITbl; fut_chan_p chan[FUT_NOCHAN], theChan; mf2_tbldat_p gTbl[FUT_NOCHAN], oTbl[FUT_NOCHAN]; KpInt32_p BoseSort[FUT_NICHAN] = {BoseSort1, BoseSort2, BoseSort3, BoseSort4, BoseSort5, BoseSort6, BoseSort7, BoseSort8}; mf2_tbldat_t identityTable[2] = {0, MF2_TBL_MAXVAL}; fut = PTTableP->dataP; separableFut = fut_is_separable (fut); /* check for separable (linearization) fut */ /* set up input table stuff */ switch (dataTypeI) { case KCM_UBYTE: dataMax = (1 << 8) -1; break; case KCM_USHORT_12: dataMax = (1 << 12) -1; break; case KCM_USHORT: dataMax = (1 << 16) -1; break; default: dataMax = 1; } for (i1 = 0, numInputs = 0; i1 < FUT_NICHAN; i1++) { if (inp[i1].p8 != NULL) { inData[numInputs].p8 = inp[i1].p8; /* copy addresses - do not change supplied lists! */ inStrideL[numInputs] = inStride[i1]; theITbl = fut->itbl[i1]; if ( ! IS_ITBL(theITbl)) { return; } iTbl[numInputs] = theITbl; /* collect the input tables */ /* set up interpolation into input table */ doDivide (theITbl->refTblEntries -1, dataMax, iIndexFactor[numInputs]); /* set up interpolation into input table */ /* set up interpolation into grid table */ gDimSize[i1] = theITbl->size; /* save in case of separable fut */ doDivide (gDimSize[i1] -1, MF2_TBL_MAXVAL, gIndexFactor[numInputs]); /* set up interpolation into input table */ numInputs++; } } /* set up grid and output table stuff */ for (i1 = 0, numOutputs = 0; i1 < FUT_NOCHAN; i1++) { if (outp[i1].p8 != NULL) { fut_otbl_p theOTbl; outData[numOutputs].p8 = outp[i1].p8; /* copy addresses - do not update supplied lists! */ outStrideL[numOutputs] = outStride[i1]; theChan = fut->chan[i1]; if ( ! IS_CHAN(theChan)) { return; } chan[numOutputs] = theChan; gTbl[numOutputs] = theChan->gtbl->refTbl; /* get the grid */ theOTbl = theChan->otbl; /* set up interpolation into output table */ if ( ! IS_OTBL(theOTbl) || ((oTbl[numOutputs] = theOTbl->refTbl) == NULL)) { oTbl[numOutputs] = identityTable; oTblEntries[numOutputs] = 2; } else { oTblEntries[numOutputs] = theOTbl->refTblEntries; } doDivide (oTblEntries[numOutputs] -1, MF2_TBL_MAXVAL, oIndexFactor[numOutputs]); /* set up interpolation into input table */ numOutputs++; } } /* set up output data scaling */ switch (dataTypeO) { case KCM_UBYTE: oDataBits = 8; break; case KCM_USHORT_12: oDataBits = 12; break; case KCM_USHORT: oDataBits = 16; break; default: dataMax = 1; } dataMax = (1 << oDataBits) -1; oDataShift = 32 -1 - oDataBits; oDataFactor = (dataMax << oDataShift) / MF2_TBL_MAXVAL; oDataRound = (1 << (oDataShift -1)) -1; /* all set up; evaluate each pixel */ for (i1 = 0; i1 < n; i1++) { KpInt32_t cell, i2, index, dimSize, numCompares, hVert[FUT_NICHAN]; KpInt32_t sPosition, iTableData[FUT_NICHAN], hFrac[FUT_NICHAN]; KpInt32_p BoseSortP; for (i2 = 0, cell = 0; i2 < numInputs; i2++) { KpInt32_t srcData, interpData; if (dataTypeI == KCM_UBYTE) { srcData = (KpInt32_t) (*inData[i2].p8); /* get 8 bit input data */ } else { srcData = (KpInt32_t) (*inData[i2].p16); /* get 12/16 bit input data */ } inData[i2].p8 += inStrideL[i2]; /* pass source image data through the input table */ theITbl = iTbl[i2]; interpData = interp1DTable (theITbl->refTbl, theITbl->refTblEntries, srcData, iIndexFactor[i2]); iTableData[i2] = interpData; /* save in case of separable fut */ doMultiply (interpData, gIndexFactor[i2], sPosition); /* calculate the input table position */ index = sPosition >> EVAL_FRACBITS; dimSize = theITbl->size; /* size of this dimension */ if (index < dimSize -1) { hFrac[i2] = sPosition & ((1 << EVAL_FRACBITS) -1); /* get grid interpolant */ } else { hFrac[i2] = (1 << EVAL_FRACBITS) -1; index--; } hVert[i2] = dimSize; /* save for offset calcs */ cell *= dimSize; /* build cell index */ cell += index; /* add in this index */ } /* build offsets for each dimension */ index = 2; for (i2 = numInputs-1; i2 >= 0; i2--) { dimSize = hVert[i2]; hVert[i2] = index; index *= dimSize; } /* find the hyperhedron in which the interpolation point is located */ BoseSortP = BoseSort[numInputs -1]; numCompares = *BoseSortP++; /* first element is # of compares */ for (i2 = 0; i2 < numCompares; i2++) { KpInt32_t tmpI, index1, index2; index1 = *BoseSortP++; index2 = *BoseSortP++; /* sort into largest to smallest based upon interpolants */ tmpI = hFrac[index1]; if (tmpI < hFrac[index2]) { hFrac[index1] = hFrac[index2]; /* swap interpolants */ hFrac[index2] = tmpI; tmpI = hVert[index1]; /* swap vertices */ hVert[index1] = hVert[index2]; hVert[index2] = tmpI; } } /* evaluate each output channel */ for (i2 = 0; i2 < numOutputs; i2++) { KpInt32_t i3, tResult, oTableData, previousVertex, thisVertex; KpUInt8_p vertexP; if (separableFut == 1) { tResult = interp1DTable (gTbl[i2], gDimSize[i2], iTableData[i2], gIndexFactor[i2]); } else { /* hyperhedral interpolation */ vertexP = (KpUInt8_p)(gTbl[i2] + cell); previousVertex = (KpInt32_t) *(mf2_tbldat_p)(vertexP); tResult = previousVertex << (EVAL_FRACBITS - EVAL_EXTENDED_BITS); for (i3 = 0; i3 < numInputs; i3++) { vertexP += hVert[i3]; thisVertex = (KpInt32_t) *(mf2_tbldat_p)(vertexP); interpolateDelta (previousVertex, thisVertex, hFrac[i3], previousVertex) tResult += previousVertex; previousVertex = thisVertex; } tResult += ROUND_VALUE(EVAL_FRACBITS - EVAL_EXTENDED_BITS); KCP_SHIFT_RIGHT(tResult, tResult, EVAL_FRACBITS - EVAL_EXTENDED_BITS); } /* output table lookup */ oTableData = interp1DTable (oTbl[i2], oTblEntries[i2], tResult, oIndexFactor[i2]); oTableData *= oDataFactor; /* convert to dest size */ oTableData += oDataRound; /* round */ oTableData >>= oDataShift; /* remove fractional bits */ if (dataTypeO == KCM_UBYTE) { *outData[i2].p8 = (KpUInt8_t) oTableData; } else { *outData[i2].p16 = (KpUInt16_t) oTableData; } outData[i2].p8 += outStrideL[i2]; /* next output data location */ } } }
/* fut_comp_iotblMF composes an output table with an input table. The composite table * has the same data width and format as an input table, but has the number of entries of * an output table. */ static KpInt32_t fut_comp_iotblMF ( fut_itbl_p itbl, fut_otbl_p otbl, fut_itbl_p dstitbl) { mf2_tbldat_t x, intDestData, theOTbl[MF2_MAX_TBL_ENT]; mf2_tbldat_t identOTbl[2] = {0, MF2_TBL_MAXVAL}; mf2_tbldat_p srcOTblP, theOTblP; fut_otbldat_p optr; KpInt32_t i, tableIndex, tableIndexNext, srcOTblEntries; KpFloat32_t index, tableFrac, srcData, srcData1, destData, indexRatio; if ( ! IS_ITBL(itbl) || ! IS_OTBL(otbl) || ! IS_ITBL(dstitbl)) { return 0; } if (otbl->refTblEntries > dstitbl->refTblEntries) { return 0; /* screwed up somewhere */ } if ((srcOTblP = otbl->refTbl) == NULL) { srcOTblP = identOTbl; /* null means identity */ srcOTblEntries = 2; } else { srcOTblEntries = otbl->refTblEntries; } if (otbl->refTblEntries == dstitbl->refTblEntries) { theOTblP = otbl->refTbl; } else { /* expand current otbl to specified size */ theOTblP = theOTbl; convert1DTable (srcOTblP, sizeof (mf2_tbldat_t), srcOTblEntries, MF2_TBL_MAXVAL, theOTblP, sizeof (mf2_tbldat_t), dstitbl->refTblEntries, MF2_TBL_MAXVAL, KCP_MAP_END_POINTS, KCP_MAP_END_POINTS); } /* compose output table into this input table */ optr = dstitbl->refTbl; indexRatio = (KpFloat32_t) (itbl->refTblEntries -1) / (KpFloat32_t) MF2_TBL_MAXVAL; for (i = 0; i < dstitbl->refTblEntries; i++) { x = theOTblP [i]; /* interpolation value */ index = (KpFloat32_t) x * indexRatio; /* calculate the input table position */ tableIndex = (KpInt32_t) index; /* the input table index */ tableFrac = index - (KpFloat32_t) tableIndex; /* and the input table interpolant */ if (tableIndex >= itbl->refTblEntries) { /* make sure we're in range for interpolation */ tableIndex = itbl->refTblEntries -1; /* 1st source is past end */ tableIndexNext = tableIndex; } else { tableIndexNext = tableIndex +1; if (tableIndexNext == itbl->refTblEntries) { tableIndexNext = tableIndex; /* 1st source is at end */ } } srcData = (KpFloat32_t) itbl->refTbl [tableIndex]; srcData1 = (KpFloat32_t) itbl->refTbl [tableIndexNext]; destData = srcData + (tableFrac * (srcData1 - srcData)); /* interpolate */ /* round and convert to integer */ intDestData = (mf2_tbldat_t)(destData + 0.5); if (intDestData > (mf2_tbldat_t)MF2_TBL_MAXVAL) { intDestData = MF2_TBL_MAXVAL; } optr [i] = intDestData; } return 1; }
/*--------------------------------------------------------------------------- * makeInverseXformFromMatrix -- make a fut of given gridsize from given * matrix data for inverse transform (XYZ -> RGB); return status code *--------------------------------------------------------------------------- */ PTErr_t makeInverseXformFromMatrix (LPMATRIXDATA mdata, KpUInt32_t interpMode, KpInt32_p dim, fut_p theFut) { PTErr_t PTErr = KCP_SUCCESS; ResponseRecord_p rrp; KpInt32_t i; fut_chan_p theChan; fut_gtbl_p theGtbl; fut_otbl_p theOtbl; mf2_tbldat_p gtblDat[3], otblDat, prevOtblDat; KpUInt16_t prevGamma = 0, thisGamma; double fwdgamma, one[3]; double offset[3] = {1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0}; KpUInt16_t *pCurveData = NULL; for (i = 0; i < 3; i++) { if (!IS_CHAN(theChan = theFut->chan[i]) || !IS_GTBL(theGtbl = theChan->gtbl) || ((gtblDat[i] = theGtbl->refTbl) == NULL) /* Get grid tables */ || !IS_OTBL(theOtbl = theChan->otbl) || ((otblDat = theOtbl->refTbl) == NULL)) { /* Get output table */ return KCP_INCON_PT; } if (theOtbl->refTblEntries != FUT_OUTTBL_ENT) return KCP_INCON_PT; /* Get ResponseRecord: */ rrp = mdata->outResponse[i]; if (NULL == rrp) { break; /* must only have output tables */ } if (PARA_TYPE_SIG == rrp->TagSig) { pCurveData = (KpUInt16_p) allocBufferPtr (MFV_CURVE_TBL_ENT*sizeof(KpUInt16_t)); /* get memory for curve data */ if (NULL == pCurveData) { return KCP_NO_MEMORY; } makeCurveFromPara (rrp->ParaFunction, rrp->ParaParams, pCurveData, MFV_CURVE_TBL_ENT); rrp->CurveCount = MFV_CURVE_TBL_ENT; rrp->CurveData = pCurveData; } if ((rrp->CurveCount > 0) && (rrp->CurveData == (KpUInt16_p)NULL)) { PTErr = KCP_INCON_PT; goto ErrOut; } /* Recompute output table: */ switch (rrp->CurveCount) { case 0: /* linear response, with clipping */ calcOtbl0 (otblDat); break; case 1: /* power law */ thisGamma = rrp->CurveData[0]; if (prevGamma == thisGamma) { /* same gamma, just copy table */ memcpy (otblDat, prevOtblDat, sizeof (*otblDat) * FUT_OUTTBL_ENT); } else { prevGamma = thisGamma; prevOtblDat = otblDat; fwdgamma = (double)thisGamma / SCALEDOT8; if (fwdgamma <= 0.0) { PTErr = KCP_INCON_PT; goto ErrOut; } calcOtbl1 (otblDat, fwdgamma); } break; default: /* look-up table of arbitrary length */ makeInverseMonotonic (rrp->CurveCount, rrp->CurveData); if (rrp->CurveCount == theOtbl->refTblEntries) { /* ready-to-use look-up table */ memcpy (otblDat, rrp->CurveData, sizeof (*otblDat) * rrp->CurveCount); } else { PTErr = calcOtblN (otblDat, rrp, interpMode); if (PTErr != KCP_SUCCESS) { PTErr = KCP_INCON_PT; goto ErrOut; } } break; } } /* Compute inverse matrix (XYZ -> RGB): */ one[0] = one[1] = one[2] = 1.0; /* arbitrary vector */ /* replaces matrix with inverse */ if (solvemat (3, mdata->matrix, one) != 0) { PTErr = KCP_INCON_PT; goto ErrOut; } /* Rescale given matrix by factor of 3 for extended range: */ for (i = 0; i < 3; i++) { KpInt32_t j; for (j = 0; j < 3; j++) { mdata->matrix[i][j] /= 3.0; } } /* Replace grid tables: */ calcGtbl3 (gtblDat, dim, mdata->matrix, offset); /* with offset */ ErrOut: if (NULL != pCurveData) { freeBufferPtr (pCurveData); } return PTErr; }