void FontInstanceAdapter::getWideGlyphAdvance(le_uint32 glyph, LEPoint &advance) const { hsGGlyph glyphRef; hsFixedPoint2 adv; // FIXME: return value? fStrike->getMetrics(glyph, glyphRef, adv); advance.fX = fixedToFloat(adv.fX); advance.fY = fixedToFloat(adv.fY); }
void FontInstanceAdapter::transformFunits(float xFunits, float yFunits, LEPoint &pixels) const { hsFixedPoint2 pt; long xFunitsL = (long)xFunits; long yFunitsL = (long)yFunits; fStrike->TransformFunits(0, (short)xFunitsL, (short)yFunitsL, pt); pixels.fX = fixedToFloat(pt.fX); pixels.fY = fixedToFloat(pt.fY); }
void transform_t::dump(const char* what) { GLfixed const * const m = matrix.m; LOGD("%s:", what); for (int i=0 ; i<4 ; i++) LOGD("[%08x %08x %08x %08x] [%f %f %f %f]\n", m[I(0,i)], m[I(1,i)], m[I(2,i)], m[I(3,i)], fixedToFloat(m[I(0,i)]), fixedToFloat(m[I(1,i)]), fixedToFloat(m[I(2,i)]), fixedToFloat(m[I(3,i)])); }
le_bool FontInstanceAdapter::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const { hsFixedPoint2 pt; le_bool result; result = fStrike->GetGlyphPoint(glyph, pointNumber, pt); if (result) { point.fX = fixedToFloat(pt.fX); point.fY = fixedToFloat(pt.fY); } return result; }
void matrixf_t::load(const GLfixed* rhs) { GLfloat* fp = m; unsigned int i = 16; do { *fp++ = fixedToFloat(*rhs++); } while (--i); }
bool TerrainBlock::exportHeightMap( const UTF8 *filePath, const String &format ) const { GBitmap output( mFile->mSize, mFile->mSize, false, GFXFormatR5G6B5 ); // First capture the max height... we'll normalize // everything to this value. U16 maxHeight = 0; Vector<const U16>::iterator iBits = mFile->mHeightMap.begin(); for ( S32 y = 0; y < mFile->mSize; y++ ) { for ( S32 x = 0; x < mFile->mSize; x++ ) { if ( *iBits > maxHeight ) maxHeight = *iBits; ++iBits; } } // Now write out the map. iBits = mFile->mHeightMap.begin(); U16 *oBits = (U16*)output.getWritableBits(); for ( S32 y = 0; y < mFile->mSize; y++ ) { for ( S32 x = 0; x < mFile->mSize; x++ ) { // PNG expects big endian. U16 height = (U16)( ( (F32)(*iBits) / (F32)maxHeight ) * (F32)U16_MAX ); *oBits = convertHostToBEndian( height ); ++oBits; ++iBits; } } FileStream stream; if ( !stream.open( filePath, Torque::FS::File::Write ) ) { Con::errorf( "TerrainBlock::exportHeightMap() - Error opening file for writing: %s !", filePath ); return false; } if ( !output.writeBitmap( format, stream ) ) { Con::errorf( "TerrainBlock::exportHeightMap() - Error writing %s: %s !", format.c_str(), filePath ); return false; } // Print out the map size in meters, so that the user // knows what values to use when importing it into // another terrain tool. S32 dim = mSquareSize * mFile->mSize; S32 height = fixedToFloat( maxHeight ); Con::printf( "Saved heightmap with dimensions %d x %d x %d.", dim, dim, height ); return true; }
int Tracker::arCameraObserv2Ideal_LUT(Camera* pCam, ARFloat ox, ARFloat oy, ARFloat *ix, ARFloat *iy) { if (!undistO2ITable) buildUndistO2ITable(pCam); int x = (int) ox, y = (int) oy; fixedToFloat(undistO2ITable[x + y * arImXsize], *ix, *iy); return 0; }
AR_TEMPL_FUNC int AR_TEMPL_TRACKER::arParamObserv2Ideal_LUT(Camera* pCam, ARFloat ox, ARFloat oy, ARFloat *ix, ARFloat *iy) { if(!undistO2ITable) buildUndistO2ITable(pCam); int x=(int)ox, y=(int)oy; fixedToFloat(undistO2ITable[x+y*arImXsize], *ix,*iy); return 0; }
void Tracker::buildUndistO2ITable(Camera* pCam) { int x, y; ARFloat cx, cy, ox, oy; unsigned int fixed; char* cachename = NULL; bool loaded = false; if (loadCachedUndist) { assert(pCam->getFileName() != ""); cachename = new char[strlen(pCam->getFileName().c_str()) + 5]; strcpy(cachename, pCam->getFileName().c_str()); strcat(cachename, ".LUT"); } // we have to take care here when using a memory manager that can not free memory // (usually this lookup table should only be built once - unless we change camera resolution) // if (undistO2ITable) delete[] undistO2ITable; undistO2ITable = new unsigned int[arImXsize * arImYsize]; if (loadCachedUndist) { if (FILE* fp = fopen(cachename, "rb")) { size_t numBytes = fread(undistO2ITable, 1, arImXsize * arImYsize * sizeof(unsigned int), fp); fclose(fp); if (numBytes == arImXsize * arImYsize * sizeof(unsigned int)) loaded = true; } } if (!loaded) { for (x = 0; x < arImXsize; x++) { for (y = 0; y < arImYsize; y++) { arCameraObserv2Ideal_std(pCam, (ARFloat) x, (ARFloat) y, &cx, &cy); floatToFixed(cx, cy, fixed); fixedToFloat(fixed, ox, oy); undistO2ITable[x + y * arImXsize] = fixed; } } if (loadCachedUndist) if (FILE* fp = fopen(cachename, "wb")) { fwrite(undistO2ITable, 1, arImXsize * arImYsize * sizeof(unsigned int), fp); fclose(fp); } } delete[] cachename; }
void TerrCell::_updateBounds() { PROFILE_SCOPE( TerrCell_UpdateBounds ); const F32 squareSize = mTerrain->getSquareSize(); // This should really only be called for cells of smMinCellSize, // in which case stepSize is always one. const U32 stepSize = mSize / smMinCellSize; // Prepare to expand the bounds. mBounds.minExtents.set( F32_MAX, F32_MAX, F32_MAX ); mBounds.maxExtents.set( -F32_MAX, -F32_MAX, -F32_MAX ); Point3F vert; Point2F texCoord; const TerrainFile *file = mTerrain->getFile(); for ( U32 y = 0; y < smVBStride; y++ ) { for ( U32 x = 0; x < smVBStride; x++ ) { // Setup this point. vert.x = (F32)( mPoint.x + x * stepSize ) * squareSize; vert.y = (F32)( mPoint.y + y * stepSize ) * squareSize; vert.z = fixedToFloat( file->getHeight( mPoint.x + x, mPoint.y + y ) ); // HACK: Call it twice to deal with the inverted // inital bounds state... shouldn't be a perf issue. mBounds.extend( vert ); mBounds.extend( vert ); } } mRadius = mBounds.len() * 0.5; _updateOBB(); }
void TerrCell::_updateVertexBuffer() { PROFILE_SCOPE( TerrCell_UpdateVertexBuffer ); // Start off with no empty squares mHasEmpty = false; mEmptyVertexList.clear(); mVertexBuffer.set( GFX, smVBSize, GFXBufferTypeStatic ); const F32 squareSize = mTerrain->getSquareSize(); const U32 blockSize = mTerrain->getBlockSize(); const U32 stepSize = mSize / smMinCellSize; U32 vbcounter = 0; TerrVertex *vert = mVertexBuffer.lock(); Point2I gridPt; Point2F point; F32 height; Point3F normal; const TerrainFile *file = mTerrain->getFile(); for ( U32 y = 0; y < smVBStride; y++ ) { for ( U32 x = 0; x < smVBStride; x++ ) { // We clamp here to keep the geometry from reading across // one side of the height map to the other causing walls // around the edges of the terrain. gridPt.x = mClamp( mPoint.x + x * stepSize, 0, blockSize - 1 ); gridPt.y = mClamp( mPoint.y + y * stepSize, 0, blockSize - 1 ); // Setup this point. point.x = (F32)gridPt.x * squareSize; point.y = (F32)gridPt.y * squareSize; height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) ); vert->point.x = point.x; vert->point.y = point.y; vert->point.z = height; // Get the normal. mTerrain->getSmoothNormal( point, &normal, true, false ); vert->normal = normal; // Get the tangent z. vert->tangentZ = fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ) - height; // Test the empty state for this vert. if ( file->isEmptyAt( gridPt.x, gridPt.y ) ) { mHasEmpty = true; mEmptyVertexList.push_back( vbcounter ); } vbcounter++; ++vert; } } // Add verts for 'skirts' around/beneath the edge verts of this cell. // This could probably be reduced to a loop... const F32 skirtDepth = mSize / smMinCellSize * mTerrain->getSquareSize(); // Top edge skirt for ( U32 i = 0; i < smVBStride; i++ ) { gridPt.x = mClamp( mPoint.x + i * stepSize, 0, blockSize - 1 ); gridPt.y = mClamp( mPoint.y, 0, blockSize - 1 ); point.x = (F32)gridPt.x * squareSize; point.y = (F32)gridPt.y * squareSize; height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) ); vert->point.x = point.x; vert->point.y = point.y; vert->point.z = height - skirtDepth; // Get the normal. mTerrain->getNormal( point, &normal, true, false ); vert->normal = normal; // Get the tangent. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ); vbcounter++; ++vert; } // Bottom edge skirt for ( U32 i = 0; i < smVBStride; i++ ) { gridPt.x = mClamp( mPoint.x + i * stepSize, 0, blockSize - 1 ); gridPt.y = mClamp( mPoint.y + smMinCellSize * stepSize, 0, blockSize - 1 ); point.x = (F32)gridPt.x * squareSize; point.y = (F32)gridPt.y * squareSize; height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) ); vert->point.x = point.x; vert->point.y = point.y; vert->point.z = height - skirtDepth; // Get the normal. mTerrain->getNormal( point, &normal, true, false ); vert->normal = normal; // Get the tangent. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ); vbcounter++; ++vert; } // Left edge skirt for ( U32 i = 0; i < smVBStride; i++ ) { gridPt.x = mClamp( mPoint.x, 0, blockSize - 1 ); gridPt.y = mClamp( mPoint.y + i * stepSize, 0, blockSize - 1 ); point.x = (F32)gridPt.x * squareSize; point.y = (F32)gridPt.y * squareSize; height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) ); vert->point.x = point.x; vert->point.y = point.y; vert->point.z = height - skirtDepth; // Get the normal. mTerrain->getNormal( point, &normal, true, false ); vert->normal = normal; // Get the tangent. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ); vbcounter++; ++vert; } // Right edge skirt for ( U32 i = 0; i < smVBStride; i++ ) { gridPt.x = mClamp( mPoint.x + smMinCellSize * stepSize, 0, blockSize - 1 ); gridPt.y = mClamp( mPoint.y + i * stepSize, 0, blockSize - 1 ); point.x = (F32)gridPt.x * squareSize; point.y = (F32)gridPt.y * squareSize; height = fixedToFloat( file->getHeight( gridPt.x, gridPt.y ) ); vert->point.x = point.x; vert->point.y = point.y; vert->point.z = height - skirtDepth; // Get the normal. mTerrain->getNormal( point, &normal, true, false ); vert->normal = normal; // Get the tangent. vert->tangentZ = height - fixedToFloat( file->getHeight( gridPt.x + 1, gridPt.y ) ); vbcounter++; ++vert; } AssertFatal( vbcounter == smVBSize, "bad" ); mVertexBuffer.unlock(); }
bool TerrainBlock::buildPolyList(AbstractPolyList* polyList, const Box3F &box, const SphereF&) { if (box.maxExtents.z < -TerrainThickness || box.minExtents.z > fixedToFloat(gridMap[BlockShift]->maxHeight)) return false; // Transform the bounding sphere into the object's coord space. Note that this // not really optimal. Box3F osBox = box; mWorldToObj.mul(osBox); AssertWarn(mObjScale == Point3F::One, "Error, handle the scale transform on the terrain"); // Setup collision state data polyList->setTransform(&getTransform(), getScale()); polyList->setObject(this); S32 xStart = (S32)mFloor( osBox.minExtents.x / mSquareSize ); S32 xEnd = (S32)mCeil ( osBox.maxExtents.x / mSquareSize ); S32 yStart = (S32)mFloor( osBox.minExtents.y / mSquareSize ); S32 yEnd = (S32)mCeil ( osBox.maxExtents.y / mSquareSize ); if (!mTile && xStart<0) xStart = 0; S32 xExt = xEnd - xStart; if (xExt > MaxExtent) xExt = MaxExtent; xEnd = xStart + xExt; mHeightMax = floatToFixed(osBox.maxExtents.z); mHeightMin = (osBox.minExtents.z < 0.0f)? 0.0f: floatToFixed(osBox.minExtents.z); // Index of shared points U32 bp[(MaxExtent + 1) * 2],*vb[2]; vb[0] = &bp[0]; vb[1] = &bp[xExt + 1]; clrbuf(vb[1],xExt + 1); bool emitted = false; for (S32 y = yStart; y < yEnd; y++) { S32 yi = y & BlockMask; swap(vb[0],vb[1]); clrbuf(vb[1],xExt + 1); // for (S32 x = xStart; x < xEnd; x++) { S32 xi = x & BlockMask; GridSquare *gs = findSquare(0, Point2I(xi, yi)); // If we disable repeat, then skip non-primary if(!mTile && (x!=xi || y!=yi)) continue; // holes only in the primary terrain block if (((gs->flags & GridSquare::Empty) && x == xi && y == yi) || gs->minHeight > mHeightMax || gs->maxHeight < mHeightMin) continue; emitted = true; // Add the missing points U32 vi[5]; for (int i = 0; i < 4 ; i++) { S32 dx = i >> 1; S32 dy = dx ^ (i & 1); U32* vp = &vb[dy][x - xStart + dx]; if (*vp == U32_MAX) { Point3F pos; pos.x = (F32)((x + dx) * mSquareSize); pos.y = (F32)((y + dy) * mSquareSize); pos.z = fixedToFloat(getHeight(xi + dx, yi + dy)); *vp = polyList->addPoint(pos); } vi[i] = *vp; } U32* vp = &vi[0]; if (!(gs->flags & GridSquare::Split45)) vi[4] = vi[0], vp++; BaseMatInstance* material = getMaterialInst( xi, yi ); U32 surfaceKey = ((xi << 16) + yi) << 1; polyList->begin(material,surfaceKey); polyList->vertex(vp[0]); polyList->vertex(vp[1]); polyList->vertex(vp[2]); polyList->plane(vp[0],vp[1],vp[2]); polyList->end(); polyList->begin(material,surfaceKey + 1); polyList->vertex(vp[0]); polyList->vertex(vp[2]); polyList->vertex(vp[3]); polyList->plane(vp[0],vp[2],vp[3]); polyList->end(); } } return emitted; }
void TerrainBlock::buildConvex(const Box3F& box,Convex* convex) { sTerrainConvexList.collectGarbage(); // if (box.maxExtents.z < -TerrainThickness || box.minExtents.z > fixedToFloat(gridMap[BlockShift]->maxHeight)) return; // Transform the bounding sphere into the object's coord space. Note that this // not really optimal. Box3F osBox = box; mWorldToObj.mul(osBox); AssertWarn(mObjScale == Point3F(1, 1, 1), "Error, handle the scale transform on the terrain"); S32 xStart = (S32)mFloor( osBox.minExtents.x / mSquareSize ); S32 xEnd = (S32)mCeil ( osBox.maxExtents.x / mSquareSize ); S32 yStart = (S32)mFloor( osBox.minExtents.y / mSquareSize ); S32 yEnd = (S32)mCeil ( osBox.maxExtents.y / mSquareSize ); S32 xExt = xEnd - xStart; if (xExt > MaxExtent) xExt = MaxExtent; mHeightMax = floatToFixed(osBox.maxExtents.z); mHeightMin = (osBox.minExtents.z < 0)? 0: floatToFixed(osBox.minExtents.z); for (S32 y = yStart; y < yEnd; y++) { S32 yi = y & BlockMask; // for (S32 x = xStart; x < xEnd; x++) { S32 xi = x & BlockMask; GridSquare *gs = findSquare(0, Point2I(xi, yi)); // If we disable repeat, then skip non-primary if(!mTile && (x!=xi || y!=yi)) continue; // holes only in the primary terrain block if (((gs->flags & GridSquare::Empty) && x == xi && y == yi) || gs->minHeight > mHeightMax || gs->maxHeight < mHeightMin) continue; U32 sid = (x << 16) + (y & ((1 << 16) - 1)); Convex* cc = 0; // See if the square already exists as part of the working set. CollisionWorkingList& wl = convex->getWorkingList(); for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext) if (itr->mConvex->getType() == TerrainConvexType && static_cast<TerrainConvex*>(itr->mConvex)->squareId == sid) { cc = itr->mConvex; break; } if (cc) continue; // Create a new convex. TerrainConvex* cp = new TerrainConvex; sTerrainConvexList.registerObject(cp); convex->addToWorkingList(cp); cp->halfA = true; cp->square = 0; cp->mObject = this; cp->squareId = sid; cp->material = getMaterial(xi,yi)->index;//RDTODO cp->box.minExtents.set((F32)(x * mSquareSize), (F32)(y * mSquareSize), fixedToFloat(gs->minHeight)); cp->box.maxExtents.x = cp->box.minExtents.x + mSquareSize; cp->box.maxExtents.y = cp->box.minExtents.y + mSquareSize; cp->box.maxExtents.z = fixedToFloat(gs->maxHeight); mObjToWorld.mul(cp->box); // Build points Point3F* pos = cp->point; for (int i = 0; i < 4 ; i++,pos++) { S32 dx = i >> 1; S32 dy = dx ^ (i & 1); pos->x = (F32)((x + dx) * mSquareSize); pos->y = (F32)((y + dy) * mSquareSize); pos->z = fixedToFloat(getHeight(xi + dx, yi + dy)); } // Build normals, then split into two Convex objects if the // square is concave if ((cp->split45 = gs->flags & GridSquare::Split45) == true) { VectorF *vp = cp->point; mCross(vp[0] - vp[1],vp[2] - vp[1],&cp->normal[0]); cp->normal[0].normalize(); mCross(vp[2] - vp[3],vp[0] - vp[3],&cp->normal[1]); cp->normal[1].normalize(); if (mDot(vp[3] - vp[1],cp->normal[0]) > 0) { TerrainConvex* nc = new TerrainConvex(*cp); sTerrainConvexList.registerObject(nc); convex->addToWorkingList(nc); nc->halfA = false; nc->square = cp; cp->square = nc; } } else { VectorF *vp = cp->point; mCross(vp[3] - vp[0],vp[1] - vp[0],&cp->normal[0]); cp->normal[0].normalize(); mCross(vp[1] - vp[2],vp[3] - vp[2],&cp->normal[1]); cp->normal[1].normalize(); if (mDot(vp[2] - vp[0],cp->normal[0]) > 0) { TerrainConvex* nc = new TerrainConvex(*cp); sTerrainConvexList.registerObject(nc); convex->addToWorkingList(nc); nc->halfA = false; nc->square = cp; cp->square = nc; } } } } }
bool TerrainBlock::buildPolyList(PolyListContext, AbstractPolyList* polyList, const Box3F &box, const SphereF&) { PROFILE_SCOPE( TerrainBlock_buildPolyList ); // First check to see if the query misses the // terrain elevation range. const Point3F &terrainPos = getPosition(); if ( box.maxExtents.z - terrainPos.z < -TerrainThickness || box.minExtents.z - terrainPos.z > fixedToFloat( mFile->getMaxHeight() ) ) return false; // Transform the bounding sphere into the object's coord // space. Note that this is really optimal. Box3F osBox = box; mWorldToObj.mul(osBox); AssertWarn(mObjScale == Point3F::One, "Error, handle the scale transform on the terrain"); // Setup collision state data polyList->setTransform(&getTransform(), getScale()); polyList->setObject(this); S32 xStart = (S32)mFloor( osBox.minExtents.x / mSquareSize ); S32 xEnd = (S32)mCeil ( osBox.maxExtents.x / mSquareSize ); S32 yStart = (S32)mFloor( osBox.minExtents.y / mSquareSize ); S32 yEnd = (S32)mCeil ( osBox.maxExtents.y / mSquareSize ); if ( xStart < 0 ) xStart = 0; S32 xExt = xEnd - xStart; if ( xExt > MaxExtent ) xExt = MaxExtent; xEnd = xStart + xExt; U32 heightMax = floatToFixed(osBox.maxExtents.z); U32 heightMin = (osBox.minExtents.z < 0.0f)? 0.0f: floatToFixed(osBox.minExtents.z); // Index of shared points U32 bp[(MaxExtent + 1) * 2],*vb[2]; vb[0] = &bp[0]; vb[1] = &bp[xExt + 1]; clrbuf(vb[1],xExt + 1); const U32 BlockMask = mFile->mSize - 1; bool emitted = false; for (S32 y = yStart; y < yEnd; y++) { S32 yi = y & BlockMask; swap(vb[0],vb[1]); clrbuf(vb[1],xExt + 1); // for (S32 x = xStart; x < xEnd; x++) { S32 xi = x & BlockMask; const TerrainSquare *sq = mFile->findSquare( 0, xi, yi ); if ( x != xi || y != yi ) continue; // holes only in the primary terrain block if ( ( ( sq->flags & TerrainSquare::Empty ) && x == xi && y == yi ) || sq->minHeight > heightMax || sq->maxHeight < heightMin ) continue; emitted = true; // Add the missing points U32 vi[5]; for (int i = 0; i < 4 ; i++) { S32 dx = i >> 1; S32 dy = dx ^ (i & 1); U32* vp = &vb[dy][x - xStart + dx]; if (*vp == U32_MAX) { Point3F pos; pos.x = (F32)((x + dx) * mSquareSize); pos.y = (F32)((y + dy) * mSquareSize); pos.z = fixedToFloat( mFile->getHeight(xi + dx, yi + dy) ); *vp = polyList->addPoint(pos); } vi[i] = *vp; } U32* vp = &vi[0]; if ( !( sq->flags & TerrainSquare::Split45 ) ) vi[4] = vi[0], vp++; BaseMatInstance *material = NULL; //getMaterialInst( xi, yi ); U32 surfaceKey = ((xi << 16) + yi) << 1; polyList->begin(material,surfaceKey); polyList->vertex(vp[0]); polyList->vertex(vp[1]); polyList->vertex(vp[2]); polyList->plane(vp[0],vp[1],vp[2]); polyList->end(); polyList->begin(material,surfaceKey + 1); polyList->vertex(vp[0]); polyList->vertex(vp[2]); polyList->vertex(vp[3]); polyList->plane(vp[0],vp[2],vp[3]); polyList->end(); } } return emitted; }
static GLfixed fog_exp2(ogles_context_t* c, GLfixed z) { const float e = fixedToFloat(gglMulx(c->fog.density, z)); return clampF(gglFloatToFixed(fastexpf(-e*e))); }
virtual float getAltitude(int x, int y) { return fixedToFloat(mBlock->getHeight(x,y)); }
virtual float getMaxHeight() { return fixedToFloat(mBlock->findSquare(TerrainBlock::BlockShift, Point2I(0,0))->maxHeight); }
bool TerrainBlock::castRayBlock(const Point3F &pStart, const Point3F &pEnd, const Point2I &aBlockPos, U32 aLevel, F32 invDeltaX, F32 invDeltaY, F32 aStartT, F32 aEndT, RayInfo *info, bool collideEmpty) { F32 invBlockSize = 1 / F32(BlockSquareWidth); static TerrLOSStackNode stack[BlockShift * 3 + 1]; U32 stackSize = 1; stack[0].startT = aStartT; stack[0].endT = aEndT; stack[0].blockPos = aBlockPos; stack[0].level = aLevel; if(!mTile && !aBlockPos.isZero()) return false; while(stackSize--) { TerrLOSStackNode *sn = stack + stackSize; U32 level = sn->level; F32 startT = sn->startT; F32 endT = sn->endT; Point2I blockPos = sn->blockPos; GridSquare *sq = findSquare(level, Point2I(blockPos.x & BlockMask, blockPos.y & BlockMask)); F32 startZ = startT * (pEnd.z - pStart.z) + pStart.z; F32 endZ = endT * (pEnd.z - pStart.z) + pStart.z; F32 minHeight = fixedToFloat(sq->minHeight); if(startZ <= minHeight && endZ <= minHeight) { //drawLineTest(startT, sn->endT, false); continue; } F32 maxHeight = fixedToFloat(sq->maxHeight); if(startZ >= maxHeight && endZ >= maxHeight) { //drawLineTest(startT, endT, false); continue; } if (!collideEmpty && (sq->flags & GridSquare::Empty) && blockPos.x == (blockPos.x & BlockMask) && blockPos.y == (blockPos.y & BlockMask)) { //drawLineTest(startT, endT, false); continue; } if(level == 0) { F32 xs = blockPos.x * invBlockSize; F32 ys = blockPos.y * invBlockSize; F32 zBottomLeft = fixedToFloat(getHeight(blockPos.x, blockPos.y)); F32 zBottomRight= fixedToFloat(getHeight(blockPos.x + 1, blockPos.y)); F32 zTopLeft = fixedToFloat(getHeight(blockPos.x, blockPos.y + 1)); F32 zTopRight = fixedToFloat(getHeight(blockPos.x + 1, blockPos.y + 1)); PlaneF p1, p2; PlaneF divider; Point3F planePoint; if(sq->flags & GridSquare::Split45) { p1.set(zBottomLeft - zBottomRight, zBottomRight - zTopRight, invBlockSize); p2.set(zTopLeft - zTopRight, zBottomLeft - zTopLeft, invBlockSize); planePoint.set(xs, ys, zBottomLeft); divider.x = 1; divider.y = -1; divider.z = 0; } else { p1.set(zTopLeft - zTopRight, zBottomRight - zTopRight, invBlockSize); p2.set(zBottomLeft - zBottomRight, zBottomLeft - zTopLeft, invBlockSize); planePoint.set(xs + invBlockSize, ys, zBottomRight); divider.x = 1; divider.y = 1; divider.z = 0; } p1.setPoint(planePoint); p2.setPoint(planePoint); divider.setPoint(planePoint); F32 t1 = p1.intersect(pStart, pEnd); F32 t2 = p2.intersect(pStart, pEnd); F32 td = divider.intersect(pStart, pEnd); F32 dStart = divider.distToPlane(pStart); F32 dEnd = divider.distToPlane(pEnd); // see if the line crosses the divider if((dStart >= 0 && dEnd < 0) || (dStart < 0 && dEnd >= 0)) { if(dStart < 0) { F32 temp = t1; t1 = t2; t2 = temp; } if(t1 >= startT && t1 && t1 <= td && t1 <= endT) { info->t = t1; info->normal = p1; return true; } if(t2 >= td && t2 >= startT && t2 <= endT) { info->t = t2; info->normal = p2; return true; } } else { F32 t; if(dStart >= 0) { t = t1; info->normal = p1; } else { t = t2; info->normal = p2; } if(t >= startT && t <= endT) { info->t = t; return true; } } continue; } int subSqWidth = 1 << (level - 1); F32 xIntercept = (blockPos.x + subSqWidth) * invBlockSize; F32 xInt = calcInterceptX(pStart.x, invDeltaX, xIntercept); F32 yIntercept = (blockPos.y + subSqWidth) * invBlockSize; F32 yInt = calcInterceptY(pStart.y, invDeltaY, yIntercept); F32 startX = startT * (pEnd.x - pStart.x) + pStart.x; F32 startY = startT * (pEnd.y - pStart.y) + pStart.y; if(xInt < startT) xInt = MAX_FLOAT; if(yInt < startT) yInt = MAX_FLOAT; U32 x0 = (startX > xIntercept) * subSqWidth; U32 y0 = (startY > yIntercept) * subSqWidth; U32 x1 = subSqWidth - x0; U32 y1 = subSqWidth - y0; U32 nextLevel = level - 1; // push the items on the stack in reverse order of processing if(xInt > endT && yInt > endT) { // only test the square the point started in: stack[stackSize].blockPos.set(blockPos.x + x0, blockPos.y + y0); stack[stackSize].level = nextLevel; stackSize++; } else if(xInt < yInt) { F32 nextIntersect = endT; if(yInt <= endT) { stack[stackSize].blockPos.set(blockPos.x + x1, blockPos.y + y1); stack[stackSize].startT = yInt; stack[stackSize].endT = endT; stack[stackSize].level = nextLevel; nextIntersect = yInt; stackSize++; } stack[stackSize].blockPos.set(blockPos.x + x1, blockPos.y + y0); stack[stackSize].startT = xInt; stack[stackSize].endT = nextIntersect; stack[stackSize].level = nextLevel; stack[stackSize+1].blockPos.set(blockPos.x + x0, blockPos.y + y0); stack[stackSize+1].startT = startT; stack[stackSize+1].endT = xInt; stack[stackSize+1].level = nextLevel; stackSize += 2; } else if(yInt < xInt) { F32 nextIntersect = endT; if(xInt <= endT) { stack[stackSize].blockPos.set(blockPos.x + x1, blockPos.y + y1); stack[stackSize].startT = xInt; stack[stackSize].endT = endT; stack[stackSize].level = nextLevel; nextIntersect = xInt; stackSize++; } stack[stackSize].blockPos.set(blockPos.x + x0, blockPos.y + y1); stack[stackSize].startT = yInt; stack[stackSize].endT = nextIntersect; stack[stackSize].level = nextLevel; stack[stackSize+1].blockPos.set(blockPos.x + x0, blockPos.y + y0); stack[stackSize+1].startT = startT; stack[stackSize+1].endT = yInt; stack[stackSize+1].level = nextLevel; stackSize += 2; } else { stack[stackSize].blockPos.set(blockPos.x + x1, blockPos.y + y1); stack[stackSize].startT = xInt; stack[stackSize].endT = endT; stack[stackSize].level = nextLevel; stack[stackSize+1].blockPos.set(blockPos.x + x0, blockPos.y + y0); stack[stackSize+1].startT = startT; stack[stackSize+1].endT = xInt; stack[stackSize+1].level = nextLevel; stackSize += 2; } } return false; }