| File: | src/hoover/rays.c |
| Location: | line 471, column 16 |
| Description: | The left operand of '!=' is a garbage value |
| 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 | #include "hoover.h" | |||
| 25 | ||||
| 26 | /* | |||
| 27 | ** learned: if you're going to "simplify" code which computes some | |||
| 28 | ** floating point value within a loop using AFFINE() on the loop | |||
| 29 | ** control variable, by simply incrementing that value with the | |||
| 30 | ** correct amount iteration, BE SURE THAT THE INCREMENTING IS DONE in | |||
| 31 | ** every possible control path of the loop (wasn't incrementing ray | |||
| 32 | ** sample position if first sample wasn't inside the volume) | |||
| 33 | */ | |||
| 34 | ||||
| 35 | /* | |||
| 36 | ** _hooverLearnLengths() | |||
| 37 | ** | |||
| 38 | ** This is where we enforce the constraint that the volume always fit | |||
| 39 | ** inside a cube with edge length 2, centered at the origin. | |||
| 40 | ** | |||
| 41 | ** volHLen[i] is the HALF the length of the volume along axis i | |||
| 42 | ** | |||
| 43 | ** NOTE: none of this comes into play if we have ctx->shape | |||
| 44 | */ | |||
| 45 | void | |||
| 46 | _hooverLearnLengths(double volHLen[3], double voxLen[3], hooverContext *ctx) { | |||
| 47 | double maxLen; | |||
| 48 | int numSamples[3], numElements[3]; | |||
| 49 | ||||
| 50 | ELL_3V_COPY(numSamples, ctx->volSize)((numSamples)[0] = (ctx->volSize)[0], (numSamples)[1] = (ctx ->volSize)[1], (numSamples)[2] = (ctx->volSize)[2]); | |||
| 51 | if (nrrdCenterNode == ctx->volCentering) { | |||
| 52 | numElements[0] = numSamples[0]-1; | |||
| 53 | numElements[1] = numSamples[1]-1; | |||
| 54 | numElements[2] = numSamples[2]-1; | |||
| 55 | } else { | |||
| 56 | numElements[0] = numSamples[0]; | |||
| 57 | numElements[1] = numSamples[1]; | |||
| 58 | numElements[2] = numSamples[2]; | |||
| 59 | } | |||
| 60 | volHLen[0] = numElements[0]*ctx->volSpacing[0]; | |||
| 61 | volHLen[1] = numElements[1]*ctx->volSpacing[1]; | |||
| 62 | volHLen[2] = numElements[2]*ctx->volSpacing[2]; | |||
| 63 | maxLen = AIR_MAX(volHLen[0], volHLen[1])((volHLen[0]) > (volHLen[1]) ? (volHLen[0]) : (volHLen[1]) ); | |||
| 64 | maxLen = AIR_MAX(volHLen[2], maxLen)((volHLen[2]) > (maxLen) ? (volHLen[2]) : (maxLen)); | |||
| 65 | volHLen[0] /= maxLen; | |||
| 66 | volHLen[1] /= maxLen; | |||
| 67 | volHLen[2] /= maxLen; | |||
| 68 | voxLen[0] = 2*volHLen[0]/numElements[0]; | |||
| 69 | voxLen[1] = 2*volHLen[1]/numElements[1]; | |||
| 70 | voxLen[2] = 2*volHLen[2]/numElements[2]; | |||
| 71 | } | |||
| 72 | ||||
| 73 | /* | |||
| 74 | ** _hooverExtraContext struct | |||
| 75 | ** | |||
| 76 | ** Like hooverContext, this is READ-ONLY information which is not specific | |||
| 77 | ** to any thread. | |||
| 78 | ** Unlike hooverContext, it is solely for the benefit of the calculations | |||
| 79 | ** done in _hooverThreadBody. | |||
| 80 | ** | |||
| 81 | ** No one outside hoover should need to know about this. | |||
| 82 | */ | |||
| 83 | typedef struct { | |||
| 84 | double volHLen[3], /* length of x,y,z edges of volume bounding box */ | |||
| 85 | voxLen[3], /* length of x,y,z edges of voxels */ | |||
| 86 | uBase, uCap, /* uMin and uMax as seen on the near cutting plane */ | |||
| 87 | vBase, vCap, /* analogous to uBase and uCap */ | |||
| 88 | rayZero[3]; /* location of near plane, line of sight interxion */ | |||
| 89 | } _hooverExtraContext; | |||
| 90 | ||||
| 91 | _hooverExtraContext * | |||
| 92 | _hooverExtraContextNew(hooverContext *ctx) { | |||
| 93 | _hooverExtraContext *ec; | |||
| 94 | ||||
| 95 | ec = (_hooverExtraContext *)calloc(1, sizeof(_hooverExtraContext)); | |||
| 96 | if (ec) { | |||
| 97 | if (ctx->shape) { | |||
| 98 | ELL_3V_NAN_SET(ec->volHLen)( (ec->volHLen)[0] = (airFloatQNaN.f), (ec->volHLen)[1] = (airFloatQNaN.f), (ec->volHLen)[2] = (airFloatQNaN.f)); | |||
| 99 | ELL_3V_NAN_SET(ec->voxLen)( (ec->voxLen)[0] = (airFloatQNaN.f), (ec->voxLen)[1] = (airFloatQNaN.f), (ec->voxLen)[2] = (airFloatQNaN.f)); | |||
| 100 | } else { | |||
| 101 | _hooverLearnLengths(ec->volHLen, ec->voxLen, ctx); | |||
| 102 | } | |||
| 103 | ELL_3V_SCALE_ADD2(ec->rayZero,((ec->rayZero)[0] = (1.0)*(ctx->cam->from)[0] + (ctx ->cam->vspNeer)*(ctx->cam->N)[0], (ec->rayZero )[1] = (1.0)*(ctx->cam->from)[1] + (ctx->cam->vspNeer )*(ctx->cam->N)[1], (ec->rayZero)[2] = (1.0)*(ctx-> cam->from)[2] + (ctx->cam->vspNeer)*(ctx->cam-> N)[2]) | |||
| 104 | 1.0, ctx->cam->from,((ec->rayZero)[0] = (1.0)*(ctx->cam->from)[0] + (ctx ->cam->vspNeer)*(ctx->cam->N)[0], (ec->rayZero )[1] = (1.0)*(ctx->cam->from)[1] + (ctx->cam->vspNeer )*(ctx->cam->N)[1], (ec->rayZero)[2] = (1.0)*(ctx-> cam->from)[2] + (ctx->cam->vspNeer)*(ctx->cam-> N)[2]) | |||
| 105 | ctx->cam->vspNeer, ctx->cam->N)((ec->rayZero)[0] = (1.0)*(ctx->cam->from)[0] + (ctx ->cam->vspNeer)*(ctx->cam->N)[0], (ec->rayZero )[1] = (1.0)*(ctx->cam->from)[1] + (ctx->cam->vspNeer )*(ctx->cam->N)[1], (ec->rayZero)[2] = (1.0)*(ctx-> cam->from)[2] + (ctx->cam->vspNeer)*(ctx->cam-> N)[2]); | |||
| 106 | } | |||
| 107 | return ec; | |||
| 108 | } | |||
| 109 | ||||
| 110 | _hooverExtraContext * | |||
| 111 | _hooverExtraContextNix(_hooverExtraContext *ec) { | |||
| 112 | ||||
| 113 | if (ec) { | |||
| 114 | free(ec); | |||
| 115 | } | |||
| 116 | return NULL((void*)0); | |||
| 117 | } | |||
| 118 | ||||
| 119 | /* | |||
| 120 | ** _hooverThreadArg struct | |||
| 121 | ** | |||
| 122 | ** A pointer to this is passed to _hooverThreadBody. It contains all the | |||
| 123 | ** information which is not thread-specific, and all the thread-specific | |||
| 124 | ** information known at the level of hooverRender. | |||
| 125 | ** | |||
| 126 | ** For simplicity sake, a pointer to a struct of this type is also | |||
| 127 | ** returned from _hooverThreadBody, so this is where we store an | |||
| 128 | ** error-signaling return value (errCode), and what function had | |||
| 129 | ** trouble (whichErr). | |||
| 130 | */ | |||
| 131 | typedef struct { | |||
| 132 | /* ----------------------- input */ | |||
| 133 | hooverContext *ctx; | |||
| 134 | _hooverExtraContext *ec; | |||
| 135 | void *render; | |||
| 136 | int whichThread; | |||
| 137 | /* ----------------------- output */ | |||
| 138 | int whichErr; | |||
| 139 | int errCode; | |||
| 140 | } _hooverThreadArg; | |||
| 141 | ||||
| 142 | void * | |||
| 143 | _hooverThreadBody(void *_arg) { | |||
| 144 | _hooverThreadArg *arg; | |||
| 145 | void *thread; | |||
| 146 | int ret, /* to catch return values from callbacks */ | |||
| 147 | sampleI, /* which sample we're on */ | |||
| 148 | inside, /* we're inside the volume */ | |||
| 149 | vI, uI; /* integral coords in image */ | |||
| 150 | double tmp, | |||
| 151 | mm, /* lowest position in index space, for all axes */ | |||
| 152 | Mx, My, Mz, /* highest position in index space on each axis */ | |||
| 153 | u, v, /* floating-point coords in image */ | |||
| 154 | uvScale, /* how to scale (u,v) to go from image to | |||
| 155 | near plane, according to ortho or perspective */ | |||
| 156 | lx, ly, lz, /* half edge-lengths of volume */ | |||
| 157 | rayLen=0, /* length of segment formed by ray line intersecting | |||
| 158 | the near and far clipping planes */ | |||
| 159 | rayT, /* current position along ray (world-space) */ | |||
| 160 | rayDirW[3], /* unit-length ray direction (world-space) */ | |||
| 161 | rayDirI[3], /* rayDirW transformed into index space; | |||
| 162 | not unit length, but a unit change in | |||
| 163 | world space along rayDirW translates to | |||
| 164 | this change in index space along rayDirI */ | |||
| 165 | rayPosW[3], /* current ray location (world-space) */ | |||
| 166 | rayPosI[3], /* current ray location (index-space) */ | |||
| 167 | rayStartW[3], /* ray start on near plane (world-space) */ | |||
| 168 | rayStartI[3], /* ray start on near plane (index-space) */ | |||
| 169 | rayStep, /* distance between samples (world-space) */ | |||
| 170 | vOff[3], uOff[3]; /* offsets in arg->ec->wU and arg->ec->wV | |||
| 171 | directions towards start of ray */ | |||
| 172 | ||||
| 173 | arg = (_hooverThreadArg *)_arg; | |||
| 174 | if ( (ret = (arg->ctx->threadBegin)(&thread, | |||
| 175 | arg->render, | |||
| 176 | arg->ctx->user, | |||
| 177 | arg->whichThread)) ) { | |||
| 178 | arg->errCode = ret; | |||
| 179 | arg->whichErr = hooverErrThreadBegin; | |||
| 180 | return arg; | |||
| 181 | } | |||
| 182 | if (arg->ctx->shape) { | |||
| 183 | lx = ly = lz = AIR_NAN(airFloatQNaN.f); | |||
| 184 | if (nrrdCenterNode == arg->ctx->shape->center) { | |||
| 185 | mm = 0; | |||
| 186 | Mx = arg->ctx->shape->size[0]-1; | |||
| 187 | My = arg->ctx->shape->size[1]-1; | |||
| 188 | Mz = arg->ctx->shape->size[2]-1; | |||
| 189 | } else { | |||
| 190 | mm = -0.5; | |||
| 191 | Mx = arg->ctx->shape->size[0]-0.5; | |||
| 192 | My = arg->ctx->shape->size[1]-0.5; | |||
| 193 | Mz = arg->ctx->shape->size[2]-0.5; | |||
| 194 | } | |||
| 195 | } else { | |||
| 196 | lx = arg->ec->volHLen[0]; | |||
| 197 | ly = arg->ec->volHLen[1]; | |||
| 198 | lz = arg->ec->volHLen[2]; | |||
| 199 | if (nrrdCenterNode == arg->ctx->volCentering) { | |||
| 200 | mm = 0; | |||
| 201 | Mx = arg->ctx->volSize[0]-1; | |||
| 202 | My = arg->ctx->volSize[1]-1; | |||
| 203 | Mz = arg->ctx->volSize[2]-1; | |||
| 204 | } else { | |||
| 205 | mm = -0.5; | |||
| 206 | Mx = arg->ctx->volSize[0]-0.5; | |||
| 207 | My = arg->ctx->volSize[1]-0.5; | |||
| 208 | Mz = arg->ctx->volSize[2]-0.5; | |||
| 209 | } | |||
| 210 | } | |||
| 211 | ||||
| 212 | if (arg->ctx->cam->orthographic) { | |||
| 213 | ELL_3V_COPY(rayDirW, arg->ctx->cam->N)((rayDirW)[0] = (arg->ctx->cam->N)[0], (rayDirW)[1] = (arg->ctx->cam->N)[1], (rayDirW)[2] = (arg->ctx-> cam->N)[2]); | |||
| 214 | if (arg->ctx->shape) { | |||
| 215 | double zeroW[3], zeroI[3]; | |||
| 216 | ELL_3V_SET(zeroW, 0, 0, 0)((zeroW)[0] = (0), (zeroW)[1] = (0), (zeroW)[2] = (0)); | |||
| 217 | gageShapeWtoI(arg->ctx->shape, zeroI, zeroW); | |||
| 218 | gageShapeWtoI(arg->ctx->shape, rayDirI, rayDirW); | |||
| 219 | ELL_3V_SUB(rayDirI, rayDirI, zeroI)((rayDirI)[0] = (rayDirI)[0] - (zeroI)[0], (rayDirI)[1] = (rayDirI )[1] - (zeroI)[1], (rayDirI)[2] = (rayDirI)[2] - (zeroI)[2]); | |||
| 220 | } else { | |||
| 221 | rayDirI[0] = AIR_DELTA(-lx, rayDirW[0], lx, mm, Mx)( ((double)(Mx)-(mm))*((double)(rayDirW[0])) / ((double)(lx)- (-lx)) ); | |||
| 222 | rayDirI[1] = AIR_DELTA(-ly, rayDirW[1], ly, mm, My)( ((double)(My)-(mm))*((double)(rayDirW[1])) / ((double)(ly)- (-ly)) ); | |||
| 223 | rayDirI[2] = AIR_DELTA(-lz, rayDirW[2], lz, mm, Mz)( ((double)(Mz)-(mm))*((double)(rayDirW[2])) / ((double)(lz)- (-lz)) ); | |||
| 224 | } | |||
| 225 | rayLen = arg->ctx->cam->vspFaar - arg->ctx->cam->vspNeer; | |||
| 226 | uvScale = 1.0; | |||
| 227 | } else { | |||
| 228 | uvScale = arg->ctx->cam->vspNeer/arg->ctx->cam->vspDist; | |||
| 229 | } | |||
| 230 | ||||
| 231 | while (1) { | |||
| 232 | /* the work assignment is simply the next scanline to be rendered: | |||
| 233 | the result of all this is setting vI */ | |||
| 234 | if (arg->ctx->workMutex) { | |||
| 235 | airThreadMutexLock(arg->ctx->workMutex); | |||
| 236 | } | |||
| 237 | vI = arg->ctx->workIdx; | |||
| 238 | if (arg->ctx->workIdx < arg->ctx->imgSize[1]) { | |||
| 239 | arg->ctx->workIdx += 1; | |||
| 240 | } | |||
| 241 | if (arg->ctx->workMutex) { | |||
| 242 | airThreadMutexUnlock(arg->ctx->workMutex); | |||
| 243 | } | |||
| 244 | if (vI == arg->ctx->imgSize[1]) { | |||
| 245 | /* we're done! */ | |||
| 246 | break; | |||
| 247 | } | |||
| 248 | ||||
| 249 | if (nrrdCenterCell == arg->ctx->imgCentering) { | |||
| 250 | v = uvScale*AIR_AFFINE(-0.5, vI, arg->ctx->imgSize[1]-0.5,( ((double)(arg->ctx->cam->vRange[1])-(arg->ctx-> cam->vRange[0]))*((double)(vI)-(-0.5)) / ((double)(arg-> ctx->imgSize[1]-0.5)-(-0.5)) + (arg->ctx->cam->vRange [0])) | |||
| 251 | arg->ctx->cam->vRange[0],( ((double)(arg->ctx->cam->vRange[1])-(arg->ctx-> cam->vRange[0]))*((double)(vI)-(-0.5)) / ((double)(arg-> ctx->imgSize[1]-0.5)-(-0.5)) + (arg->ctx->cam->vRange [0])) | |||
| 252 | arg->ctx->cam->vRange[1])( ((double)(arg->ctx->cam->vRange[1])-(arg->ctx-> cam->vRange[0]))*((double)(vI)-(-0.5)) / ((double)(arg-> ctx->imgSize[1]-0.5)-(-0.5)) + (arg->ctx->cam->vRange [0])); | |||
| 253 | } else { | |||
| 254 | v = uvScale*AIR_AFFINE(0.0, vI, arg->ctx->imgSize[1]-1.0,( ((double)(arg->ctx->cam->vRange[1])-(arg->ctx-> cam->vRange[0]))*((double)(vI)-(0.0)) / ((double)(arg-> ctx->imgSize[1]-1.0)-(0.0)) + (arg->ctx->cam->vRange [0])) | |||
| 255 | arg->ctx->cam->vRange[0],( ((double)(arg->ctx->cam->vRange[1])-(arg->ctx-> cam->vRange[0]))*((double)(vI)-(0.0)) / ((double)(arg-> ctx->imgSize[1]-1.0)-(0.0)) + (arg->ctx->cam->vRange [0])) | |||
| 256 | arg->ctx->cam->vRange[1])( ((double)(arg->ctx->cam->vRange[1])-(arg->ctx-> cam->vRange[0]))*((double)(vI)-(0.0)) / ((double)(arg-> ctx->imgSize[1]-1.0)-(0.0)) + (arg->ctx->cam->vRange [0])); | |||
| 257 | } | |||
| 258 | ELL_3V_SCALE(vOff, v, arg->ctx->cam->V)((vOff)[0] = (v)*(arg->ctx->cam->V)[0], (vOff)[1] = ( v)*(arg->ctx->cam->V)[1], (vOff)[2] = (v)*(arg->ctx ->cam->V)[2]); | |||
| 259 | for (uI=0; uI<arg->ctx->imgSize[0]; uI++) { | |||
| 260 | if (nrrdCenterCell == arg->ctx->imgCentering) { | |||
| 261 | u = uvScale*AIR_AFFINE(-0.5, uI, arg->ctx->imgSize[0]-0.5,( ((double)(arg->ctx->cam->uRange[1])-(arg->ctx-> cam->uRange[0]))*((double)(uI)-(-0.5)) / ((double)(arg-> ctx->imgSize[0]-0.5)-(-0.5)) + (arg->ctx->cam->uRange [0])) | |||
| 262 | arg->ctx->cam->uRange[0],( ((double)(arg->ctx->cam->uRange[1])-(arg->ctx-> cam->uRange[0]))*((double)(uI)-(-0.5)) / ((double)(arg-> ctx->imgSize[0]-0.5)-(-0.5)) + (arg->ctx->cam->uRange [0])) | |||
| 263 | arg->ctx->cam->uRange[1])( ((double)(arg->ctx->cam->uRange[1])-(arg->ctx-> cam->uRange[0]))*((double)(uI)-(-0.5)) / ((double)(arg-> ctx->imgSize[0]-0.5)-(-0.5)) + (arg->ctx->cam->uRange [0])); | |||
| 264 | } else { | |||
| 265 | u = uvScale*AIR_AFFINE(0.0, uI, arg->ctx->imgSize[0]-1.0,( ((double)(arg->ctx->cam->uRange[1])-(arg->ctx-> cam->uRange[0]))*((double)(uI)-(0.0)) / ((double)(arg-> ctx->imgSize[0]-1.0)-(0.0)) + (arg->ctx->cam->uRange [0])) | |||
| 266 | arg->ctx->cam->uRange[0],( ((double)(arg->ctx->cam->uRange[1])-(arg->ctx-> cam->uRange[0]))*((double)(uI)-(0.0)) / ((double)(arg-> ctx->imgSize[0]-1.0)-(0.0)) + (arg->ctx->cam->uRange [0])) | |||
| 267 | arg->ctx->cam->uRange[1])( ((double)(arg->ctx->cam->uRange[1])-(arg->ctx-> cam->uRange[0]))*((double)(uI)-(0.0)) / ((double)(arg-> ctx->imgSize[0]-1.0)-(0.0)) + (arg->ctx->cam->uRange [0])); | |||
| 268 | } | |||
| 269 | ELL_3V_SCALE(uOff, u, arg->ctx->cam->U)((uOff)[0] = (u)*(arg->ctx->cam->U)[0], (uOff)[1] = ( u)*(arg->ctx->cam->U)[1], (uOff)[2] = (u)*(arg->ctx ->cam->U)[2]); | |||
| 270 | ELL_3V_ADD3(rayStartW, uOff, vOff, arg->ec->rayZero)((rayStartW)[0] = (uOff)[0] + (vOff)[0] + (arg->ec->rayZero )[0], (rayStartW)[1] = (uOff)[1] + (vOff)[1] + (arg->ec-> rayZero)[1], (rayStartW)[2] = (uOff)[2] + (vOff)[2] + (arg-> ec->rayZero)[2]); | |||
| 271 | if (arg->ctx->shape) { | |||
| 272 | gageShapeWtoI(arg->ctx->shape, rayStartI, rayStartW); | |||
| 273 | } else { | |||
| 274 | rayStartI[0] = AIR_AFFINE(-lx, rayStartW[0], lx, mm, Mx)( ((double)(Mx)-(mm))*((double)(rayStartW[0])-(-lx)) / ((double )(lx)-(-lx)) + (mm)); | |||
| 275 | rayStartI[1] = AIR_AFFINE(-ly, rayStartW[1], ly, mm, My)( ((double)(My)-(mm))*((double)(rayStartW[1])-(-ly)) / ((double )(ly)-(-ly)) + (mm)); | |||
| 276 | rayStartI[2] = AIR_AFFINE(-lz, rayStartW[2], lz, mm, Mz)( ((double)(Mz)-(mm))*((double)(rayStartW[2])-(-lz)) / ((double )(lz)-(-lz)) + (mm)); | |||
| 277 | } | |||
| 278 | if (!arg->ctx->cam->orthographic) { | |||
| 279 | ELL_3V_SUB(rayDirW, rayStartW, arg->ctx->cam->from)((rayDirW)[0] = (rayStartW)[0] - (arg->ctx->cam->from )[0], (rayDirW)[1] = (rayStartW)[1] - (arg->ctx->cam-> from)[1], (rayDirW)[2] = (rayStartW)[2] - (arg->ctx->cam ->from)[2]); | |||
| 280 | ELL_3V_NORM(rayDirW, rayDirW, tmp)(tmp = (sqrt((((rayDirW))[0]*((rayDirW))[0] + ((rayDirW))[1]* ((rayDirW))[1] + ((rayDirW))[2]*((rayDirW))[2]))), ((rayDirW) [0] = (1.0/tmp)*(rayDirW)[0], (rayDirW)[1] = (1.0/tmp)*(rayDirW )[1], (rayDirW)[2] = (1.0/tmp)*(rayDirW)[2])); | |||
| 281 | if (arg->ctx->shape) { | |||
| 282 | double zeroW[3], zeroI[3]; | |||
| 283 | ELL_3V_SET(zeroW, 0, 0, 0)((zeroW)[0] = (0), (zeroW)[1] = (0), (zeroW)[2] = (0)); | |||
| 284 | gageShapeWtoI(arg->ctx->shape, zeroI, zeroW); | |||
| 285 | gageShapeWtoI(arg->ctx->shape, rayDirI, rayDirW); | |||
| 286 | ELL_3V_SUB(rayDirI, rayDirI, zeroI)((rayDirI)[0] = (rayDirI)[0] - (zeroI)[0], (rayDirI)[1] = (rayDirI )[1] - (zeroI)[1], (rayDirI)[2] = (rayDirI)[2] - (zeroI)[2]); | |||
| 287 | } else { | |||
| 288 | rayDirI[0] = AIR_DELTA(-lx, rayDirW[0], lx, mm, Mx)( ((double)(Mx)-(mm))*((double)(rayDirW[0])) / ((double)(lx)- (-lx)) ); | |||
| 289 | rayDirI[1] = AIR_DELTA(-ly, rayDirW[1], ly, mm, My)( ((double)(My)-(mm))*((double)(rayDirW[1])) / ((double)(ly)- (-ly)) ); | |||
| 290 | rayDirI[2] = AIR_DELTA(-lz, rayDirW[2], lz, mm, Mz)( ((double)(Mz)-(mm))*((double)(rayDirW[2])) / ((double)(lz)- (-lz)) ); | |||
| 291 | } | |||
| 292 | rayLen = ((arg->ctx->cam->vspFaar - arg->ctx->cam->vspNeer)/ | |||
| 293 | ELL_3V_DOT(rayDirW, arg->ctx->cam->N)((rayDirW)[0]*(arg->ctx->cam->N)[0] + (rayDirW)[1]*( arg->ctx->cam->N)[1] + (rayDirW)[2]*(arg->ctx-> cam->N)[2])); | |||
| 294 | } | |||
| 295 | if ( (ret = (arg->ctx->rayBegin)(thread, | |||
| 296 | arg->render, | |||
| 297 | arg->ctx->user, | |||
| 298 | uI, vI, rayLen, | |||
| 299 | rayStartW, rayStartI, | |||
| 300 | rayDirW, rayDirI)) ) { | |||
| 301 | arg->errCode = ret; | |||
| 302 | arg->whichErr = hooverErrRayBegin; | |||
| 303 | return arg; | |||
| 304 | } | |||
| 305 | ||||
| 306 | sampleI = 0; | |||
| 307 | rayT = 0; | |||
| 308 | while (1) { | |||
| 309 | ELL_3V_SCALE_ADD2(rayPosW, 1.0, rayStartW, rayT, rayDirW)((rayPosW)[0] = (1.0)*(rayStartW)[0] + (rayT)*(rayDirW)[0], ( rayPosW)[1] = (1.0)*(rayStartW)[1] + (rayT)*(rayDirW)[1], (rayPosW )[2] = (1.0)*(rayStartW)[2] + (rayT)*(rayDirW)[2]); | |||
| 310 | if (arg->ctx->shape) { | |||
| 311 | gageShapeWtoI(arg->ctx->shape, rayPosI, rayPosW); | |||
| 312 | } else { | |||
| 313 | ELL_3V_SCALE_ADD2(rayPosI, 1.0, rayStartI, rayT, rayDirI)((rayPosI)[0] = (1.0)*(rayStartI)[0] + (rayT)*(rayDirI)[0], ( rayPosI)[1] = (1.0)*(rayStartI)[1] + (rayT)*(rayDirI)[1], (rayPosI )[2] = (1.0)*(rayStartI)[2] + (rayT)*(rayDirI)[2]); | |||
| 314 | } | |||
| 315 | inside = (AIR_IN_CL(mm, rayPosI[0], Mx)((mm) <= (rayPosI[0]) && (rayPosI[0]) <= (Mx)) && | |||
| 316 | AIR_IN_CL(mm, rayPosI[1], My)((mm) <= (rayPosI[1]) && (rayPosI[1]) <= (My)) && | |||
| 317 | AIR_IN_CL(mm, rayPosI[2], Mz)((mm) <= (rayPosI[2]) && (rayPosI[2]) <= (Mz))); | |||
| 318 | rayStep = (arg->ctx->sample)(thread, | |||
| 319 | arg->render, | |||
| 320 | arg->ctx->user, | |||
| 321 | sampleI, rayT, | |||
| 322 | inside, | |||
| 323 | rayPosW, rayPosI); | |||
| 324 | if (!AIR_EXISTS(rayStep)(((int)(!((rayStep) - (rayStep)))))) { | |||
| 325 | /* sampling failed */ | |||
| 326 | arg->errCode = 0; | |||
| 327 | arg->whichErr = hooverErrSample; | |||
| 328 | return arg; | |||
| 329 | } | |||
| 330 | if (!rayStep) { | |||
| 331 | /* ray decided to finish itself */ | |||
| 332 | break; | |||
| 333 | } | |||
| 334 | /* else we moved to a new location along the ray */ | |||
| 335 | rayT += rayStep; | |||
| 336 | if (!AIR_IN_CL(0, rayT, rayLen)((0) <= (rayT) && (rayT) <= (rayLen))) { | |||
| 337 | /* ray stepped outside near-far clipping region, its done. */ | |||
| 338 | break; | |||
| 339 | } | |||
| 340 | sampleI++; | |||
| 341 | } | |||
| 342 | ||||
| 343 | if ( (ret = (arg->ctx->rayEnd)(thread, | |||
| 344 | arg->render, | |||
| 345 | arg->ctx->user)) ) { | |||
| 346 | arg->errCode = ret; | |||
| 347 | arg->whichErr = hooverErrRayEnd; | |||
| 348 | return arg; | |||
| 349 | } | |||
| 350 | } /* end this scanline */ | |||
| 351 | } /* end while(1) assignment of scanlines */ | |||
| 352 | ||||
| 353 | if ( (ret = (arg->ctx->threadEnd)(thread, | |||
| 354 | arg->render, | |||
| 355 | arg->ctx->user)) ) { | |||
| 356 | arg->errCode = ret; | |||
| 357 | arg->whichErr = hooverErrThreadEnd; | |||
| 358 | return arg; | |||
| 359 | } | |||
| 360 | ||||
| 361 | /* returning NULL actually indicates that there was NOT an error */ | |||
| 362 | return NULL((void*)0); | |||
| 363 | } | |||
| 364 | ||||
| 365 | typedef union { | |||
| 366 | _hooverThreadArg **h; | |||
| 367 | void **v; | |||
| 368 | } _htpu; | |||
| 369 | ||||
| 370 | /* | |||
| 371 | ******** hooverRender() | |||
| 372 | ** | |||
| 373 | ** because of the biff usage(), only one thread can call hooverRender(), | |||
| 374 | ** and no promises if the threads themselves call biff... | |||
| 375 | */ | |||
| 376 | int | |||
| 377 | hooverRender(hooverContext *ctx, int *errCodeP, int *errThreadP) { | |||
| 378 | static const char me[]="hooverRender"; | |||
| 379 | _hooverExtraContext *ec; | |||
| 380 | _hooverThreadArg args[HOOVER_THREAD_MAX512]; | |||
| 381 | _hooverThreadArg *errArg; | |||
| ||||
| 382 | airThread *thread[HOOVER_THREAD_MAX512]; | |||
| 383 | _htpu u; | |||
| 384 | ||||
| 385 | void *render; | |||
| 386 | int ret; | |||
| 387 | airArray *mop; | |||
| 388 | unsigned int threadIdx; | |||
| 389 | ||||
| 390 | if (!( errCodeP && errThreadP )) { | |||
| 391 | biffAddf(HOOVERhooverBiffKey, "%s: got NULL int return pointer", me); | |||
| 392 | return hooverErrInit; | |||
| 393 | } | |||
| 394 | ||||
| 395 | /* this calls limnCameraUpdate() */ | |||
| 396 | if (hooverContextCheck(ctx)) { | |||
| 397 | biffAddf(HOOVERhooverBiffKey, "%s: problem detected in given context", me); | |||
| 398 | *errCodeP = 0; | |||
| 399 | *errThreadP = 0; | |||
| 400 | return hooverErrInit; | |||
| 401 | } | |||
| 402 | ||||
| 403 | if (!(ec = _hooverExtraContextNew(ctx))) { | |||
| 404 | biffAddf(HOOVERhooverBiffKey, "%s: problem creating thread context", me); | |||
| 405 | *errCodeP = 0; | |||
| 406 | *errThreadP = 0; | |||
| 407 | return hooverErrInit; | |||
| 408 | } | |||
| 409 | mop = airMopNew(); | |||
| 410 | airMopAdd(mop, ec, (airMopper)_hooverExtraContextNix, airMopAlways); | |||
| 411 | if ( (ret = (ctx->renderBegin)(&render, ctx->user)) ) { | |||
| 412 | *errCodeP = ret; | |||
| 413 | *errCodeP = 0; | |||
| 414 | *errThreadP = 0; | |||
| 415 | airMopError(mop); | |||
| 416 | return hooverErrRenderBegin; | |||
| 417 | } | |||
| 418 | ||||
| 419 | for (threadIdx=0; threadIdx<ctx->numThreads; threadIdx++) { | |||
| 420 | args[threadIdx].ctx = ctx; | |||
| 421 | args[threadIdx].ec = ec; | |||
| 422 | args[threadIdx].render = render; | |||
| 423 | args[threadIdx].whichThread = threadIdx; | |||
| 424 | args[threadIdx].whichErr = hooverErrNone; | |||
| 425 | args[threadIdx].errCode = 0; | |||
| 426 | thread[threadIdx] = airThreadNew(); | |||
| 427 | } | |||
| 428 | ctx->workIdx = 0; | |||
| 429 | if (1 < ctx->numThreads) { | |||
| 430 | ctx->workMutex = airThreadMutexNew(); | |||
| 431 | } else { | |||
| 432 | ctx->workMutex = NULL((void*)0); | |||
| 433 | } | |||
| 434 | ||||
| 435 | /* (done): call airThreadStart() once per thread, passing the | |||
| 436 | address of a distinct (and appropriately intialized) | |||
| 437 | _hooverThreadArg to each. If return of airThreadStart() is | |||
| 438 | non-zero, put its return in *errCodeP, the number of the | |||
| 439 | problematic in *errThreadP, and return hooverErrThreadCreate. | |||
| 440 | Then call airThreadJoin() on all the threads, passing &errArg as | |||
| 441 | "retval". On non-zero return, set *errCodeP and *errThreadP, | |||
| 442 | and return hooverErrThreadJoin. If return of airThreadJoin() is | |||
| 443 | zero, but the errArg is non-NULL, then assume that this errArg | |||
| 444 | is actually just the passed _hooverThreadArg returned to us, and | |||
| 445 | from this copy errArg->errCode into *errCodeP, and return | |||
| 446 | errArg->whichErr */ | |||
| 447 | ||||
| 448 | if (1 < ctx->numThreads && !airThreadCapable) { | |||
| 449 | fprintf(stderr__stderrp, "%s: WARNING: not multi-threaded; will do %d " | |||
| 450 | "\"threads\" serially !!!\n", me, ctx->numThreads); | |||
| 451 | } | |||
| 452 | ||||
| 453 | for (threadIdx=0; threadIdx<ctx->numThreads; threadIdx++) { | |||
| 454 | if ((ret = airThreadStart(thread[threadIdx], _hooverThreadBody, | |||
| 455 | (void *) &args[threadIdx]))) { | |||
| 456 | *errCodeP = ret; | |||
| 457 | *errThreadP = threadIdx; | |||
| 458 | airMopError(mop); | |||
| 459 | return hooverErrThreadCreate; | |||
| 460 | } | |||
| 461 | } | |||
| 462 | ||||
| 463 | for (threadIdx=0; threadIdx<ctx->numThreads; threadIdx++) { | |||
| 464 | u.h = &errArg; | |||
| 465 | if ((ret = airThreadJoin(thread[threadIdx], u.v))) { | |||
| 466 | *errCodeP = ret; | |||
| 467 | *errThreadP = threadIdx; | |||
| 468 | airMopError(mop); | |||
| 469 | return hooverErrThreadJoin; | |||
| 470 | } | |||
| 471 | if (errArg != NULL((void*)0)) { | |||
| ||||
| 472 | *errCodeP = errArg->errCode; | |||
| 473 | *errThreadP = threadIdx; | |||
| 474 | return errArg->whichErr; | |||
| 475 | } | |||
| 476 | thread[threadIdx] = airThreadNix(thread[threadIdx]); | |||
| 477 | } | |||
| 478 | ||||
| 479 | if (1 < ctx->numThreads) { | |||
| 480 | ctx->workMutex = airThreadMutexNix(ctx->workMutex); | |||
| 481 | } | |||
| 482 | ||||
| 483 | if ( (ret = (ctx->renderEnd)(render, ctx->user)) ) { | |||
| 484 | *errCodeP = ret; | |||
| 485 | *errThreadP = -1; | |||
| 486 | return hooverErrRenderEnd; | |||
| 487 | } | |||
| 488 | render = NULL((void*)0); | |||
| 489 | airMopOkay(mop); | |||
| 490 | ||||
| 491 | *errCodeP = 0; | |||
| 492 | *errThreadP = 0; | |||
| 493 | return hooverErrNone; | |||
| 494 | } |