| File: | src/mite/txf.c |
| Location: | line 287, column 17 |
| Description: | Access to field 'table' results in a dereference of a null pointer (loaded from field 'kind') |
| 1 | /* | |||
| 2 | Teem: Tools to process and visualize scientific data and images . | |||
| 3 | Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago | |||
| 4 | Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann | |||
| 5 | Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah | |||
| 6 | ||||
| 7 | This library is free software; you can redistribute it and/or | |||
| 8 | modify it under the terms of the GNU Lesser General Public License | |||
| 9 | (LGPL) as published by the Free Software Foundation; either | |||
| 10 | version 2.1 of the License, or (at your option) any later version. | |||
| 11 | The terms of redistributing and/or modifying this software also | |||
| 12 | include exceptions to the LGPL that facilitate static linking. | |||
| 13 | ||||
| 14 | This library is distributed in the hope that it will be useful, | |||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 17 | Lesser General Public License for more details. | |||
| 18 | ||||
| 19 | You should have received a copy of the GNU Lesser General Public License | |||
| 20 | along with this library; if not, write to Free Software Foundation, Inc., | |||
| 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| 22 | */ | |||
| 23 | ||||
| 24 | /* learned: don't confuse allocate an array of structs with an array | |||
| 25 | of pointers to structs. Don't be surprised when you bus error | |||
| 26 | because of the difference | |||
| 27 | */ | |||
| 28 | ||||
| 29 | #include "mite.h" | |||
| 30 | #include "privateMite.h" | |||
| 31 | ||||
| 32 | char | |||
| 33 | miteRangeChar[MITE_RANGE_NUM9+1] = "ARGBEadsp"; | |||
| 34 | ||||
| 35 | const char * | |||
| 36 | _miteStageOpStr[] = { | |||
| 37 | "(unknown miteStageOp)", | |||
| 38 | "min", | |||
| 39 | "max", | |||
| 40 | "add", | |||
| 41 | "multiply" | |||
| 42 | }; | |||
| 43 | ||||
| 44 | const int | |||
| 45 | _miteStageOpVal[] = { | |||
| 46 | miteStageOpUnknown, | |||
| 47 | miteStageOpMin, | |||
| 48 | miteStageOpMax, | |||
| 49 | miteStageOpAdd, | |||
| 50 | miteStageOpMultiply | |||
| 51 | }; | |||
| 52 | ||||
| 53 | const char * | |||
| 54 | _miteStageOpStrEqv[] = { | |||
| 55 | "min", | |||
| 56 | "max", | |||
| 57 | "add", "+", | |||
| 58 | "multiply", "*", "x", | |||
| 59 | "" | |||
| 60 | }; | |||
| 61 | ||||
| 62 | const int | |||
| 63 | _miteStageOpValEqv[] = { | |||
| 64 | miteStageOpMin, | |||
| 65 | miteStageOpMax, | |||
| 66 | miteStageOpAdd, miteStageOpAdd, | |||
| 67 | miteStageOpMultiply, miteStageOpMultiply, miteStageOpMultiply | |||
| 68 | }; | |||
| 69 | ||||
| 70 | const airEnum | |||
| 71 | _miteStageOp = { | |||
| 72 | "miteStageOp", | |||
| 73 | MITE_STAGE_OP_MAX4, | |||
| 74 | _miteStageOpStr, _miteStageOpVal, | |||
| 75 | NULL((void*)0), | |||
| 76 | _miteStageOpStrEqv, _miteStageOpValEqv, | |||
| 77 | AIR_FALSE0 | |||
| 78 | }; | |||
| 79 | const airEnum *const | |||
| 80 | miteStageOp = &_miteStageOp; | |||
| 81 | ||||
| 82 | /* | |||
| 83 | ******** miteVariableParse() | |||
| 84 | ** | |||
| 85 | ** takes a string (usually the label from a nrrd axis) and parses it | |||
| 86 | ** to determine the gageItemSpec from it (which means finding the | |||
| 87 | ** kind and item). The valid formats are: | |||
| 88 | ** | |||
| 89 | ** "" : NULL kind, 0 item | |||
| 90 | ** <item> : miteValGageKind (DEPRECATED) | |||
| 91 | ** mite(<item>) : miteValGageKind | |||
| 92 | ** gage(<item>) : gageKindScl (DEPRECATED) | |||
| 93 | ** gage(scalar:<item>) : gageKindScl | |||
| 94 | ** gage(vector:<item>) : gageKindVec | |||
| 95 | ** gage(tensor:<item>) : tenGageKind | |||
| 96 | ** | |||
| 97 | ** Notice that "scalar", "vector", and "tensor" do NOT refer to the type | |||
| 98 | ** of the quantity being measured, but rather to the type of volume in | |||
| 99 | ** which quantity is measured (i.e., the gageKind used) | |||
| 100 | */ | |||
| 101 | int | |||
| 102 | miteVariableParse(gageItemSpec *isp, const char *label) { | |||
| 103 | static const char me[]="miteVariableParse"; | |||
| 104 | ||||
| 105 | char *buff, *endparen, *kqstr, *col, *kstr, *qstr; | |||
| 106 | airArray *mop; | |||
| 107 | ||||
| 108 | if (!( isp && label )) { | |||
| 109 | biffAddf(MITEmiteBiffKey, "%s: got NULL pointer", me); | |||
| 110 | return 1; | |||
| 111 | } | |||
| 112 | if (0 == strlen(label)) { | |||
| 113 | /* nothing was specified; we try to indicate that by mimicking | |||
| 114 | the return of gageItemSpecNew() */ | |||
| 115 | isp->item = 0; | |||
| 116 | isp->kind = NULL((void*)0); | |||
| 117 | return 0; | |||
| 118 | } | |||
| 119 | /* else given string was non-empty */ | |||
| 120 | mop = airMopNew(); | |||
| 121 | buff = airStrdup(label); | |||
| 122 | if (!buff) { | |||
| 123 | biffAddf(MITEmiteBiffKey, "%s: couldn't strdup label!", me); | |||
| 124 | airMopError(mop); return 1; | |||
| 125 | } | |||
| 126 | airMopAdd(mop, buff, airFree, airMopAlways); | |||
| 127 | if (strstr(buff, "gage(") == buff) { | |||
| 128 | /* txf domain variable is to be measured directly by gage */ | |||
| 129 | if (!(endparen = strstr(buff, ")"))) { | |||
| 130 | biffAddf(MITEmiteBiffKey, "%s: didn't see close paren after \"gage(\"", me); | |||
| 131 | airMopError(mop); return 1; | |||
| 132 | } | |||
| 133 | *endparen = 0; | |||
| 134 | kqstr = buff + strlen("gage("); | |||
| 135 | /* first see if its a (deprecated) gageKindScl specification */ | |||
| 136 | isp->item = airEnumVal(gageScl, kqstr); | |||
| 137 | if (0 != isp->item) { | |||
| 138 | isp->kind = gageKindScl; | |||
| 139 | fprintf(stderr__stderrp, "\n%s: WARNING: deprecated use of txf domain " | |||
| 140 | "\"gage(%s)\" without explicit gage kind specification; " | |||
| 141 | "should use \"gage(%s:%s)\" instead\n\n", | |||
| 142 | me, kqstr, gageKindScl->name, kqstr); | |||
| 143 | } else { | |||
| 144 | /* should be of form "<kind>:<item>" */ | |||
| 145 | col = strstr(kqstr, ":"); | |||
| 146 | if (!col) { | |||
| 147 | biffAddf(MITEmiteBiffKey, "%s: didn't see \":\" separator between gage " | |||
| 148 | "kind and item", me); | |||
| 149 | airMopError(mop); return 1; | |||
| 150 | } | |||
| 151 | *col = 0; | |||
| 152 | kstr = kqstr; | |||
| 153 | qstr = col+1; | |||
| 154 | if (!strcmp(gageKindScl->name, kstr)) { | |||
| 155 | isp->kind = gageKindScl; | |||
| 156 | } else if (!strcmp(gageKindVec->name, kstr)) { | |||
| 157 | isp->kind = gageKindVec; | |||
| 158 | } else if (!strcmp(tenGageKind->name, kstr)) { | |||
| 159 | isp->kind = tenGageKind; | |||
| 160 | } else { | |||
| 161 | biffAddf(MITEmiteBiffKey, "%s: don't recognized \"%s\" gage kind", me, kstr); | |||
| 162 | airMopError(mop); return 1; | |||
| 163 | } | |||
| 164 | isp->item = airEnumVal(isp->kind->enm, qstr); | |||
| 165 | if (0 == isp->item) { | |||
| 166 | biffAddf(MITEmiteBiffKey, "%s: couldn't parse \"%s\" as a %s variable", | |||
| 167 | me, qstr, isp->kind->name); | |||
| 168 | airMopError(mop); return 1; | |||
| 169 | } | |||
| 170 | } | |||
| 171 | } else if (strstr(buff, "mite(") == buff) { | |||
| 172 | /* txf domain variable is *not* directly measured by gage */ | |||
| 173 | if (!(endparen = strstr(buff, ")"))) { | |||
| 174 | biffAddf(MITEmiteBiffKey, "%s: didn't see close paren after \"mite(\"", me); | |||
| 175 | airMopError(mop); return 1; | |||
| 176 | } | |||
| 177 | *endparen = 0; | |||
| 178 | qstr = buff + strlen("mite("); | |||
| 179 | isp->item = airEnumVal(miteVal, qstr); | |||
| 180 | if (0 == isp->item) { | |||
| 181 | biffAddf(MITEmiteBiffKey, "%s: couldn't parse \"%s\" as a miteVal variable", | |||
| 182 | me, qstr); | |||
| 183 | airMopError(mop); return 1; | |||
| 184 | } | |||
| 185 | isp->kind = miteValGageKind; | |||
| 186 | } else { | |||
| 187 | /* didn't start with "gage(" or "mite(" */ | |||
| 188 | isp->item = airEnumVal(miteVal, label); | |||
| 189 | if (0 != isp->item) { | |||
| 190 | /* its measured by mite */ | |||
| 191 | isp->kind = miteValGageKind; | |||
| 192 | fprintf(stderr__stderrp, "\n%s: WARNING: deprecated use of txf domain " | |||
| 193 | "\"%s\"; should use \"mite(%s)\" instead\n\n", | |||
| 194 | me, label, label); | |||
| 195 | } else { | |||
| 196 | biffAddf(MITEmiteBiffKey, "%s: \"%s\" not a recognized variable", me, label); | |||
| 197 | airMopError(mop); return 1; | |||
| 198 | } | |||
| 199 | } | |||
| 200 | airMopOkay(mop); | |||
| 201 | return 0; | |||
| 202 | } | |||
| 203 | ||||
| 204 | void | |||
| 205 | miteVariablePrint(char *buff, const gageItemSpec *isp) { | |||
| 206 | static const char me[]="miteVariablePrint"; | |||
| 207 | ||||
| 208 | if (!(isp->kind)) { | |||
| 209 | strcpy(buff, "")__builtin___strcpy_chk (buff, "", __builtin_object_size (buff , 2 > 1 ? 1 : 0)); | |||
| 210 | } else if (gageKindScl == isp->kind | |||
| 211 | || gageKindVec == isp->kind | |||
| 212 | || tenGageKind == isp->kind) { | |||
| 213 | sprintf(buff, "gage(%s:%s)", isp->kind->name,__builtin___sprintf_chk (buff, 0, __builtin_object_size (buff , 2 > 1 ? 1 : 0), "gage(%s:%s)", isp->kind->name, airEnumStr (isp->kind->enm, isp->item)) | |||
| 214 | airEnumStr(isp->kind->enm, isp->item))__builtin___sprintf_chk (buff, 0, __builtin_object_size (buff , 2 > 1 ? 1 : 0), "gage(%s:%s)", isp->kind->name, airEnumStr (isp->kind->enm, isp->item)); | |||
| 215 | } else if (miteValGageKind == isp->kind) { | |||
| 216 | sprintf(buff, "%s(%s)", isp->kind->name,__builtin___sprintf_chk (buff, 0, __builtin_object_size (buff , 2 > 1 ? 1 : 0), "%s(%s)", isp->kind->name, airEnumStr (isp->kind->enm, isp->item)) | |||
| 217 | airEnumStr(isp->kind->enm, isp->item))__builtin___sprintf_chk (buff, 0, __builtin_object_size (buff , 2 > 1 ? 1 : 0), "%s(%s)", isp->kind->name, airEnumStr (isp->kind->enm, isp->item)); | |||
| 218 | } else { | |||
| 219 | sprintf(buff, "(%s: unknown gageKind!)", me)__builtin___sprintf_chk (buff, 0, __builtin_object_size (buff , 2 > 1 ? 1 : 0), "(%s: unknown gageKind!)", me); | |||
| 220 | } | |||
| 221 | return; | |||
| 222 | } | |||
| 223 | ||||
| 224 | int | |||
| 225 | miteNtxfCheck(const Nrrd *ntxf) { | |||
| 226 | static const char me[]="miteNtxfCheck"; | |||
| 227 | char *rangeStr, *domStr; | |||
| 228 | gageItemSpec isp; | |||
| 229 | unsigned int rii, axi; | |||
| 230 | int ilog2; | |||
| 231 | ||||
| 232 | if (nrrdCheck(ntxf)) { | |||
| ||||
| 233 | biffMovef(MITEmiteBiffKey, NRRDnrrdBiffKey, "%s: basic nrrd validity check failed", me); | |||
| 234 | return 1; | |||
| 235 | } | |||
| 236 | if (!( nrrdTypeFloat == ntxf->type || | |||
| 237 | nrrdTypeDouble == ntxf->type || | |||
| 238 | nrrdTypeUChar == ntxf->type )) { | |||
| 239 | biffAddf(MITEmiteBiffKey, "%s: need a type %s, %s or %s nrrd (not %s)", me, | |||
| 240 | airEnumStr(nrrdType, nrrdTypeFloat), | |||
| 241 | airEnumStr(nrrdType, nrrdTypeDouble), | |||
| 242 | airEnumStr(nrrdType, nrrdTypeUChar), | |||
| 243 | airEnumStr(nrrdType, ntxf->type)); | |||
| 244 | return 1; | |||
| 245 | } | |||
| 246 | if (!( 2 <= ntxf->dim )) { | |||
| 247 | biffAddf(MITEmiteBiffKey, "%s: nrrd dim (%d) isn't at least 2 (for a 1-D txf)", | |||
| 248 | me, ntxf->dim); | |||
| 249 | return 1; | |||
| 250 | } | |||
| 251 | rangeStr = ntxf->axis[0].label; | |||
| 252 | if (0 == airStrlen(rangeStr)) { | |||
| 253 | biffAddf(MITEmiteBiffKey, "%s: axis[0]'s label doesn't specify txf range", me); | |||
| 254 | return 1; | |||
| 255 | } | |||
| 256 | if (airStrlen(rangeStr) != ntxf->axis[0].size) { | |||
| 257 | char stmp1[AIR_STRLEN_SMALL(128+1)], stmp2[AIR_STRLEN_SMALL(128+1)]; | |||
| 258 | biffAddf(MITEmiteBiffKey, "%s: axis[0]'s size %s, but label specifies %s values", me, | |||
| 259 | airSprintSize_t(stmp1, ntxf->axis[0].size), | |||
| 260 | airSprintSize_t(stmp2, airStrlen(rangeStr))); | |||
| 261 | return 1; | |||
| 262 | } | |||
| 263 | for (rii=0; rii<airStrlen(rangeStr); rii++) { | |||
| 264 | if (!strchr(miteRangeChar, rangeStr[rii])) { | |||
| 265 | biffAddf(MITEmiteBiffKey, "%s: char %d of axis[0]'s label (\"%c\") isn't a valid " | |||
| 266 | "transfer function range specifier (not in \"%s\")", | |||
| 267 | me, rii, rangeStr[rii], miteRangeChar); | |||
| 268 | return 1; | |||
| 269 | } | |||
| 270 | } | |||
| 271 | for (axi=1; axi<ntxf->dim; axi++) { | |||
| 272 | if (1 == ntxf->axis[axi].size) { | |||
| 273 | biffAddf(MITEmiteBiffKey, "%s: # samples on axis %d must be > 1", me, axi); | |||
| 274 | return 1; | |||
| 275 | } | |||
| 276 | domStr = ntxf->axis[axi].label; | |||
| 277 | if (0 == airStrlen(domStr)) { | |||
| 278 | biffAddf(MITEmiteBiffKey, "%s: axis[%d] of txf didn't specify a domain variable", | |||
| 279 | me, axi); | |||
| 280 | return 1; | |||
| 281 | } | |||
| 282 | if (miteVariableParse(&isp, domStr)) { | |||
| 283 | biffAddf(MITEmiteBiffKey, "%s: couldn't parse txf domain \"%s\" for axis %d\n", | |||
| 284 | me, domStr, axi); | |||
| 285 | return 1; | |||
| 286 | } | |||
| 287 | if (!( 1 == isp.kind->table[isp.item].answerLength || | |||
| ||||
| 288 | 3 == isp.kind->table[isp.item].answerLength )) { | |||
| 289 | biffAddf(MITEmiteBiffKey, "%s: %s (item %d) not a scalar or vector " | |||
| 290 | "(answerLength = %d): " | |||
| 291 | "can't be a txf domain variable", me, domStr, isp.item, | |||
| 292 | isp.kind->table[isp.item].answerLength); | |||
| 293 | return 1; | |||
| 294 | } | |||
| 295 | if (3 == isp.kind->table[isp.item].answerLength) { | |||
| 296 | /* has to be right length for one of the quantization schemes */ | |||
| 297 | ilog2 = airLog2(ntxf->axis[axi].size); | |||
| 298 | if (-1 == ilog2) { | |||
| 299 | char stmp[AIR_STRLEN_SMALL(128+1)]; | |||
| 300 | biffAddf(MITEmiteBiffKey, "%s: txf axis size for %s must be power of 2 (not %s)", | |||
| 301 | me, domStr, airSprintSize_t(stmp, ntxf->axis[axi].size)); | |||
| 302 | return 1; | |||
| 303 | } else { | |||
| 304 | if (!( AIR_IN_CL(8, ilog2, 16)((8) <= (ilog2) && (ilog2) <= (16)) )) { | |||
| 305 | biffAddf(MITEmiteBiffKey, "%s: log_2 of txf axis size for %s should be in " | |||
| 306 | "range [8,16] (not %d)", me, domStr, ilog2); | |||
| 307 | return 1; | |||
| 308 | } | |||
| 309 | } | |||
| 310 | } else { | |||
| 311 | if (!( AIR_EXISTS(ntxf->axis[axi].min)(((int)(!((ntxf->axis[axi].min) - (ntxf->axis[axi].min) )))) && | |||
| 312 | AIR_EXISTS(ntxf->axis[axi].max)(((int)(!((ntxf->axis[axi].max) - (ntxf->axis[axi].max) )))) )) { | |||
| 313 | biffAddf(MITEmiteBiffKey, "%s: min and max of axis %d aren't both set", me, axi); | |||
| 314 | return 1; | |||
| 315 | } | |||
| 316 | if (!( ntxf->axis[axi].min < ntxf->axis[axi].max )) { | |||
| 317 | biffAddf(MITEmiteBiffKey, "%s: min (%g) not less than max (%g) on axis %d", | |||
| 318 | me, ntxf->axis[axi].min, ntxf->axis[axi].max, axi); | |||
| 319 | return 1; | |||
| 320 | } | |||
| 321 | } | |||
| 322 | } | |||
| 323 | ||||
| 324 | return 0; | |||
| 325 | } | |||
| 326 | ||||
| 327 | /* | |||
| 328 | ******** miteQueryAdd() | |||
| 329 | ** | |||
| 330 | ** This looks a given gageItemSpec and sets the bits in the | |||
| 331 | ** gageKindScl and tenGageKind queries that are required to calculate | |||
| 332 | ** the quantity | |||
| 333 | ** | |||
| 334 | ** NOTE: This does NOT initialize the query{Scl,Vec,Ten}: it | |||
| 335 | ** just adds on new items to the existing queries | |||
| 336 | ** | |||
| 337 | ** HEY: this is really unfortunate: each new gage type use for | |||
| 338 | ** volume rendering in mite will have to explicitly added as | |||
| 339 | ** arguments here, which is part of the reason that mite may end | |||
| 340 | ** up explicitly depending on the libraries supplying those gageKinds | |||
| 341 | ** (like how mite now must depend on ten) | |||
| 342 | ** | |||
| 343 | ** The queryMite argument is a little odd- its not a real gage kind, | |||
| 344 | ** but we use it to organize which of the miteVal quantities we take | |||
| 345 | ** the time to compute in miteSample(). | |||
| 346 | */ | |||
| 347 | void | |||
| 348 | miteQueryAdd(gageQuery queryScl, gageQuery queryVec, | |||
| 349 | gageQuery queryTen, gageQuery queryMite, | |||
| 350 | gageItemSpec *isp) { | |||
| 351 | static const char me[]="miteQueryAdd"; | |||
| 352 | ||||
| 353 | if (NULL((void*)0) == isp->kind) { | |||
| 354 | /* nothing to add */ | |||
| 355 | } else if (gageKindScl == isp->kind) { | |||
| 356 | GAGE_QUERY_ITEM_ON(queryScl, isp->item)(queryScl[isp->item/8] |= (1 << (isp->item % 8))); | |||
| 357 | } else if (gageKindVec == isp->kind) { | |||
| 358 | GAGE_QUERY_ITEM_ON(queryVec, isp->item)(queryVec[isp->item/8] |= (1 << (isp->item % 8))); | |||
| 359 | } else if (tenGageKind == isp->kind) { | |||
| 360 | GAGE_QUERY_ITEM_ON(queryTen, isp->item)(queryTen[isp->item/8] |= (1 << (isp->item % 8))); | |||
| 361 | } else if (miteValGageKind == isp->kind) { | |||
| 362 | /* regardless of whether the mite query requires scl, vec, or ten | |||
| 363 | queries, we add it to the quantites that have to be computed | |||
| 364 | per-sample */ | |||
| 365 | GAGE_QUERY_ITEM_ON(queryMite, isp->item)(queryMite[isp->item/8] |= (1 << (isp->item % 8)) ); | |||
| 366 | /* HEY: some these have useful analogs for tensor data, but I | |||
| 367 | won't be able to express them. This means that while Phong | |||
| 368 | shading of *scalar* volumes can be implemented with transfer | |||
| 369 | functions, it is currently not possible in *tensor* volumes | |||
| 370 | (for instance, using the gradient of fractional anisotropy) */ | |||
| 371 | switch(isp->item) { | |||
| 372 | case miteValVrefN: | |||
| 373 | case miteValNdotV: | |||
| 374 | case miteValNdotL: | |||
| 375 | /* the "N" can be a normalized vector from any of the | |||
| 376 | available kinds (except miteValGageKind!), and its | |||
| 377 | associated query will be handled elsewhere, so there's | |||
| 378 | nothing to add here */ | |||
| 379 | break; | |||
| 380 | case miteValGTdotV: | |||
| 381 | GAGE_QUERY_ITEM_ON(queryScl, gageSclGeomTens)(queryScl[gageSclGeomTens/8] |= (1 << (gageSclGeomTens % 8))); | |||
| 382 | break; | |||
| 383 | case miteValVdefT: | |||
| 384 | GAGE_QUERY_ITEM_ON(queryTen, tenGageTensor)(queryTen[tenGageTensor/8] |= (1 << (tenGageTensor % 8) )); | |||
| 385 | case miteValVdefTdotV: | |||
| 386 | GAGE_QUERY_ITEM_ON(queryTen, tenGageTensor)(queryTen[tenGageTensor/8] |= (1 << (tenGageTensor % 8) )); | |||
| 387 | break; | |||
| 388 | } | |||
| 389 | } else { | |||
| 390 | fprintf(stderr__stderrp, "%s: PANIC: unrecognized non-NULL gageKind\n", me); | |||
| 391 | exit(1); | |||
| 392 | } | |||
| 393 | return; | |||
| 394 | } | |||
| 395 | ||||
| 396 | int | |||
| 397 | _miteNtxfCopy(miteRender *mrr, miteUser *muu) { | |||
| 398 | static const char me[]="_miteNtxfCopy"; | |||
| 399 | int ni, E; | |||
| 400 | ||||
| 401 | mrr->ntxf = AIR_CALLOC(muu->ntxfNum, Nrrd *)(Nrrd **)(calloc((muu->ntxfNum), sizeof(Nrrd *))); | |||
| 402 | if (!mrr->ntxf) { | |||
| 403 | biffAddf(MITEmiteBiffKey, "%s: couldn't calloc %d ntxf pointers", me, muu->ntxfNum); | |||
| 404 | return 1; | |||
| 405 | } | |||
| 406 | mrr->ntxfNum = muu->ntxfNum; | |||
| 407 | airMopAdd(mrr->rmop, mrr->ntxf, airFree, airMopAlways); | |||
| 408 | E = 0; | |||
| 409 | for (ni=0; ni<mrr->ntxfNum; ni++) { | |||
| 410 | mrr->ntxf[ni] = nrrdNew(); | |||
| 411 | if (!E) airMopAdd(mrr->rmop, mrr->ntxf[ni], | |||
| 412 | (airMopper)nrrdNuke, airMopAlways); | |||
| 413 | if (!( nrrdTypeUChar == muu->ntxf[ni]->type | |||
| 414 | || nrrdTypeFloat == muu->ntxf[ni]->type | |||
| 415 | || nrrdTypeDouble == muu->ntxf[ni]->type )) { | |||
| 416 | biffAddf(MITEmiteBiffKey, | |||
| 417 | "%s: sorry, can't handle txf of type %s (only %s, %s, %s)", | |||
| 418 | me, airEnumStr(nrrdType, muu->ntxf[ni]->type), | |||
| 419 | airEnumStr(nrrdType, nrrdTypeUChar), | |||
| 420 | airEnumStr(nrrdType, nrrdTypeFloat), | |||
| 421 | airEnumStr(nrrdType, nrrdTypeDouble)); | |||
| 422 | return 1; | |||
| 423 | } | |||
| 424 | /* note that key/values need to be copied for the sake of | |||
| 425 | identifying a non-default miteStageOp */ | |||
| 426 | switch(muu->ntxf[ni]->type) { | |||
| 427 | case nrrdTypeUChar: | |||
| 428 | if (!E) E |= nrrdUnquantize(mrr->ntxf[ni], muu->ntxf[ni], nrrdTypeUChar); | |||
| 429 | if (!E) E |= nrrdKeyValueCopy(mrr->ntxf[ni], muu->ntxf[ni]); | |||
| 430 | break; | |||
| 431 | case mite_ntnrrdTypeDouble: | |||
| 432 | if (!E) E |= nrrdCopy(mrr->ntxf[ni], muu->ntxf[ni]); | |||
| 433 | break; | |||
| 434 | default: /* will be either float or double (whatever mite_nt isn't) */ | |||
| 435 | if (!E) E |= nrrdConvert(mrr->ntxf[ni], muu->ntxf[ni], mite_ntnrrdTypeDouble); | |||
| 436 | if (!E) E |= nrrdKeyValueCopy(mrr->ntxf[ni], muu->ntxf[ni]); | |||
| 437 | break; | |||
| 438 | } | |||
| 439 | } | |||
| 440 | if (E) { | |||
| 441 | biffMovef(MITEmiteBiffKey, NRRDnrrdBiffKey, "%s: troubling copying/converting all ntxfs", me); | |||
| 442 | return 1; | |||
| 443 | } | |||
| 444 | return 0; | |||
| 445 | } | |||
| 446 | ||||
| 447 | int | |||
| 448 | _miteNtxfAlphaAdjust(miteRender *mrr, miteUser *muu) { | |||
| 449 | static const char me[]="_miteNtxfAlphaAdjust"; | |||
| 450 | int ni, ei, ri, nnum, rnum; | |||
| 451 | Nrrd *ntxf; | |||
| 452 | mite_t *data, alpha, frac; | |||
| 453 | ||||
| 454 | if (_miteNtxfCopy(mrr, muu)) { | |||
| 455 | biffAddf(MITEmiteBiffKey, "%s: trouble copying/converting transfer functions", me); | |||
| 456 | return 1; | |||
| 457 | } | |||
| 458 | frac = muu->rayStep/muu->refStep; | |||
| 459 | for (ni=0; ni<mrr->ntxfNum; ni++) { | |||
| 460 | ntxf = mrr->ntxf[ni]; | |||
| 461 | if (!strchr(ntxf->axis[0].label, miteRangeChar[miteRangeAlpha])) { | |||
| 462 | continue; | |||
| 463 | } | |||
| 464 | /* else this txf sets opacity */ | |||
| 465 | data = (mite_t *)ntxf->data; | |||
| 466 | rnum = ntxf->axis[0].size; | |||
| 467 | nnum = nrrdElementNumber(ntxf)/rnum; | |||
| 468 | for (ei=0; ei<nnum; ei++) { | |||
| 469 | for (ri=0; ri<rnum; ri++) { | |||
| 470 | if (ntxf->axis[0].label[ri] == miteRangeChar[miteRangeAlpha]) { | |||
| 471 | alpha = data[ri + rnum*ei]; | |||
| 472 | data[ri + rnum*ei] = 1 - pow(AIR_MAX(0, 1-alpha)((0) > (1-alpha) ? (0) : (1-alpha)), frac); | |||
| 473 | } | |||
| 474 | } | |||
| 475 | } | |||
| 476 | } | |||
| 477 | return 0; | |||
| 478 | } | |||
| 479 | ||||
| 480 | int | |||
| 481 | _miteStageNum(miteRender *mrr) { | |||
| 482 | int num, ni; | |||
| 483 | ||||
| 484 | num = 0; | |||
| 485 | for (ni=0; ni<mrr->ntxfNum; ni++) { | |||
| 486 | num += mrr->ntxf[ni]->dim - 1; | |||
| 487 | } | |||
| 488 | return num; | |||
| 489 | } | |||
| 490 | ||||
| 491 | void | |||
| 492 | _miteStageInit(miteStage *stage) { | |||
| 493 | int rii; | |||
| 494 | ||||
| 495 | stage->val = NULL((void*)0); | |||
| 496 | stage->size = -1; | |||
| 497 | stage->op = miteStageOpUnknown; | |||
| 498 | stage->qn = NULL((void*)0); | |||
| 499 | stage->min = stage->max = AIR_NAN(airFloatQNaN.f); | |||
| 500 | stage->data = NULL((void*)0); | |||
| 501 | for (rii=0; rii<=MITE_RANGE_NUM9-1; rii++) { | |||
| 502 | stage->rangeIdx[rii] = -1; | |||
| 503 | } | |||
| 504 | stage->rangeNum = -1; | |||
| 505 | stage->label = NULL((void*)0); | |||
| 506 | return; | |||
| 507 | } | |||
| 508 | ||||
| 509 | double * | |||
| 510 | _miteAnswerPointer(miteThread *mtt, gageItemSpec *isp) { | |||
| 511 | static const char me[]="_miteAnswerPointer"; | |||
| 512 | double *ret; | |||
| 513 | ||||
| 514 | if (!isp->kind) { | |||
| 515 | /* we got a NULL kind (as happens with output of | |||
| 516 | gageItemSpecNew(), or miteVariableParse of an | |||
| 517 | empty string); only NULL return is sensible */ | |||
| 518 | return NULL((void*)0); | |||
| 519 | } | |||
| 520 | ||||
| 521 | if (gageKindScl == isp->kind) { | |||
| 522 | ret = mtt->ansScl; | |||
| 523 | } else if (gageKindVec == isp->kind) { | |||
| 524 | ret = mtt->ansVec; | |||
| 525 | } else if (tenGageKind == isp->kind) { | |||
| 526 | ret = mtt->ansTen; | |||
| 527 | } else if (miteValGageKind == isp->kind) { | |||
| 528 | ret = mtt->ansMiteVal; | |||
| 529 | } else { | |||
| 530 | fprintf(stderr__stderrp, "\nPANIC: %s: unknown gageKind!\n", me); | |||
| 531 | exit(1); | |||
| 532 | } | |||
| 533 | ret += gageKindAnswerOffset(isp->kind, isp->item); | |||
| 534 | return ret; | |||
| 535 | } | |||
| 536 | ||||
| 537 | /* | |||
| 538 | ** _miteStageSet | |||
| 539 | ** | |||
| 540 | ** ALLOCATES and initializes stage array in a miteThread | |||
| 541 | */ | |||
| 542 | int | |||
| 543 | _miteStageSet(miteThread *mtt, miteRender *mrr) { | |||
| 544 | static const char me[]="_miteStageSet"; | |||
| 545 | char *value; | |||
| 546 | int ni, di, stageIdx, rii, stageNum, ilog2; | |||
| 547 | Nrrd *ntxf; | |||
| 548 | miteStage *stage; | |||
| 549 | gageItemSpec isp; | |||
| 550 | char rc; | |||
| 551 | ||||
| 552 | stageNum = _miteStageNum(mrr); | |||
| 553 | /* fprintf(stderr, "!%s: stageNum = %d\n", me, stageNum); */ | |||
| 554 | mtt->stage = AIR_CALLOC(stageNum, miteStage)(miteStage*)(calloc((stageNum), sizeof(miteStage))); | |||
| 555 | if (!mtt->stage) { | |||
| 556 | biffAddf(MITEmiteBiffKey, "%s: couldn't alloc array of %d stages", me, stageNum); | |||
| 557 | return 1; | |||
| 558 | } | |||
| 559 | airMopAdd(mtt->rmop, mtt->stage, airFree, airMopAlways); | |||
| 560 | mtt->stageNum = stageNum; | |||
| 561 | stageIdx = 0; | |||
| 562 | for (ni=0; ni<mrr->ntxfNum; ni++) { | |||
| 563 | ntxf = mrr->ntxf[ni]; | |||
| 564 | for (di=ntxf->dim-1; di>=1; di--) { | |||
| 565 | stage = mtt->stage + stageIdx; | |||
| 566 | _miteStageInit(stage); | |||
| 567 | miteVariableParse(&isp, ntxf->axis[di].label); | |||
| 568 | stage->val = _miteAnswerPointer(mtt, &isp); | |||
| 569 | stage->label = ntxf->axis[di].label; | |||
| 570 | /* | |||
| 571 | fprintf(stderr, "!%s: ans=%p + offset[%d]=%d == %p\n", me, | |||
| 572 | mtt->ans, dom, kind->ansOffset[dom], stage->val); | |||
| 573 | */ | |||
| 574 | stage->size = ntxf->axis[di].size; | |||
| 575 | stage->min = ntxf->axis[di].min; | |||
| 576 | stage->max = ntxf->axis[di].max; | |||
| 577 | if (di > 1) { | |||
| 578 | stage->data = NULL((void*)0); | |||
| 579 | } else { | |||
| 580 | stage->data = (mite_t *)ntxf->data; | |||
| 581 | value = nrrdKeyValueGet(ntxf, "miteStageOp"); | |||
| 582 | if (value) { | |||
| 583 | stage->op = airEnumVal(miteStageOp, value); | |||
| 584 | if (miteStageOpUnknown == stage->op) { | |||
| 585 | stage->op = miteStageOpMultiply; | |||
| 586 | } | |||
| 587 | } else { | |||
| 588 | stage->op = miteStageOpMultiply; | |||
| 589 | } | |||
| 590 | if (1 == isp.kind->table[isp.item].answerLength) { | |||
| 591 | stage->qn = NULL((void*)0); | |||
| 592 | } else if (3 == isp.kind->table[isp.item].answerLength) { | |||
| 593 | char stmp[AIR_STRLEN_SMALL(128+1)]; | |||
| 594 | ilog2 = airLog2(ntxf->axis[di].size); | |||
| 595 | switch(ilog2) { | |||
| 596 | case 8: stage->qn = limnVtoQN_d[ limnQN8octa]; break; | |||
| 597 | case 9: stage->qn = limnVtoQN_d[ limnQN9octa]; break; | |||
| 598 | case 10: stage->qn = limnVtoQN_d[limnQN10octa]; break; | |||
| 599 | case 11: stage->qn = limnVtoQN_d[limnQN11octa]; break; | |||
| 600 | case 12: stage->qn = limnVtoQN_d[limnQN12octa]; break; | |||
| 601 | case 13: stage->qn = limnVtoQN_d[limnQN13octa]; break; | |||
| 602 | case 14: stage->qn = limnVtoQN_d[limnQN14octa]; break; | |||
| 603 | case 15: stage->qn = limnVtoQN_d[limnQN15octa]; break; | |||
| 604 | case 16: stage->qn = limnVtoQN_d[limnQN16octa]; break; | |||
| 605 | default: | |||
| 606 | biffAddf(MITEmiteBiffKey, "%s: txf axis %d size %s not usable for " | |||
| 607 | "vector txf domain variable %s", me, di, | |||
| 608 | airSprintSize_t(stmp, ntxf->axis[di].size), | |||
| 609 | ntxf->axis[di].label); | |||
| 610 | return 1; | |||
| 611 | break; | |||
| 612 | } | |||
| 613 | } else { | |||
| 614 | biffAddf(MITEmiteBiffKey, "%s: %s not scalar or vector (len = %d): can't be " | |||
| 615 | "a txf domain variable", me, | |||
| 616 | ntxf->axis[di].label, | |||
| 617 | isp.kind->table[isp.item].answerLength); | |||
| 618 | return 1; | |||
| 619 | } | |||
| 620 | stage->rangeNum = ntxf->axis[0].size; | |||
| 621 | for (rii=0; rii<stage->rangeNum; rii++) { | |||
| 622 | rc = ntxf->axis[0].label[rii]; | |||
| 623 | stage->rangeIdx[rii] = strchr(miteRangeChar, rc) - miteRangeChar; | |||
| 624 | /* | |||
| 625 | fprintf(stderr, "!%s: range: %c -> %d\n", "_miteStageSet", | |||
| 626 | ntxf->axis[0].label[rii], stage->rangeIdx[rii]); | |||
| 627 | */ | |||
| 628 | } | |||
| 629 | } | |||
| 630 | stageIdx++; | |||
| 631 | } | |||
| 632 | } | |||
| 633 | return 0; | |||
| 634 | } | |||
| 635 | ||||
| 636 | void | |||
| 637 | _miteStageRun(miteThread *mtt, miteUser *muu) { | |||
| 638 | static const char me[]="_miteStageRun"; | |||
| 639 | int stageIdx, ri, rii; | |||
| 640 | unsigned int txfIdx, finalIdx; | |||
| 641 | miteStage *stage; | |||
| 642 | mite_t *rangeData; | |||
| 643 | double *dbg=NULL((void*)0); | |||
| 644 | ||||
| 645 | finalIdx = 0; | |||
| 646 | if (mtt->verbose) { | |||
| 647 | dbg = muu->debug + muu->debugIdx; | |||
| 648 | } | |||
| 649 | for (stageIdx=0; stageIdx<mtt->stageNum; stageIdx++) { | |||
| 650 | stage = &(mtt->stage[stageIdx]); | |||
| 651 | if (stage->qn) { | |||
| 652 | /* its a vector-valued txf domain variable */ | |||
| 653 | txfIdx = stage->qn(stage->val); | |||
| 654 | /* right now, we can't store vector-valued txf domain variables */ | |||
| 655 | } else { | |||
| 656 | /* its a scalar txf domain variable */ | |||
| 657 | txfIdx = airIndexClamp(stage->min, *(stage->val), | |||
| 658 | stage->max, stage->size); | |||
| 659 | if (mtt->verbose) { | |||
| 660 | fprintf(stderr__stderrp, "!%s: %s=%g in [%g,%g]/%u -> %u\n", me, | |||
| 661 | stage->label, *(stage->val), | |||
| 662 | stage->min, stage->max, stage->size, txfIdx); | |||
| 663 | dbg[0 + 2*stageIdx] = *(stage->val); | |||
| 664 | } | |||
| 665 | } | |||
| 666 | finalIdx = stage->size*finalIdx + txfIdx; | |||
| 667 | if (mtt->verbose) { | |||
| 668 | dbg[1 + 2*stageIdx] = txfIdx; | |||
| 669 | } | |||
| 670 | if (stage->data) { | |||
| 671 | rangeData = stage->data + stage->rangeNum*finalIdx; | |||
| 672 | for (rii=0; rii<stage->rangeNum; rii++) { | |||
| 673 | ri = stage->rangeIdx[rii]; | |||
| 674 | switch(stage->op) { | |||
| 675 | case miteStageOpMin: | |||
| 676 | mtt->range[ri] = AIR_MIN(mtt->range[ri], rangeData[rii])((mtt->range[ri]) < (rangeData[rii]) ? (mtt->range[ri ]) : (rangeData[rii])); | |||
| 677 | break; | |||
| 678 | case miteStageOpMax: | |||
| 679 | mtt->range[ri] = AIR_MAX(mtt->range[ri], rangeData[rii])((mtt->range[ri]) > (rangeData[rii]) ? (mtt->range[ri ]) : (rangeData[rii])); | |||
| 680 | break; | |||
| 681 | case miteStageOpAdd: | |||
| 682 | mtt->range[ri] += rangeData[rii]; | |||
| 683 | break; | |||
| 684 | case miteStageOpMultiply: | |||
| 685 | default: | |||
| 686 | mtt->range[ri] *= rangeData[rii]; | |||
| 687 | break; | |||
| 688 | } | |||
| 689 | } | |||
| 690 | finalIdx = 0; | |||
| 691 | } | |||
| 692 | } | |||
| 693 | return; | |||
| 694 | } |