示例#1
0
void Builder_MakeChunk(ChunkInfo* info) {
	Int32 x = info->CentreX - 8, y = info->CentreY - 8, z = info->CentreZ - 8;
	bool allAir = false, hasMesh;
	hasMesh = Builder_BuildChunk(x, y, z, &allAir);
	info->AllAir = allAir;
	if (!hasMesh) return;

	Int32 totalVerts = Builder_TotalVerticesCount();
	if (totalVerts == 0) return;
#if !CC_BUILD_GL11
	/* add an extra element to fix crashing on some GPUs */
	info->Vb = Gfx_CreateVb(Builder_Vertices, VERTEX_FORMAT_P3FT2FC4B, totalVerts + 1);
#endif

	Int32 i, offset = 0, partsIndex = MapRenderer_Pack(x >> CHUNK_SHIFT, y >> CHUNK_SHIFT, z >> CHUNK_SHIFT);
	bool hasNormal = false, hasTranslucent = false;

	for (i = 0; i < MapRenderer_1DUsedCount; i++) {
		Int32 j = i + ATLAS1D_MAX_ATLASES;
		Int32 curIdx = partsIndex + i * MapRenderer_ChunksCount;

		Builder_SetPartInfo(&Builder_Parts[i], &offset, &MapRenderer_PartsNormal[curIdx],      &hasNormal);
		Builder_SetPartInfo(&Builder_Parts[j], &offset, &MapRenderer_PartsTranslucent[curIdx], &hasTranslucent);
	}

	if (hasNormal) {
		info->NormalParts = &MapRenderer_PartsNormal[partsIndex];
	}
	if (hasTranslucent) {
		info->TranslucentParts = &MapRenderer_PartsTranslucent[partsIndex];
	}

#if OCCLUSION
	if (info.NormalParts != null || info.TranslucentParts != null)
		info.occlusionFlags = (UInt8)ComputeOcclusion();
#endif
}
示例#2
0
//================================================================
//================================================================
bool __cdecl RunTask(IAgent* agent, DWORD sessionId, IGenericStream* inStream, IGenericStream* outStream)
{
 EnterCriticalSection(&CS);

 DWORD dataKey = sessionId;
 
 //uncomment to allow each thread from pool to have separate global data
 //dataKey |= GetCurrentThreadId();

 TSessionDataCache::iterator i = sessionDataCache.find(dataKey);

 if (i==sessionDataCache.end())
 { 
  sessionDataCache.insert(std::make_pair(dataKey,TSessionData()));


  //----------- read global data -------------
  IGenericStream* globalDataStream;

  HRESULT rz = agent->GetData(sessionId, dataDesc, &globalDataStream);

  if (rz!=S_OK) 
  {
   LeaveCriticalSection(&CS);
   return false;
  } 

  i = sessionDataCache.find(dataKey);
   assert(i!=sessionDataCache.end());

   TSessionData* sd = &i->second;

   sd->octree = new AtiOctree(globalDataStream);

   globalDataStream->Read(&sd->highNumTris,sizeof(sd->highNumTris));
   sd->highTris = new NmRawTriangle[sd->highNumTris];
   globalDataStream->Read(sd->highTris,sd->highNumTris*sizeof(NmRawTriangle));

   globalDataStream->Read(&sd->gNumSamples,sizeof(sd->gNumSamples));
   sd->gSamples = new NmSample[sd->gNumSamples];
   globalDataStream->Read(sd->gSamples,sd->gNumSamples*sizeof(NmSample));

   globalDataStream->Read(&sd->hTangentSpace,sizeof(sd->hTangentSpace));
   if (sd->hTangentSpace!=NULL)
    {
     sd->hTangentSpace = new NmTangentMatrix[sd->highNumTris];
     globalDataStream->Read(sd->hTangentSpace,sd->highNumTris*sizeof(NmTangentMatrix));
    }

   globalDataStream->Read(&sd->bumpWidth,sizeof(sd->bumpWidth));
   globalDataStream->Read(&sd->bumpHeight,sizeof(sd->bumpHeight));
   globalDataStream->Read(&sd->bumpMap,sizeof(sd->bumpMap));
   if (sd->bumpMap!=NULL)
    {
     sd->bumpMap = new float[sd->bumpWidth*sd->bumpHeight*3];
     globalDataStream->Read(sd->bumpMap,sd->bumpWidth*sd->bumpHeight*3*sizeof(float));
    }

   globalDataStream->Read(&sd->numRays,sizeof(sd->numRays));
   if (sd->numRays!=0)
    {
     sd->rays = new NmRawPointD[sd->numRays];
     globalDataStream->Read(sd->rays,sd->numRays*sizeof(NmRawPointD));
     
     sd->rayWeights = new double[sd->numRays];
     globalDataStream->Read(sd->rayWeights,sd->numRays*sizeof(double));
    }


   {
    globalDataStream->AddRef();
    DWORD d = globalDataStream->Release();
   }
   
   globalDataStream->Release();
   
   agent->FreeCachedData(sessionId, dataDesc);
  }  
 
 TSessionData* sd = &i->second;

 LeaveCriticalSection(&CS);

//------------------------------------------

 float* img;
 float* img2;
 int minX;
 int pad;
 int maxX;
 int gWidth;
 int y;
 double x1,x2,x3,y1,y2,y3;
 double b0;
 bool gInTangentSpace;
 NmTangentMatrix tangentSpace_l;
 NmRawTriangle lTri;
 bool gOcclusion;
 bool gBentNormal;
 int numComponents;
 int gOcclIdx;
 bool gDisplacements;
 int gDispIdx;
 bool gEdgeCopy;
 int gNormalRules;
 double gMaxAngle;
 double gDistance;
 double gEpsilon;
 
 int gMaxCells = 0;
 AtiOctreeCell** gCell = NULL;

 DWORD intag;
 
 bool bFirstPass=true;
 int l;

 inStream->Read(&intag, sizeof(DWORD));

 do
 {

   inStream->Read(&img, sizeof(float*));
   inStream->Read(&img2, sizeof(float*));

   if (bFirstPass==true)
    {
     outStream->Write(&img, sizeof(float*));
     outStream->Write(&img2, sizeof(float*));
    }

   inStream->Read(&minX, sizeof(minX));
   inStream->Read(&pad, sizeof(pad));
   inStream->Read(&maxX, sizeof(maxX));
   inStream->Read(&gWidth, sizeof(gWidth));
   inStream->Read(&y, sizeof(y));
   
   inStream->Read(&x1, sizeof(x1));
   inStream->Read(&x2, sizeof(x2));
   inStream->Read(&x3, sizeof(x3));

   inStream->Read(&y1, sizeof(y1));
   inStream->Read(&y2, sizeof(y2));
   inStream->Read(&y3, sizeof(y3));
   
   inStream->Read(&b0, sizeof(b0));

   inStream->Read(&gInTangentSpace, sizeof(gInTangentSpace));

   inStream->Read(&tangentSpace_l,sizeof(NmTangentMatrix));

   inStream->Read(&lTri, sizeof(NmRawTriangle));
/*   
   if (bFirstPass)                  
    {
     octree = new AtiOctree(inStream);

     inStream->Read(&highNumTris,sizeof(highNumTris));
     highTris = new NmRawTriangle[highNumTris];
     inStream->Read(highTris,highNumTris*sizeof(NmRawTriangle));

     inStream->Read(&gNumSamples,sizeof(gNumSamples));
     gSamples = new NmSample[gNumSamples];
     inStream->Read(gSamples,gNumSamples*sizeof(NmSample));

     inStream->Read(&hTangentSpace,sizeof(hTangentSpace));
     if (hTangentSpace!=NULL)
      {
       hTangentSpace = new NmTangentMatrix[highNumTris];
       inStream->Read(hTangentSpace,highNumTris*sizeof(NmTangentMatrix));
      }

     inStream->Read(&bumpWidth,sizeof(bumpWidth));
     inStream->Read(&bumpHeight,sizeof(bumpHeight));
     inStream->Read(&bumpMap,sizeof(bumpMap));
     if (bumpMap!=NULL)
      {
       bumpMap = new float[bumpWidth*bumpHeight*3];
       inStream->Read(bumpMap,bumpWidth*bumpHeight*3*sizeof(float));
      }

     inStream->Read(&numRays,sizeof(numRays));
     if (numRays!=0)
      {
       rays = new NmRawPointD[numRays];
       inStream->Read(rays,numRays*sizeof(NmRawPointD));
       
       rayWeights = new double[numRays];
       inStream->Read(rayWeights,numRays*sizeof(double));
      }

   }
*/
   inStream->Read(&gOcclusion,sizeof(gOcclusion));
   inStream->Read(&gBentNormal,sizeof(gBentNormal));

   inStream->Read(&numComponents,sizeof(numComponents));

   inStream->Read(&gOcclIdx,sizeof(gOcclIdx));

   inStream->Read(&gDisplacements ,sizeof(gDisplacements));

   inStream->Read(&gDispIdx ,sizeof(gDispIdx));

   inStream->Read(&gEdgeCopy, sizeof(gEdgeCopy));

   inStream->Read(&gNormalRules, sizeof(gNormalRules));

   inStream->Read(&gMaxAngle, sizeof(gMaxAngle));

   inStream->Read(&gDistance, sizeof(gDistance));

   inStream->Read(&gEpsilon, sizeof(gEpsilon));

   inStream->Read(&l, sizeof(l));

   if (bFirstPass==true)
    {
     outStream->Write(&l, sizeof(l));
    }

   bFirstPass=false;



   //---------------------------------------


                 // Loop over the Xs filling in each texel of the normal map
                 
                 for (int x = (minX - pad); x <= (maxX + pad); x++)
                 {

                  if (agent->TestConnection(sessionId)!=S_OK)
                  {
                   delete[] gCell;
                   return false;
                  }

                    // Make sure this is a valid texture coordinate
                    if ((x < 0) || (x >= gWidth))
                    {
                       continue;
                    }

                    // Find Barycentric coordinates.
                    double b1 = ((x2-x) * (y3-y) - (x3-x) * (y2-y)) / b0;
                    double b2 = ((x3-x) * (y1-y) - (x1-x) * (y3-y)) / b0;
                    double b3 = ((x1-x) * (y2-y) - (x2-x) * (y1-y)) / b0;

                    // Interpolate tangent space.
                    double ts[9];
                    if (gInTangentSpace == true)
                    {
                       for (int t = 0; t < 9; t++)
                       {
  //                        ts[t] = (tangentSpace[l].m[0][t] * b1) + 
  //                                (tangentSpace[l].m[1][t] * b2) +
  //                                (tangentSpace[l].m[2][t] * b3);
                          ts[t] = (tangentSpace_l.m[0][t] * b1) + 
                                  (tangentSpace_l.m[1][t] * b2) +
                                  (tangentSpace_l.m[2][t] * b3);
                       }
                    }
                    
                    // For each sample accumulate the normal
                    double sNorm[3] = {0.0, 0.0, 0.0};
                    double sOcclusion = 0.0;
                    double sDisplacement = 0.0;
                    int sFound = 0;
                    double aNorm[3] = {0.0, 0.0, 0.0};
                    for (int s = 0; s < sd->gNumSamples; s++)
                    {
                       // Compute new x & y
                       double sX = (double)(x) + sd->gSamples[s].x;
                       double sY = (double)(y) + sd->gSamples[s].y;
                       
                       // Find Barycentric coordinates.
                       double b1 = ((x2-sX) * (y3-sY) - (x3-sX) * (y2-sY)) / b0;
                       double b2 = ((x3-sX) * (y1-sY) - (x1-sX) * (y3-sY)) / b0;
                       double b3 = ((x1-sX) * (y2-sY) - (x2-sX) * (y1-sY)) / b0;

                       // Use Barycentric coordinates to deterimine if we are
                       // are outside of the triangle.
                       if ((b1 > 1.0) || (b1 < 0.0) ||
                           (b2 > 1.0) || (b2 < 0.0) ||
                           (b3 > 1.0) || (b3 < 0.0))
                       {
                          continue;
                       }

                       // Compute position and normal
                       NmRawPointD pos;
                       NmRawPointD norm;
                       BaryInterpolate (&lTri, b1, b2, b3, pos.v, norm.v);

                       // First see if we even have an intersection.
                       double newNorm[3];
                       double newPos[3];
                       double newDisplacement = 0.0f;
                       if (FindBestIntersection (pos, norm, sd->octree, sd->highTris,
                                                 sd->hTangentSpace, sd->bumpMap, 
                                                 sd->bumpHeight, sd->bumpWidth, newNorm, 
                                                 newPos, &newDisplacement,
                                                 gNormalRules,
                                                 gMaxAngle, gDistance, gEpsilon,
                                                 gMaxCells, gCell))
                       {
                          // Normalize the new normal
                          sDisplacement += newDisplacement;
                          Normalize (newNorm);
                          
                          // Do bent normal/occlusion if needed.
                          if (gOcclusion || gBentNormal)
                          {
                             // First do the ray casting.
                             NmRawPointD bentNormal;
                             double occlusion;
                             ComputeOcclusion ((NmRawPointD*)(newPos),
                                               (NmRawPointD*)(newNorm),
                                               sd->highNumTris, sd->highTris, sd->octree,
                                               sd->numRays, sd->rays, sd->rayWeights,
                                               &bentNormal, &occlusion,
                                               gMaxCells, gCell);
                             
                             // Add it to our sample sum.
                             if (gBentNormal)
                             {
                                sNorm[0] += bentNormal.x;
                                sNorm[1] += bentNormal.y;
                                sNorm[2] += bentNormal.z;
                             }
                             else
                             {
                                sNorm[0] += newNorm[0];
                                sNorm[1] += newNorm[1];
                                sNorm[2] += newNorm[2];
                             }
                             sOcclusion += occlusion;
                             sFound++;
                          }
                          else
                          {  // Plain old normal map
                             sNorm[0] += newNorm[0];
                             sNorm[1] += newNorm[1];
                             sNorm[2] += newNorm[2];
                             sFound++;
                          }
                       } // end if we found a normal
                    } // end for samples (s);

                    // If we found a normal put it in the image.
                    if (sFound > 0)
                    {
                       // Convert to tangent space if needed
                       if (gInTangentSpace == true)
                       {
                          ConvertToTangentSpace (ts, sNorm, sNorm);
                       }

                       // Add it to the image.
                       int idx = y*gWidth*numComponents + x*numComponents;
                       
                       //======== write result ==============
                       BYTE ostag;
                       DWORD osindex;
                       float osval;
                       
                       ostag = 3;
                       osindex = idx;
                       osval = (float)sNorm[0];
                       outStream->Write(&ostag,sizeof(ostag));
                       outStream->Write(&osindex,sizeof(osindex));
                       outStream->Write(&osval,sizeof(osval));

                       ostag = 3;
                       osindex = idx+1;
                       osval = (float)sNorm[1];
                       outStream->Write(&ostag,sizeof(ostag));
                       outStream->Write(&osindex,sizeof(osindex));
                       outStream->Write(&osval,sizeof(osval));

                       ostag = 3;
                       osindex = idx+2;
                       osval = (float)sNorm[2];
                       outStream->Write(&ostag,sizeof(ostag));
                       outStream->Write(&osindex,sizeof(osindex));
                       outStream->Write(&osval,sizeof(osval));
                       
                       
  //                     img[idx + 0] += (float)sNorm[0];
  //                     img[idx + 1] += (float)sNorm[1];
  //                     img[idx + 2] += (float)sNorm[2];

                       if (gOcclusion)
                       {
                        ostag = 1;
                        osindex = idx + gOcclIdx;
                        osval = (float)(sOcclusion/sFound);
                        outStream->Write(&ostag,sizeof(ostag));
                        outStream->Write(&osindex,sizeof(osindex));
                        outStream->Write(&osval,sizeof(osval));
                       
  //                        img[idx + gOcclIdx] = (float)(sOcclusion/sFound);
                       }
                       if (gDisplacements)
                       {
                        ostag = 1;
                        osindex = idx + gDispIdx;
                        osval = (float)(sDisplacement/sFound);
                        outStream->Write(&ostag,sizeof(ostag));
                        outStream->Write(&osindex,sizeof(osindex));
                        outStream->Write(&osval,sizeof(osval));
  //                        img[idx + gDispIdx] = (float)(sDisplacement/sFound);
                       }

                       //====================================
                    } // end if we found a normal
                    else if (gEdgeCopy)
                    {
                       // Since we didn't find a normal, "snap" the center
                       // sample's barycentric coordinates to the edge of the
                       // triangle and find the normal there. Store this in
                       // a temporary buffer that we'll use to dilate the image
                       // in a way that doesn't produce texture seams.
                       double sX = (double)x;
                       double sY = (double)y;
                       double b1 = ((x2-sX) * (y3-sY) - (x3-sX) * (y2-sY)) / b0;
                       double b2 = ((x3-sX) * (y1-sY) - (x1-sX) * (y3-sY)) / b0;
                       double b3 = ((x1-sX) * (y2-sY) - (x2-sX) * (y1-sY)) / b0;
                       
                       // "Snap" barycentric coordinates.
                       if (b1 > 1.0)
                       {
                          double diff = b1 - 1.0;
                          b1 = 1.0;
                          b2 += (diff/2.0);
                          b3 += (diff/2.0);
                       }
                       if (b1 < 0.0)
                       {
                          double diff = b1;
                          b1 = 0.0;
                          b2 += (diff/2.0);
                          b3 += (diff/2.0);
                       }
                       if (b2 > 1.0)
                       {
                          double diff = b2 - 1.0;
                          b1 = 1.0;
                          b1 += (diff/2.0);
                          b3 += (diff/2.0);
                       }
                       if (b2 < 0.0)
                       {
                          double diff = b2;
                          b2 = 0.0;
                          b1 += (diff/2.0);
                          b3 += (diff/2.0);
                       }
                       if (b3 > 1.0)
                       {
                          double diff = b3 - 1.0;
                          b3 = 1.0;
                          b2 += (diff/2.0);
                          b1 += (diff/2.0);
                       }
                       if (b3 < 0.0)
                       {
                          double diff = b3;
                          b3 = 0.0;
                          b2 += (diff/2.0);
                          b1 += (diff/2.0);
                       }

                       // Compute position and normal
                       NmRawPointD pos;
                       NmRawPointD norm;
                       BaryInterpolate (&lTri, b1, b2, b3, pos.v, norm.v);

                       // First see if we even have an intersection.
                       double newNorm[3];
                       double newPos[3];
                       double newOcclusion = 0.0;
                       double newDisplacement = 0.0;
                       if (FindBestIntersection (pos, norm, sd->octree, sd->highTris,
                                                 sd->hTangentSpace, sd->bumpMap, 
                                                 sd->bumpHeight, sd->bumpWidth, newNorm, 
                                                 newPos, &newDisplacement,
                                                 gNormalRules,
                                                 gMaxAngle, gDistance, gEpsilon,
                                                 gMaxCells, gCell))
                       {
                          // Normalize the new normal
                          Normalize (newNorm);
                          
                          // Do bent normal/occlusion if needed.
                          if (gOcclusion || gBentNormal)
                          {
                             // First do the ray casting.
                             NmRawPointD bentNormal;
                             ComputeOcclusion ((NmRawPointD*)(newPos),
                                               (NmRawPointD*)(newNorm),
                                               sd->highNumTris, sd->highTris, sd->octree,
                                               sd->numRays, sd->rays, sd->rayWeights,
                                               &bentNormal, &newOcclusion,
                                               gMaxCells, gCell);
                             
                             // Replace normal with bent normal if needed
                             if (gBentNormal)
                             {
                                newNorm[0] += bentNormal.x;
                                newNorm[1] += bentNormal.y;
                                newNorm[2] += bentNormal.z;
                             }
                          } // do ambient occlusion if needed

                          
                          // Convert to tangent space if needed
                          if (gInTangentSpace == true)
                          {
                             ConvertToTangentSpace (ts, newNorm, newNorm);
                          }

                          // Add it to the image.
                          int idx = y*gWidth*numComponents + x*numComponents;

                          BYTE ostag;
                          DWORD osindex;
                          float osval;
                          
                          ostag = 4;
                          osindex = idx;
                          osval = (float)newNorm[0];
                          outStream->Write(&ostag,sizeof(ostag));
                          outStream->Write(&osindex,sizeof(osindex));
                          outStream->Write(&osval,sizeof(osval));

                          ostag = 4;
                          osindex = idx+1;
                          osval = (float)newNorm[1];
                          outStream->Write(&ostag,sizeof(ostag));
                          outStream->Write(&osindex,sizeof(osindex));
                          outStream->Write(&osval,sizeof(osval));

                          ostag = 4;
                          osindex = idx+2;
                          osval = (float)newNorm[2];
                          outStream->Write(&ostag,sizeof(ostag));
                          outStream->Write(&osindex,sizeof(osindex));
                          outStream->Write(&osval,sizeof(osval));

  //                        img2[idx + 0] += (float)newNorm[0];
  //                        img2[idx + 1] += (float)newNorm[1];
  //                        img2[idx + 2] += (float)newNorm[2];

                          if (gOcclusion)
                          {
                           ostag = 2;
                           osindex = idx + gOcclIdx;
                           osval = (float)(newOcclusion);
                           outStream->Write(&ostag,sizeof(ostag));
                           outStream->Write(&osindex,sizeof(osindex));
                           outStream->Write(&osval,sizeof(osval));
                          
  //                           img2[idx + gOcclIdx] = (float)(newOcclusion);
                          }
                          if (gDisplacements)
                          {
                           ostag = 2;
                           osindex = idx + gDispIdx;
                           osval = (float)(newDisplacement);
                           outStream->Write(&ostag,sizeof(ostag));
                           outStream->Write(&osindex,sizeof(osindex));
                           outStream->Write(&osval,sizeof(osval));

  //                           img2[idx + gDispIdx] = (float)(newDisplacement);
                          }
                       } // end if we found a normal
                       // else don't add anything to either image.
                    } // end else find a "snapped" normal
                    // Spin!
  //                  ShowSpinner (prog);
                 } // end for x
                    
   inStream->Read(&intag, sizeof(DWORD));

  } while (intag==1);

 delete[] gCell;
 gMaxCells = 0;
 gCell=NULL;
 

 BYTE ostag;
 ostag = 0;
 outStream->Write(&ostag,sizeof(ostag));

 DWORD tricount;
 inStream->Read(&tricount, sizeof(tricount));
 outStream->Write(&tricount, sizeof(tricount));

 return true;
}
示例#3
0
static void Builder_Stretch(Int32 x1, Int32 y1, Int32 z1) {
	Int32 xMax = min(World_Width,  x1 + CHUNK_SIZE);
	Int32 yMax = min(World_Height, y1 + CHUNK_SIZE);
	Int32 zMax = min(World_Length, z1 + CHUNK_SIZE);
#if OCCLUSION
	Int32 flags = ComputeOcclusion();
#endif
#if DEBUG_OCCLUSION
	FastColour col = new FastColour(60, 60, 60, 255);
	if (flags & 1) col.R = 255; // x
	if (flags & 4) col.G = 255; // y
	if (flags & 2) col.B = 255; // z
	map.Sunlight = map.Shadowlight = col;
	map.SunlightXSide = map.ShadowlightXSide = col;
	map.SunlightZSide = map.ShadowlightZSide = col;
	map.SunlightYBottom = map.ShadowlightYBottom = col;
#endif

	Int32 x, y, z, xx, yy, zz;
	for (y = y1, yy = 0; y < yMax; y++, yy++) {
		for (z = z1, zz = 0; z < zMax; z++, zz++) {
			Int32 cIndex = (yy + 1) * EXTCHUNK_SIZE_2 + (zz + 1) * EXTCHUNK_SIZE + (-1 + 1);
			for (x = x1, xx = 0; x < xMax; x++, xx++) {
				cIndex++;
				BlockID b = Builder_Chunk[cIndex];
				if (Block_Draw[b] == DRAW_GAS) continue;
				Int32 index = ((yy << 8) | (zz << 4) | xx) * FACE_COUNT;

				/* Sprites only use one face to indicate stretching count, so we can take a shortcut here.
				Note that sprites are not drawn with any of the DrawXFace, they are drawn using DrawSprite. */
				if (Block_Draw[b] == DRAW_SPRITE) {
					index += FACE_YMAX;
					if (Builder_Counts[index]) {
						Builder_X = x; Builder_Y = y; Builder_Z = z;
						Builder_AddSpriteVertices(b);
						Builder_Counts[index] = 1;
					}
					continue;
				}

				Builder_X = x; Builder_Y = y; Builder_Z = z;
				Builder_FullBright = Block_FullBright[b];
				UInt32 tileIdx = b * BLOCK_COUNT;
				/* All of these function calls are inlined as they can be called tens of millions to hundreds of millions of times. */

				if (Builder_Counts[index] == 0 ||
					(x == 0 && (y < Builder_SidesLevel || (b >= BLOCK_WATER && b <= BLOCK_STILL_LAVA && y < Builder_EdgeLevel))) ||
					(x != 0 && (Block_Hidden[tileIdx + Builder_Chunk[cIndex - 1]] & (1 << FACE_XMIN)) != 0)) {
					Builder_Counts[index] = 0;
				} else {
					Int32 count = Builder_StretchZ(index, x, y, z, cIndex, b, FACE_XMIN);
					Builder_AddVertices(b, FACE_XMIN);
					Builder_Counts[index] = (UInt8)count;
				}

				index++;
				if (Builder_Counts[index] == 0 ||
					(x == World_MaxX && (y < Builder_SidesLevel || (b >= BLOCK_WATER && b <= BLOCK_STILL_LAVA && y < Builder_EdgeLevel))) ||
					(x != World_MaxX && (Block_Hidden[tileIdx + Builder_Chunk[cIndex + 1]] & (1 << FACE_XMAX)) != 0)) {
					Builder_Counts[index] = 0;
				} else {
					Int32 count = Builder_StretchZ(index, x, y, z, cIndex, b, FACE_XMAX);
					Builder_AddVertices(b, FACE_XMAX);
					Builder_Counts[index] = (UInt8)count;
				}

				index++;
				if (Builder_Counts[index] == 0 ||
					(z == 0 && (y < Builder_SidesLevel || (b >= BLOCK_WATER && b <= BLOCK_STILL_LAVA && y < Builder_EdgeLevel))) ||
					(z != 0 && (Block_Hidden[tileIdx + Builder_Chunk[cIndex - EXTCHUNK_SIZE]] & (1 << FACE_ZMIN)) != 0)) {
					Builder_Counts[index] = 0;
				} else {
					Int32 count = Builder_StretchX(index, Builder_X, Builder_Y, Builder_Z, cIndex, b, FACE_ZMIN);
					Builder_AddVertices(b, FACE_ZMIN);
					Builder_Counts[index] = (UInt8)count;
				}

				index++;
				if (Builder_Counts[index] == 0 ||
					(z == World_MaxZ && (y < Builder_SidesLevel || (b >= BLOCK_WATER && b <= BLOCK_STILL_LAVA && y < Builder_EdgeLevel))) ||
					(z != World_MaxZ && (Block_Hidden[tileIdx + Builder_Chunk[cIndex + EXTCHUNK_SIZE]] & (1 << FACE_ZMAX)) != 0)) {
					Builder_Counts[index] = 0;
				} else {
					Int32 count = Builder_StretchX(index, x, y, z, cIndex, b, FACE_ZMAX);
					Builder_AddVertices(b, FACE_ZMAX);
					Builder_Counts[index] = (UInt8)count;
				}

				index++;
				if (Builder_Counts[index] == 0 || y == 0 ||
					(Block_Hidden[tileIdx + Builder_Chunk[cIndex - EXTCHUNK_SIZE_2]] & (1 << FACE_YMIN)) != 0) {
					Builder_Counts[index] = 0;
				} else {
					Int32 count = Builder_StretchX(index, x, y, z, cIndex, b, FACE_YMIN);
					Builder_AddVertices(b, FACE_YMIN);
					Builder_Counts[index] = (UInt8)count;
				}

				index++;
				if (Builder_Counts[index] == 0 ||
					(Block_Hidden[tileIdx + Builder_Chunk[cIndex + EXTCHUNK_SIZE_2]] & (1 << FACE_YMAX)) != 0) {
					Builder_Counts[index] = 0;
				} else if (b < BLOCK_WATER || b > BLOCK_STILL_LAVA) {
					Int32 count = Builder_StretchX(index, x, y, z, cIndex, b, FACE_YMAX);
					Builder_AddVertices(b, FACE_YMAX);
					Builder_Counts[index] = (UInt8)count;
				} else {
					Int32 count = Builder_StretchXLiquid(index, x, y, z, cIndex, b);
					if (count > 0) Builder_AddVertices(b, FACE_YMAX);
					Builder_Counts[index] = (UInt8)count;
				}
			}
		}
	}
}