/* fut_add_chan inserts a new output channel into a fut. * Unlike itbls, otbls, and gtbls, the channel structure is not sharable * and so the caller must not free the chan after this call. (If the * passed channel structure needs to be saved, use fut_copy_chan). * The iomask in this case simply tells which output channel is being * added, and if this channel already exists, an error (0) is returned. * * fut_add_chan is intended to be used in conjunction with fut_new_chan * to construct futs with independent input tables. It does not update * the list of common input tables as does fut_new and fut_defchan and * should not be mixed with calls to fut_defchan. */ KpInt32_t fut_add_chan (fut_p fut, KpInt32_t iomask, fut_chan_p chan) { KpInt32_t ochan; if ( ! IS_FUT(fut) || (chan != FUT_NULL_CHAN && ! IS_CHAN(chan)) ) { return (0); } /* get output channel no. */ ochan = FUT_CHAN ((KpInt32_t)FUT_OMASK(iomask)); /* prohibit redefinition of channel */ if ( ochan >= FUT_NOCHAN || fut->chan[ochan] != NULL) return (0); /* insert channel into fut */ fut->chan[ochan] = chan; fut->chanHandle[ochan] = (IS_CHAN(fut->chan[ochan])) ? fut->chan[ochan]->handle : FUT_NULL_HANDLE; /* update iomasks */ if ( IS_CHAN(chan) ) { fut->iomask.out |= FUT_BIT(ochan); fut->iomask.in |= chan->imask; } return (1); }
/* fut_free_chan_list_p For each channel, This functions frees all input tables, the output table and the grid table. It then frees the actual fut_chan_t memory. */ static void fut_free_chan_list_p ( fut_chan_p FAR * chan_list, KpHandle_t FAR * chanHdl_list) { KpInt32_t i; fut_chan_p chan; if ( (chan_list == NULL) || ( chanHdl_list == NULL) ) return; for ( i=0; i<FUT_NOCHAN; i++ ) { chan = chan_list[i]; if (chan == NULL) { /* chan is unlocked on entry */ chan = lockBuffer(chanHdl_list[i]); } if (IS_CHAN(chan)) { fut_free_itbl_list_p (chan->itbl, chan->itblHandle); /* free input tables */ fut_free_otbl_p (chan->otbl, chan->otblHandle); /* free output table */ fut_free_gtbl_p (chan->gtbl, chan->gtblHandle); /* free grid table */ /* free fut_chan_t structure itself */ chan->magic = 0; freeBufferPtr ((KpGenericPtr_t)chan); chan_list[i] = FUT_NULL_CHAN; } } }
//////////////////////////////////////////////////////////// // HANDLE EVENT FROM RAW MIDI NOTE // Note on has velocity > 0 void gate_midi_note(byte chan, byte note, byte vel) { // for each gate output for(byte which_gate=0; which_gate<GATE_MAX; ++which_gate) { GATE_OUT *pgate = &l_gate[which_gate]; GATE_OUT_CFG *pcfg = &l_gate_cfg[which_gate]; // does this gate respond to midi note? if(pcfg->event.mode != GATE_MIDI_NOTE) continue; // does the MIDI channel match? if(!IS_CHAN(pcfg->note.chan, chan)) continue; // Does the note match? if(!IS_NOTE_MATCH(pcfg->note.note, pcfg->note.note_max, note)) continue; // is this a note off or note on with velocity above threshold? if(vel && vel < pcfg->note.vel_min) { continue; } // trigger (for note on) or untrigger (for note off) trigger(pgate, pcfg, which_gate, !!vel, false); } }
static KpInt32_t fut_size_chan ( fut_chan_p chan, chan_hdr_p chanio) { KpInt32_t size = 0; KpInt32_t i1; if ( ! IS_CHAN (chan) ) return (0); /* add up size of the input tables */ for ( i1=0; i1<FUT_NICHAN; i1++ ) { if ( chanio->icode[i1] == FUTIO_UNIQUE ) size += fut_size_itbl (chan->itbl[i1]); } /* add up size of the output table */ if ( chanio->ocode == FUTIO_UNIQUE ) { size += fut_size_otbl (chan->otbl); } /* add up size of the grid table */ if ( chanio->gcode == FUTIO_UNIQUE ) { size += fut_size_gtbl (chan->gtbl); } return size; }
void fut_free_chan (fut_chan_p chan) { if ( ! IS_CHAN(chan) ) /* check if defined */ return; fut_free_itbl_list (chan->itbl); /* free input tables */ fut_free_otbl (chan->otbl); /* free output table */ fut_free_gtbl (chan->gtbl); /* free grid table */ /* free fut_chan_t structure itself */ chan->magic = 0; freeBufferPtr ((KpGenericPtr_t)chan); }
void fut_free_mftdat (fut_p fut) { KpInt32_t i; fut_chan_p chan; if (IS_FUT(fut)) { fut_free_itbldat_list (&fut->itbl[0], FUT_MFTDATA); for ( i=0; i<FUT_NOCHAN; i++ ) { chan = fut->chan[i]; if (IS_CHAN(chan)) { fut_free_itbldat_list (&chan->itbl[0], FUT_MFTDATA); fut_free_gmftdat (chan->gtbl, freeData); fut_free_omftdat (chan->otbl, freeData); } } } }
//////////////////////////////////////////////////////////// // HANDLE EVENT FROM RAW MIDI CC void gate_midi_cc(byte chan, byte cc, byte value) { // for each gate output for(byte which_gate=0; which_gate<GATE_MAX; ++which_gate) { GATE_OUT *pgate = &l_gate[which_gate]; GATE_OUT_CFG *pcfg = &l_gate_cfg[which_gate]; // does this gate respond to CC? if(pcfg->event.mode != GATE_MIDI_CC && pcfg->event.mode != GATE_MIDI_CC_NEG) continue; // is this the correct CC? if(cc != pcfg->cc.cc) { continue; } // does the MIDI channel match? if(!IS_CHAN(pcfg->cc.chan, chan)) continue; // has the value just gone above threshold? if(value >= pcfg->cc.threshold && ( pgate->value < pcfg->cc.threshold || pgate->value == NO_VALUE)) { // trigger gate trigger(pgate, pcfg, which_gate, !(pcfg->event.mode == GATE_MIDI_CC_NEG), false); pgate->value = value; } // has the value just gone below threshold? else if(value < pcfg->cc.threshold && ( pgate->value >= pcfg->cc.threshold || pgate->value == NO_VALUE)) { // untrigger gate trigger(pgate, pcfg, which_gate, (pcfg->event.mode == GATE_MIDI_CC_NEG), false); pgate->value = value; } } }
/* fut_comp_chan_ilut composes (in place) the input tables of a * fut output channel with the look-up tables specified in the * list, luts. The original and new input tables from the * parent fut must be passed in order to preserve the sharing * of input tables. */ static KpInt32_t fut_comp_chan_ilut (fut_chan_p chan, KpChar_p FAR* luts, fut_itbl_p FAR* orig_itbls, fut_itbl_p FAR* new_itbls, KpInt32_t is_12bits) { KpInt32_t i; fut_itbl_p new_itbl; if ( ! IS_CHAN(chan) ) { return (0); } /* check each itbl to see if must be computed or shared */ for ( i=0; i<FUT_NICHAN; i++ ) { if ((luts[i] == NULL) || (chan->itbl[i] == NULL)) continue; if ((orig_itbls != NULL) && (chan->itbl[i] == orig_itbls[i])) { new_itbl = fut_share_itbl(new_itbls[i]); } else { new_itbl = fut_comp_itbl_ilut (chan->itbl[i], luts[i], is_12bits); } if (new_itbl == FUT_NULL_ITBL) { return (0); } /* replace with the new composed or shared itbl */ fut_free_itbl (chan->itbl[i]); chan->itbl[i] = new_itbl; } 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); }
/* fut_copy_chan makes a copy of an existing fut_chan_t structure. */ fut_chan_p fut_copy_chan (fut_chan_p chan) { fut_chan_p new_chan; KpInt32_t i; KpHandle_t h; if ( ! IS_CHAN(chan) ) { return (FUT_NULL_CHAN); } new_chan = fut_alloc_chan (); if ( new_chan == FUT_NULL_CHAN ) { return (FUT_NULL_CHAN); } /* save handle before copying over old fut */ h = new_chan->handle; /* copy over to new structure */ *new_chan = *chan; /* move handle back to new structure */ new_chan->handle = h; /* copy itbls * if an itbl is shared, share it with the itbl in the new fut */ for ( i=0; i<FUT_NICHAN; i++ ) { new_chan->itbl[i] = (IS_SHARED (chan->itbl[i])) ? fut_share_itbl (chan->itbl[i]) : fut_copy_itbl (chan->itbl[i]); new_chan->itblHandle[i] = getHandleFromPtr((KpGenericPtr_t)new_chan->itbl[i]); } /* copy gtbl */ new_chan->gtbl = fut_copy_gtbl (chan->gtbl); new_chan->gtblHandle = getHandleFromPtr((KpGenericPtr_t)new_chan->gtbl); /* copy otbl */ new_chan->otbl = (IS_SHARED(chan->otbl)) ? fut_share_otbl (chan->otbl) : fut_copy_otbl (chan->otbl); new_chan->otblHandle = getHandleFromPtr((KpGenericPtr_t)new_chan->otbl); /* check for successful copies */ for ( i=0; i<FUT_NICHAN; i++ ) { if ( new_chan->itbl[i] == 0 && chan->itbl[i] != 0 ) { goto ErrOut; } } if ( (new_chan->otbl == 0 && chan->otbl != 0) || (new_chan->gtbl == 0 && chan->gtbl != 0) ) { goto ErrOut; } return (new_chan); ErrOut: fut_free_chan (new_chan); return (FUT_NULL_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_p fut_resize ( fut_p fut, KpInt32_p sizeArray) { fut_p reSizedGtblFut = NULL, gtblFut = NULL, reSizedFut = NULL, identityFut = NULL; KpInt32_t i1, i2, iomask, iiomask, imask, omask, sameDims; fut_chan_p chan; fut_itbl_p itbl, itbls[FUT_NICHAN]; fut_gtbl_p gtbls[FUT_NOCHAN]; fut_otbl_p otbls[FUT_NOCHAN]; #if defined KCP_DIAG_LOG kcpDiagLog ("fut_resize\n"); #endif if ( ! IS_FUT(fut)) { return NULL; } for (i1 = 0; i1 < FUT_NICHAN; i1++) { itbls[i1] = FUT_NULL_ITBL; /* init to null for freeing on error */ } /* collect the gtbls from the source fut */ /* make sure that all the gtbls use the same itbls */ omask = 0; for (i1 = 0, sameDims = 1; i1 < FUT_NOCHAN; i1++) { chan = fut->chan[i1]; if (IS_CHAN(chan)) { for (i2 = 0; i2 < FUT_NICHAN; i2++) { itbl = fut->itbl[i2]; if (chan->itbl[i2] != itbl) { /* must be shared */ goto GetOut; } if (IS_ITBL(itbl)) { if (itbl->size != sizeArray [i2]) { sameDims = 0; /* not the same */ } } } omask |= FUT_BIT(i1); /* resize this chan */ gtbls[i1] = chan->gtbl; /* collect gtbls */ } else { gtbls[i1] = NULL; } } if (sameDims == 1) { return fut; /* already the right size! */ } imask = fut->iomask.in; iomask = FUT_OUT(omask) | FUT_IN(imask); /* make a new fut with these gtbls and identity itbls and otbls */ gtblFut = fut_new (iomask, NULL, gtbls, NULL); if (gtblFut != NULL) { /* make an identity fut with itbls that have the specified sizes */ iiomask = FUT_OUT(imask) | FUT_IN(imask); identityFut = constructfut (iiomask, sizeArray, NULL, NULL, NULL, NULL, KCP_FIXED_RANGE, KCP_FIXED_RANGE); if (identityFut != NULL) { /* compose the new size fut with the gtbl fut */ reSizedGtblFut = fut_comp (gtblFut, identityFut, 0); if (reSizedGtblFut != NULL) { /* make a new fut with original itbls, ... */ for (i1 = 0; i1 < FUT_NICHAN; i1++) { if ((imask & FUT_BIT(i1)) != 0) { itbls[i1] = fut_copy_itbl (fut->itbl[i1]); /* copy (do not share!) original itbls */ if (itbls[i1] == NULL) { goto GetOut; } makeMftiTblDat (itbls[i1]); /* convert to mft to remove grid size dependancy */ itbls[i1]->size = reSizedGtblFut->itbl[i1]->size; /* set new grid size */ fut_free_itbldat (itbls[i1], freeData); /* free fixed table, it has incorrect grid indices */ } } /* ... resized gtbls, and original otbls */ for (i1 = 0; i1 < FUT_NOCHAN; i1++) { if ((omask & FUT_BIT(i1)) != 0) { gtbls[i1] = reSizedGtblFut->chan[i1]->gtbl; /* collect resized gtbls */ otbls[i1] = fut->chan[i1]->otbl; /* and original otbls */ } else { gtbls[i1] = NULL; otbls[i1] = NULL; } } reSizedFut = fut_new (iomask, itbls, gtbls, otbls); } } } GetOut: fut_free (reSizedGtblFut); /* free the intermediate futs */ fut_free (gtblFut); fut_free (identityFut); fut_free_tbls (FUT_NICHAN, (void **)itbls); return (reSizedFut); }
fut_p fut_comp (fut_p fut1, fut_p fut0, KpInt32_t iomask) { KpInt32_t ok = 1, nGridPoints, omask, evalomask, imask, pmask, order, i, j, nEntries, nOutChans; fut_p fut2 = NULL, evalFut = NULL; fut_itbl_p oitbls[FUT_NICHAN]; mf2_tbldat_p indat[FUT_NICHAN], outdat[FUT_NOCHAN]; fut_gtbl_p fut1_gtbls[FUT_NOCHAN]; if (( ! IS_FUT(fut0)) || ( ! IS_FUT(fut1))) { return (NULL); } /* extract component masks from iomask */ omask = FUT_OMASK(iomask); /* which output chans? */ pmask = FUT_PMASK(iomask); /* which ones allowed to pass through? */ order = FUT_ORDMASK(iomask); /* which interpolation to use? */ if ( order == FUT_DEFAULT ) { order = fut1->iomask.order; } /* adjust masks for iomask_check below */ pmask &= fut0->iomask.out; /* available for "pass through" */ if ( omask == 0 ) { /* required outputs (0 means all) */ omask = fut1->iomask.out; } /* see if fut0 can provide required inputs to fut1 */ imask = fut0->iomask.out; /* available inputs for fut1 */ iomask = FUT_OUT(omask) | FUT_IN(imask) | FUT_PASS(pmask); if ( ! fut_iomask_check (fut1, iomask) ) { return (NULL); } /* make sure the futs are in the reference state */ if ((fut_to_mft (fut0) != 1) || (fut_to_mft (fut1) != 1)) { return (NULL); } /* fut1 will be used to process the grid tables of fut0, placing the * results in the grid tables of fut2. Fut0's grid table data must first * be passed through its output tables before sending it through fut1's * input tables. This is accomplished more efficiently by composing * fut1's input tables with fut0's output tables and using these directly * on fut0 grid data rather than the normal input tables. * * Create the result fut (fut2) which will be the composition of fut1 * and fut0. Fut2 will inherit the input tables of fut0 and the output * tables of fut1. Its grid data will be in the same color coordinates * as fut1's. */ fut2 = fut_new (FUT_IN(FUT_ALLIN), fut0->itbl, NULL, NULL); if ( fut2 == NULL ) { return (NULL); } /* for each desired channel i in fut2, create a new grid table. The * dimensions of each new grid table are derived from fut0 and fut1 * like so: for every input required for channel i of fut1, form the * union of the input sets of all corresponding fut0 outputs. */ /* null all io tables and table pointers */ KpMemSet (oitbls, 0, sizeof(oitbls)); imask = 0; /* will be the input mask for all inputs needed to fut1 */ evalomask = 0; /* omask for evaluation */ for (i = 0; (i < FUT_NOCHAN) && ok; i++) { KpInt32_t size[FUT_NICHAN]; fut_gtbl_p gtbl; KpInt32_t imask1, imask2; fut1_gtbls[i] = NULL; /* assume not needed */ if ((omask & FUT_BIT(i)) == 0) { /* is this output channel needed? */ continue; /* no */ } /* if a specified output is to be passed through from fut0, do that here */ if ( ! IS_CHAN(fut1->chan[i]) && IS_CHAN(fut0->chan[i])) { ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, fut0->chan[i]->gtbl, fut0->chan[i]->otbl); continue; /* no need to evaluate this ochan */ } if (! IS_CHAN(fut1->chan[i])) { ok = 0; /* something wrong */ goto GetOut; } /* At this point we know that (fut1->chan[i] != 0). We also * have determined (from iomask_check above) that fut0->chan[j] != 0. */ imask2 = 0; /* determine inputs from fut0 needed for this channel */ imask1 = fut1->chan[i]->imask; /* inputs used by this chan */ for (j = 0; (j < FUT_NICHAN) && ok; j++) { if ((imask1 & FUT_BIT(j)) != 0) { /* this input chan is needed */ if ( ! IS_CHAN(fut0->chan[j])) { /* available? */ ok = 0; /* composition fails */ goto GetOut; } if (fut1->itbl[j] != fut1->chan[i]->itbl[j]) { /* shared itbl? */ goto nextOChan; /* nope, ignore this ochan */ } imask2 |= fut0->chan[j]->imask; } } evalomask |= FUT_BIT(i); /* will be evalutating this channel */ imask |= imask1; /* build mask of all needed inputs */ /* determine required dimensions from mask */ for (j = 0; j < FUT_NICHAN; j++) { size[j] = (imask2 & (KpInt32_t)FUT_BIT(j)) ? fut0->itbl[j]->size : 1; } /* create the new grid table * insert it along with fut1's output table into fut2 */ gtbl = fut_new_gtblEx (FUT_IN(FUT_ALLIN), NULL, NULL, size); ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, gtbl, fut1->chan[i]->otbl); fut_free_gtbl (gtbl); if (!ok) { goto GetOut; } fut1_gtbls[i] = fut1->chan[i]->gtbl; /* collect gtbls for evaluation fut */ /* verify the input data for the evaluation of the output channel in fut1 */ for (j = 0; j < FUT_NICHAN; j++) { if ((imask1 & FUT_BIT(j)) != 0) { /* this channel needed as input */ if ((fut0->chan[j]->imask & (~fut2->chan[i]->imask)) != 0) { /* it's inputs must be used by output */ ok = 0; /* composition fails */ goto GetOut; } } } nextOChan:; } /* collect the gtbls which are the input data for the chan evaluation. * also pre-compose fut0's otbls with fut1's itbls. */ for (i = 0; i < FUT_NICHAN; i++) { oitbls[i] = NULL; if (ok) { fut_chan_p theChan = fut0->chan[i]; if ((imask & FUT_BIT(i)) == 0) { continue; /* this output from fut0 not required */ } indat[i] = theChan->gtbl->refTbl; /* collect gtbls: the input data for the evaluation */ ok = (indat[i] != NULL); /* allocate memory for composed i/o tables * these have the same size as the output tables of the channel supplying the input */ if (ok) { fut_itbl_p theITbl = fut1->itbl[i]; fut_otbl_p theOTbl = theChan->otbl; oitbls[i] = fut_alloc_itbl (); /* get an itbl */ oitbls[i]->size = theITbl->size; oitbls[i]->dataClass = KCP_FIXED_RANGE; nEntries = MAX(theITbl->refTblEntries, theOTbl->refTblEntries); ok = (fut_alloc_imftdat (oitbls[i], nEntries) != NULL); if (ok) { /* make input table for evaluation */ ok = fut_comp_iotblMF (theITbl, theOTbl, oitbls[i]); } } } } /* make an evaluation fut with the composed I/O tables, fut1's gtbls, and no otbls */ evalFut = fut_new (iomask, oitbls, fut1_gtbls, NULL); if (( ! ok) || (evalFut == NULL) || /* if evaluation fut ok */ (fut_to_mft (fut2) != 1)) { /* make sure the futs are in the reference state */ ok = 0; goto GetOut; } else { /* Finally, we are ready to pass fut0's grid tables through fut1 */ for (i = 0, nOutChans = 0; (i < FUT_NOCHAN) && ok; i++) { if ((evalomask & FUT_BIT(i)) != 0) { fut_gtbl_p gtbl; gtbl = fut2->chan[i]->gtbl; nGridPoints = gtbl->tbl_size / sizeof (fut_gtbldat_t); /* grid points for eval */ if (evalFut->iomask.in != evalFut->chan[i]->imask) { /* must evaluate this channel singly */ evalomask &= ~FUT_BIT(i); /* remove channel from multiple eval list */ ok = evaluateFut (evalFut, FUT_BIT(i), KCM_USHORT, nGridPoints, (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) &(gtbl->refTbl)); } else { outdat[nOutChans] = gtbl->refTbl; nOutChans++; } } } /* eval result is composed fut's gtbls */ ok = evaluateFut (evalFut, evalomask, KCM_USHORT, nGridPoints, (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) outdat); } GetOut: /* must always free up the evaluation fut and io tables, even if an error occurred! */ fut_free (evalFut); fut_free_tbls (FUT_NICHAN, (void *)oitbls); /* check for errors */ if ( !ok ) { fut_free (fut2); fut2 = NULL; } return (fut2); }
/* fut_defchan defines an output channel for a fut. Returns FALSE(0) if * the output channel is already defined (or fut is NULL), TRUE(1) * otherwise. The size of the grid table (if non-zero) must match those * of the corresponding input table. If they do not, the channel remains * undefined and FALSE is returned. * * If a required input table is missing, the table will be shared * with the corresponding one from the list of common itbls. If there * is no such table in the common list, a ramp table is created and * inserted into the common itbl list. * * Since fut_defchan is intended to be used for constructing futs with * shared input tables, if an input table is supplied that conflicts with * a table in the common list, an error occurs. */ KpInt32_t fut_defchan ( fut_p fut, KpInt32_t iomask, fut_itbl_p FAR* itbls, fut_gtbl_p gtbl, fut_otbl_p otbl) { fut_itbl_p itbl[FUT_NICHAN]; fut_chan_p chan; KpInt32_t imask, i, tIndex; /* check for valid fut */ if ( ! IS_FUT(fut)) { return (0); } /* get input mask */ imask = (KpInt32_t) FUT_IMASK(iomask); /* get args specified by imask */ for ( i=0, tIndex = 0; i < FUT_NICHAN; i++ ) { if ((itbls != NULL) && ((imask & FUT_BIT(i)) != 0)) { /* if itbl is in arglist, use it */ itbl[i] = (fut_itbl_p)itbls[tIndex++]; } else { /* use itbl from shared itbl list */ itbl[i] = fut->itbl[i]; } } chan = fut_new_chan ((KpInt32_t)(FUT_IN (FUT_ALLIN)), (fut_itbl_p FAR*)itbl, gtbl, otbl); if ( ! IS_CHAN(chan)) { return (0); } /* If fut_new_chan created a new itbl (ramp), add it to the * common list. However, if an itbl in the chan differs from * one in the common list, return an error. */ for ( i=0; i < FUT_NICHAN; i++ ) { if ( chan->itbl[i] == NULL ) { continue; } if ( ! IS_ITBL(fut->itbl[i])) { fut->itbl[i] = fut_share_itbl(chan->itbl[i]); fut->itblHandle[i] = chan->itblHandle[i]; } else { if ( fut->itbl[i] != chan->itbl[i] ) { DIAG("fut_defchan: conflicting itbls.\n", 0); fut_free_chan (chan); return (0); } } } /* insert channel into fut */ if ( ! fut_add_chan (fut, iomask, chan) ) { fut_free_chan (chan); return (0); } return (1); }
KpInt32_t TpGetDataSize ( KpHandle_t PTHdr, KpHandle_t PTData, PTType_t format) { KpInt32_t size, futRet, imask, omask, LUTDimensions, inputChans, outputChans; KpInt32_t i, tableSize, oTableEntries, gTableEntries, iTableEntries, nParaParams; PTErr_t errnum = KCP_INVAL_PTTYPE; fut_hdr_p futHdr; fut_p fut; KpUInt32_t lutConfig; size = 0; errnum = initExport (PTHdr, PTData, format, &futHdr, &fut); /* set up to export the data */ if (errnum == KCP_SUCCESS) { switch (format) { case PTTYPE_FUTF: size = fut_get_size (fut, futHdr); fut_free_tbldat (fut); /* free the made data tables */ break; case PTTYPE_MFT1: case PTTYPE_MFT2: case PTTYPE_MFT2_VER_0: futRet = fut_mfutInfo (fut, &LUTDimensions, &inputChans, &outputChans, format, &iTableEntries, &gTableEntries, &oTableEntries); if (futRet == 1) { size = inputChans * iTableEntries; /* total input table entries */ size += outputChans * (gTableEntries + oTableEntries); /* plus total grid and output table entries */ if (format == PTTYPE_MFT1) { size *= sizeof (mf1_tbldat_t); /* mult by bytes in each entry */ } else { size += 2; /* plus input and output table counters */ size *= sizeof (mf2_tbldat_t); /* mult by bytes in each entry */ } } fut_free_mftdat (fut); /* free the made data tables */ break; case PTTYPE_MAB1: case PTTYPE_MAB2: case PTTYPE_MBA1: case PTTYPE_MBA2: lutConfig = fut->lutConfig; /* input tables must be common and in first n contiguous input channels */ imask = fut->iomask.in; /* get the fut's input mask */ for (inputChans = 0; inputChans < FUT_NICHAN; inputChans++, imask >>= 1) { if ( ! IS_ITBL(fut->itbl[inputChans]) || ((imask & 1) == 0)) { break; } } if (imask != 0) { return (0); /* this fut can not be made into a matrix fut */ } /* output tables must be in first n contiguous output channels */ omask = fut->iomask.out; /* get the fut's output mask */ for (outputChans = 0; outputChans < FUT_NOCHAN; outputChans++, omask >>= 1) { if ( ! IS_CHAN(fut->chan[outputChans]) || ((omask & 1) == 0)) { break; } } if (omask != 0) { return (0); /* this fut can not be made into a matrix fut */ } tableSize = sizeof (mab_tbldat_t); if ((LUT_TYPE_UNKNOWN == lutConfig) || (MAB_B_CURVE_ONLY == lutConfig) || (MAB_A_CLUT_B_COMBO == lutConfig) || (MBA_B_CLUT_A_COMBO == lutConfig) || (MAB_A_CLUT_M_MATRIX_B_COMBO == lutConfig) || (MBA_B_MATRIX_M_CLUT_A_COMBO == lutConfig)) { for (i = 0; i < inputChans; i++) { if (PARA_TYPE_SIG == fut->itbl[i]->ParaCurve.nSig) { nParaParams = getNumParaParams(fut->itbl[i]->ParaCurve.nFunction); size += nParaParams * sizeof (Fixed_t) + CURVETYPE_HEADER; } else { iTableEntries = fut->itbl[i]->refTblEntries; size += (iTableEntries * tableSize) + CURVETYPE_HEADER; /* total input table entries */ } size = (size + 3) & ~3; } } if ((LUT_TYPE_UNKNOWN == lutConfig) || (MBA_B_CLUT_A_COMBO == lutConfig) || (MBA_B_MATRIX_M_CLUT_A_COMBO == lutConfig) || (MAB_A_CLUT_B_COMBO == lutConfig) || (MAB_A_CLUT_M_MATRIX_B_COMBO == lutConfig)) { gTableEntries = 0; for (i = 0; i < outputChans; i++) { gTableEntries += (fut->chan[0]->gtbl->tbl_size / sizeof (fut_gtbldat_t)); /* assume 8 bit grid tables */ } if ((PTTYPE_MAB2 == format) || (PTTYPE_MBA2 == format)) { gTableEntries *= 2; /* 16 bit grid tables */ } size += gTableEntries; size += CLUT_HEADER; size = (size + 3) & ~3; } if ((LUT_TYPE_UNKNOWN == lutConfig) || (MBA_B_CURVE_ONLY == lutConfig) || (MAB_A_CLUT_B_COMBO == lutConfig) || (MBA_B_CLUT_A_COMBO == lutConfig) || (MAB_A_CLUT_M_MATRIX_B_COMBO == lutConfig) || (MBA_B_MATRIX_M_CLUT_A_COMBO == lutConfig)) { for (i = 0; i < outputChans; i++) { if (PARA_TYPE_SIG == fut->chan[i]->otbl->ParaCurve.nSig) { nParaParams = getNumParaParams(fut->chan[i]->otbl->ParaCurve.nFunction); size += nParaParams * sizeof (Fixed_t) + CURVETYPE_HEADER; } else { oTableEntries = fut->chan[i]->otbl->refTblEntries; size += (oTableEntries * tableSize + CURVETYPE_HEADER); /* plus total output table entries */ } size = (size + 3) & ~3; } } if ((MBA_B_MATRIX_M_CLUT_A_COMBO == lutConfig) || (MBA_B_MATRIX_M_COMBO == lutConfig) || (MAB_M_MATRIX_B_COMBO == lutConfig)) { for (i = 0; i < FUT_NMCHAN; i++) { if (PARA_TYPE_SIG == fut->mabInParaCurve[i].nSig) { nParaParams = getNumParaParams(fut->mabInParaCurve[i].nFunction); size += nParaParams * sizeof (Fixed_t) + CURVETYPE_HEADER; } else { iTableEntries = fut->mabInTblEntries[i]; size += (iTableEntries * tableSize) + CURVETYPE_HEADER; /* plus total matrix inputput table entries */ } size = (size + 3) & ~3; } } if ((MAB_A_CLUT_M_MATRIX_B_COMBO == lutConfig) || (MBA_B_MATRIX_M_COMBO == lutConfig) || (MAB_M_MATRIX_B_COMBO == lutConfig)) { for (i = 0; i < FUT_NMCHAN; i++) { if (PARA_TYPE_SIG == fut->mabOutParaCurve[i].nSig) { nParaParams = getNumParaParams(fut->mabOutParaCurve[i].nFunction); size += nParaParams * sizeof (Fixed_t) + CURVETYPE_HEADER; } else { oTableEntries = fut->mabOutTblEntries[i]; size += (oTableEntries * tableSize) + CURVETYPE_HEADER; /* plus total matrix outputput table entries */ } size = (size + 3) & ~3; } } fut_free_mftdat (fut); /* free the made data tables */ break; default: break; } errnum = unlockPT (PTHdr, fut); if (errnum != KCP_SUCCESS) { size = 0; } } return (size); }
PTErr_t makeForwardXformMono ( ResponseRecord_p grayTRC, fut_p theFut) { PTErr_t PTErr = KCP_FAILURE; KpInt32_t futReturn, i1; fut_otbldat_p otblDat; double gamma; fut_calcData_t calcData; KpUInt16_t rrpData[2] = { 0, RRECORD_DATA_SIZE -1 }; ResponseRecord_t rrt; KpUInt16_t *pCurveData = NULL; /* compute new table entries */ calcData.chan = 0; /* always uses 1st input chan */ for (i1 = 0; i1 < FWD_MONO_OCHANS; i1++) { if (( ! IS_CHAN(theFut->chan[i1])) || !fut_calc_gtblEx (theFut->chan[i1]->gtbl, fut_grampEx, &calcData) || !fut_calc_otblEx (theFut->chan[i1]->otbl, otblFunc, NULL)) { goto ErrOut0; } } /* get address of the first output table */ futReturn = fut_get_otbl (theFut, 0, &otblDat); if ((futReturn != 1) || (otblDat == (fut_otbldat_p)NULL)) { goto ErrOut0; } if (PARA_TYPE_SIG == grayTRC->TagSig) { pCurveData = (KpUInt16_p) allocBufferPtr (MFV_CURVE_TBL_ENT); /* get memory for curve data */ if (NULL == pCurveData) { return KCP_NO_MEMORY; } makeCurveFromPara (grayTRC->ParaFunction, grayTRC->ParaParams, pCurveData, MFV_CURVE_TBL_ENT); grayTRC->CurveCount = MFV_CURVE_TBL_ENT; grayTRC->CurveData = pCurveData; } /* setup the output table */ switch (grayTRC->CurveCount) { case 0: /* setup the responseRecord struct */ rrt.CurveCount = 2; rrt.CurveData = rrpData; /* make the output table */ PTErr = calcOtblLSN (otblDat, &rrt); break; case 1: gamma = (double)grayTRC->CurveData[0] / SCALEDOT8; if (gamma <= 0.0) { goto ErrOut0; } /* make the output table */ PTErr = calcOtblLS1 (otblDat, gamma); break; default: /* make the output table */ makeMonotonic (grayTRC->CurveCount, grayTRC->CurveData); PTErr = calcOtblLSN (otblDat, grayTRC); } GetOut: if (NULL != pCurveData) { freeBufferPtr (pCurveData); } return PTErr; ErrOut0: PTErr = KCP_SYSERR_0; goto GetOut; }
/*--------------------------------------------------------------------------- * 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; }