示例#1
0
bool GFXGLShader::initShader( const Torque::Path &file, 
                              bool isVertex, 
                              const Vector<GFXShaderMacro> &macros )
{
   PROFILE_SCOPE(GFXGLShader_CompileShader);
   GLuint activeShader = glCreateShader(isVertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
   if(isVertex)
      mVertexShader = activeShader;
   else
      mPixelShader = activeShader;
   glAttachShader(mProgram, activeShader);
   
   
   // Ok it's not in the shader gen manager, so ask Torque for it
   FileStream stream;
   if ( !stream.open( file, Torque::FS::File::Read ) )
   {
      AssertISV(false, avar("GFXGLShader::initShader - failed to open shader '%s'.", file.getFullPath().c_str()));

      if ( smLogErrors )
         Con::errorf( "GFXGLShader::initShader - Failed to open shader file '%s'.", 
            file.getFullPath().c_str() );

      return false;
   }
   
   if ( !_loadShaderFromStream( activeShader, file, &stream, macros ) )
      return false;
   
   GLint compile;
   glGetShaderiv(activeShader, GL_COMPILE_STATUS, &compile);

   // Dump the info log to the console
   U32 logLength = 0;
   glGetShaderiv(activeShader, GL_INFO_LOG_LENGTH, (GLint*)&logLength);
   
   GLint compileStatus = GL_TRUE;
   if ( logLength )
   {
      FrameAllocatorMarker fam;
      char* log = (char*)fam.alloc(logLength);
      glGetShaderInfoLog(activeShader, logLength, NULL, log);

      // Always print errors
      glGetShaderiv( activeShader, GL_COMPILE_STATUS, &compileStatus );

      if ( compileStatus == GL_FALSE )
      {
         if ( smLogErrors )
         {
            Con::errorf( "GFXGLShader::initShader - Error compiling shader!" );
            Con::errorf( "Program %s: %s", file.getFullPath().c_str(), log );
         }
      }
      else if ( smLogWarnings )
         Con::warnf( "Program %s: %s", file.getFullPath().c_str(), log );
   }

   return compileStatus != GL_FALSE;
}
bool GFXGLTextureObject::copyToBmp(GBitmap * bmp)
{
   if (!bmp)
      return false;

   // check format limitations
   // at the moment we only support RGBA for the source (other 4 byte formats should
   // be easy to add though)
   AssertFatal(mFormat == GFXFormatR8G8B8A8, "GFXGLTextureObject::copyToBmp - invalid format");
   AssertFatal(bmp->getFormat() == GFXFormatR8G8B8A8 || bmp->getFormat() == GFXFormatR8G8B8, "GFXGLTextureObject::copyToBmp - invalid format");
   if(mFormat != GFXFormatR8G8B8A8)
      return false;

   if(bmp->getFormat() != GFXFormatR8G8B8A8 && bmp->getFormat() != GFXFormatR8G8B8)
      return false;

   AssertFatal(bmp->getWidth() == getWidth(), "GFXGLTextureObject::copyToBmp - invalid size");
   AssertFatal(bmp->getHeight() == getHeight(), "GFXGLTextureObject::copyToBmp - invalid size");

   PROFILE_SCOPE(GFXGLTextureObject_copyToBmp);

   PRESERVE_TEXTURE(mBinding);
   glBindTexture(mBinding, mHandle);

   U8 dstBytesPerPixel = GFXFormat_getByteSize( bmp->getFormat() );
   U8 srcBytesPerPixel = GFXFormat_getByteSize( mFormat );
   if(dstBytesPerPixel == srcBytesPerPixel)
   {
      glGetTexImage(mBinding, 0, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], bmp->getWritableBits());
      return true;
   }

   FrameAllocatorMarker mem;
   
   U32 srcPixelCount = mTextureSize.x * mTextureSize.y;
   U8 *dest = bmp->getWritableBits();
   U8 *orig = (U8*)mem.alloc(srcPixelCount * srcBytesPerPixel);

   glGetTexImage(mBinding, 0, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], orig);
   
   for(int i = 0; i < srcPixelCount; ++i)
   {
      dest[0] = orig[0];
      dest[1] = orig[1];
      dest[2] = orig[2];
      if(dstBytesPerPixel == 4)
         dest[3] = orig[3];

      orig += srcBytesPerPixel;
      dest += dstBytesPerPixel;
   }

   return true;
}
示例#3
0
void DeferredPNGWriter::append( GBitmap* bitmap, U32 rows)
{
   AssertFatal(mActive, "Cannot append to an inactive DeferredPNGWriter!");

   U32 height = getMin( bitmap->getHeight(), rows);

   FrameAllocatorMarker marker;
   png_bytep* row_pointers = (png_bytep*)marker.alloc( height * sizeof( png_bytep ) );
   for (U32 i=0; i<height; i++)
      row_pointers[i] = const_cast<png_bytep>(bitmap->getAddress(0, i));

   png_write_rows(mData->png_ptr, row_pointers, height);
}
bool QuadTreeTracer::castRay(const Point3F &start, const Point3F &end, RayInfo *info)
{
   PROFILE_START(QuadTreeTracer_castRay);

   // Do some precalculations we'll use for the rest of this routine.
   // Set up our intercept calculation methods.
   F32 invDeltaX;
   if(end.x == start.x)
   {
      calcInterceptX = calcInterceptNone;
      invDeltaX = 0;
   }
   else
   {
      invDeltaX = 1.f / (end.x - start.x);
      calcInterceptX = calcInterceptV;
   }

   F32 invDeltaY;
   if(end.y == start.y)
   {
      calcInterceptY = calcInterceptNone;
      invDeltaY = 0;
   }
   else
   {
      invDeltaY = 1.f / (end.y - start.y);
      calcInterceptY = calcInterceptV;
   }

   // Subdivide our space based on the size of the lowest level of the tree...
   const F32 invSize   = 1.f / F32(BIT(mTreeDepth-1));

   // Grab this off the frame allocator, we don't want to do a proper alloc
   // on every ray!
   FrameAllocatorMarker stackAlloc;
   RayStackNode *stack = (RayStackNode*)stackAlloc.alloc(sizeof(RayStackNode) * (mTreeDepth * 3 + 1));

   U32 stackSize = 1;

   // Kick off the stack with the root node.
   stack[0].startT   = 0;
   stack[0].endT     = 1;
   stack[0].squarePos.set(0,0);
   stack[0].level    = mTreeDepth - 1;

   //Con::printf("QuadTreeTracer::castRay(%x)", this);

   // Aright, now let's do some raycasting!
   while(stackSize--)
   {
      // Get the current node for easy access...
      RayStackNode *sn = stack + stackSize;

      const U32 level         = sn->level;
      const F32 startT        = sn->startT;
      const F32 endT          = sn->endT;
      const Point2I squarePos = sn->squarePos;

      AssertFatal((startT >= 0.f) && (startT <= 1.f),  "QuadTreeTracer::castRay - out of range startT on stack!");
      AssertFatal((endT >= 0.f) && (endT <= 1.f),     "QuadTreeTracer::castRay - out of range endT   on stack!");

      //Con::printf(" -- node(%d, %d @ %d), sT=%f, eT=%f", squarePos.x, squarePos.y, level, startT, endT);

      // Figure our start and end Z.
      const F32 startZ = startT * (end.z - start.z) + start.z;
      const F32 endZ   = endT   * (end.z - start.z) + start.z;

      // Ok, now let's see if we hit the lower bound
      const F32 squareMin = getSquareMin(level, squarePos);

      if(startZ < squareMin && endZ < squareMin)
         continue; //Nope, skip out.

      // Hmm, let's check the upper bound.
      const F32 squareMax = getSquareMax(level, squarePos);

      if(startZ > squareMax && endZ > squareMax)
         continue; //Nope, skip out.

      // We might be intersecting something... If we've hit
      // the tree depth let's deal with the leaf intersection.
      if(level == 0)
      {
         //Con::printf(" ++ check node(%d, %d @ %d), sT=%f, eT=%f", squarePos.x, squarePos.y, level, startT, endT);

         if(castLeafRay(squarePos, start, end, startT, endT, info))
         {
            PROFILE_END();
            return true; // We hit, tell 'em so!
         }
         continue; // Otherwise, keep looking.
      }
      else
      {
         // Ok, we have to push our children as we're an inner node.

         // First, figure out some widths...
         U32 subSqSize  = BIT(level - 1);

         // Now, calculate intercepts so we know how to deal with this
         // situation... (intercept = position, int = t value for that pos)

         const F32 xIntercept = (squarePos.x + subSqSize) * invSize;
         F32 xInt = calcInterceptX(start.x, invDeltaX, xIntercept);

         const F32 yIntercept = (squarePos.y + subSqSize) * invSize;
         F32 yInt = calcInterceptY(start.y, invDeltaY, yIntercept);

         // Our starting position for this subray...
         const F32 startX = startT * (end.x - start.x) + start.x;
         const F32 startY = startT * (end.y - start.y) + start.y;

         // Deal with squares that might be "behind" the ray.
         if(xInt < startT) xInt = F32_MAX;
         if(yInt < startT) yInt = F32_MAX;

         // Do a little magic to calculate our next checks...
         const U32 x0 = (startX > xIntercept) * subSqSize;
         const U32 y0 = (startY > yIntercept) * subSqSize;

         const U32 x1 = subSqSize - x0;
         const U32 y1 = subSqSize - y0;

         const U32 nextLevel = level - 1;

         // Ok, now let's figure out what nodes, in what order, need to go
         // on the stack. We push things on in reverse order of processing.
         if(xInt > endT && yInt > endT)
         {
            stack[stackSize].squarePos.set(squarePos.x + x0, squarePos.y + y0);
            stack[stackSize].level = nextLevel;
            stackSize++;
         }
         else if(xInt < yInt)
         {
            F32 nextIntersect = endT;

            if(yInt <= endT)
            {
               stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y1);
               stack[stackSize].startT = yInt;
               stack[stackSize].endT   = endT;
               stack[stackSize].level  = nextLevel;
               nextIntersect = yInt;
               stackSize++;
            }

            // Do middle two, order doesn't matter.
            stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y0);
            stack[stackSize].startT = xInt;
            stack[stackSize].endT   = nextIntersect;
            stack[stackSize].level  = nextLevel;

            stack[stackSize+1].squarePos.set(squarePos.x + x0, squarePos.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].squarePos.set(squarePos.x + x1, squarePos.y + y1);
               stack[stackSize].startT = xInt;
               stack[stackSize].endT   = endT;
               stack[stackSize].level  = nextLevel;
               nextIntersect = xInt;
               stackSize++;
            }
            stack[stackSize].squarePos.set(squarePos.x + x0, squarePos.y + y1);
            stack[stackSize].startT  = yInt;
            stack[stackSize].endT    = nextIntersect;
            stack[stackSize].level   = nextLevel;

            stack[stackSize+1].squarePos.set(squarePos.x + x0, squarePos.y + y0);
            stack[stackSize+1].startT = startT;
            stack[stackSize+1].endT   = yInt;
            stack[stackSize+1].level  = nextLevel;
            stackSize += 2;
         }
         else
         {
            stack[stackSize].squarePos.set(squarePos.x + x1, squarePos.y + y1);
            stack[stackSize].startT = xInt;
            stack[stackSize].endT   = endT;
            stack[stackSize].level  = nextLevel;

            stack[stackSize+1].squarePos.set(squarePos.x + x0, squarePos.y + y0);
            stack[stackSize+1].startT = startT;
            stack[stackSize+1].endT   = xInt;
            stack[stackSize+1].level  = nextLevel;
            stackSize += 2;
         }
      }
   }

   // Nothing found, so give up.
   PROFILE_END();
   return false;
}
示例#5
0
bool GFXGLShader::_init()
{
   // Don't initialize empty shaders.
   if ( mVertexFile.isEmpty() && mPixelFile.isEmpty() )
      return false;

   clearShaders();

   mProgram = glCreateProgram();
   
   // Set the macros and add the global ones.
   Vector<GFXShaderMacro> macros;
   macros.merge( mMacros );
   macros.merge( smGlobalMacros );

   // Add the shader version to the macros.
   const U32 mjVer = (U32)mFloor( mPixVersion );
   const U32 mnVer = (U32)( ( mPixVersion - F32( mjVer ) ) * 10.01f );
   macros.increment();
   macros.last().name = "TORQUE_SM";
   macros.last().value = String::ToString( mjVer * 10 + mnVer );

   // Default to true so we're "successful" if a vertex/pixel shader wasn't specified.
   bool compiledVertexShader = true;
   bool compiledPixelShader = true;
   
   // Compile the vertex and pixel shaders if specified.
   if(!mVertexFile.isEmpty())
      compiledVertexShader = initShader(mVertexFile, true, macros);
   if(!mPixelFile.isEmpty())
      compiledPixelShader = initShader(mPixelFile, false, macros);
      
   // If either shader was present and failed to compile, bail.
   if(!compiledVertexShader || !compiledPixelShader)
      return false;

   // Link it!
   glLinkProgram( mProgram );

   GLint linkStatus;
   glGetProgramiv( mProgram, GL_LINK_STATUS, &linkStatus );
   
   // Dump the info log to the console
   U32 logLength = 0;
   glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, (GLint*)&logLength);
   if ( logLength )
   {
      FrameAllocatorMarker fam;
      char* log = (char*)fam.alloc( logLength );
      glGetProgramInfoLog( mProgram, logLength, NULL, log );

      if ( linkStatus == GL_FALSE )
      {
         if ( smLogErrors )
         {
            Con::errorf( "GFXGLShader::init - Error linking shader!" );
            Con::errorf( "Program %s / %s: %s", 
                mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log);
         }
      }
      else if ( smLogWarnings )
      {
         Con::warnf( "Program %s / %s: %s", 
             mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log);
      }
   }

   // If we failed to link, bail.
   if ( linkStatus == GL_FALSE )
      return false;

   initConstantDescs();   
   initHandles();
   
   // Notify Buffers we might have changed in size. 
   // If this was our first init then we won't have any activeBuffers 
   // to worry about unnecessarily calling.
   Vector<GFXShaderConstBuffer*>::iterator biter = mActiveBuffers.begin();
   for ( ; biter != mActiveBuffers.end(); biter++ )   
      ((GFXGLShaderConstBuffer*)(*biter))->onShaderReload( this );
   
   return true;
}
示例#6
0
bool GFXGLShader::_init()
{
   PROFILE_SCOPE(GFXGLShader_Init);
   // Don't initialize empty shaders.
   if ( mVertexFile.isEmpty() && mPixelFile.isEmpty() )
      return false;

   clearShaders();

   mProgram = glCreateProgram();
   
   // Set the macros and add the global ones.
   Vector<GFXShaderMacro> macros;
   macros.merge( mMacros );
   macros.merge( smGlobalMacros );

   // Add the shader version to the macros.
   const U32 mjVer = (U32)mFloor( mPixVersion );
   const U32 mnVer = (U32)( ( mPixVersion - F32( mjVer ) ) * 10.01f );
   macros.increment();
   macros.last().name = "TORQUE_SM";
   macros.last().value = String::ToString( mjVer * 10 + mnVer );
   macros.increment();
   macros.last().name = "TORQUE_VERTEX_SHADER";
   macros.last().value = "";   

   // Default to true so we're "successful" if a vertex/pixel shader wasn't specified.
   bool compiledVertexShader = true;
   bool compiledPixelShader = true;
   
   // Compile the vertex and pixel shaders if specified.
   if(!mVertexFile.isEmpty())
      compiledVertexShader = initShader(mVertexFile, true, macros);

   macros.last().name = "TORQUE_PIXEL_SHADER";
   if(!mPixelFile.isEmpty())
      compiledPixelShader = initShader(mPixelFile, false, macros);
      
   // If either shader was present and failed to compile, bail.
   if(!compiledVertexShader || !compiledPixelShader)
      return false;

   //bind vertex attributes
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Position,    "vPosition");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Normal,      "vNormal");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Color,       "vColor");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Tangent,     "vTangent");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TangentW,    "vTangentW");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Binormal,    "vBinormal");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord0,   "vTexCoord0");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord1,   "vTexCoord1");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord2,   "vTexCoord2");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord3,   "vTexCoord3");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord4,   "vTexCoord4");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord5,   "vTexCoord5");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord6,   "vTexCoord6");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord7,   "vTexCoord7");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord8,   "vTexCoord8");
   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord9,   "vTexCoord9");

   //bind fragment out color
   glBindFragDataLocation(mProgram, 0, "OUT_col");
   glBindFragDataLocation(mProgram, 1, "OUT_col1");
   glBindFragDataLocation(mProgram, 2, "OUT_col2");
   glBindFragDataLocation(mProgram, 3, "OUT_col3");

   // Link it!
   glLinkProgram( mProgram );

   GLint linkStatus;
   glGetProgramiv( mProgram, GL_LINK_STATUS, &linkStatus );
   
   // Dump the info log to the console
   U32 logLength = 0;
   glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, (GLint*)&logLength);
   if ( logLength )
   {
      FrameAllocatorMarker fam;
      char* log = (char*)fam.alloc( logLength );
      glGetProgramInfoLog( mProgram, logLength, NULL, log );

      if ( linkStatus == GL_FALSE )
      {
         if ( smLogErrors )
         {
            Con::errorf( "GFXGLShader::init - Error linking shader!" );
            Con::errorf( "Program %s / %s: %s", 
                mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log);
         }
      }
      else if ( smLogWarnings )
      {
         Con::warnf( "Program %s / %s: %s", 
             mVertexFile.getFullPath().c_str(), mPixelFile.getFullPath().c_str(), log);
      }
   }

   // If we failed to link, bail.
   if ( linkStatus == GL_FALSE )
      return false;

   initConstantDescs();   
   initHandles();
   
   // Notify Buffers we might have changed in size. 
   // If this was our first init then we won't have any activeBuffers 
   // to worry about unnecessarily calling.
   Vector<GFXShaderConstBuffer*>::iterator biter = mActiveBuffers.begin();
   for ( ; biter != mActiveBuffers.end(); biter++ )   
      ((GFXGLShaderConstBuffer*)(*biter))->onShaderReload( this );
   
   return true;
}
示例#7
0
void AtlasOldMesher::writeCollision(Stream *s)
{
   // First, do the binning. This is a bit gross but, hey, what can you do...
   const U32 gridSize = BIT(gAtlasColTreeDepth-1);
   const U32 gridCount = gridSize * gridSize;

   Vector<U16> bins[gridCount];

   // Track the min/max for the bins.
   S16 binsMax[gridCount];
   S16 binsMin[gridCount];

   // Clear bins.
   for(S32 i=0; i<gridCount; i++)
   {
      binsMax[i] = S16_MIN;
      binsMin[i] = S16_MAX;
   }

   // Get the size of bins (we step in x/y, not in Z).
   Point3F binSize( mBounds.len_x() / F32(gridSize), mBounds.len_y() / F32(gridSize), mBounds.len_z());

   for(S32 i=0; i<gridSize; i++)
   {
      for(S32 j=0; j<gridSize; j++)
      {
         // Figure the bounds for this bin...
         Box3F binBox;

         binBox.minExtents.x = binSize.x * i;
         binBox.minExtents.y = binSize.y * j;
         binBox.minExtents.z = mBounds.minExtents.z - 1.f;

         binBox.maxExtents.x = binSize.x * (i+1);
         binBox.maxExtents.y = binSize.y * (j+1);
         binBox.maxExtents.z = mBounds.maxExtents.z + 1.f;

         Vector<U16> &binList = bins[i * gridSize + j];

         S16 &binMin = binsMin[i * gridSize + j];
         S16 &binMax = binsMax[i * gridSize + j];

         // Now, consider all the triangles in the mesh. Note: we assume a trilist.
         for(S32 v=0; v<mIndices.size(); v+=3)
         {
            // Get the verts.
            const Vert &a = mVerts[mIndices[v+0]];
            const Vert &b = mVerts[mIndices[v+1]];
            const Vert &c = mVerts[mIndices[v+2]];

            // If it's a special, skip it, we don't want to collide with skirts.
            if(a.special ||
               b.special ||
               c.special)
               continue; // I can't stand skirts!

            // Reject anything degenerate...
            if(mIndices[v+0] == mIndices[v+1])
               continue;
            if(mIndices[v+1] == mIndices[v+2])
               continue;
            if(mIndices[v+2] == mIndices[v+0])
               continue;

            // Otherwise, we're good, so consider it for the current bin.
            const Point3F aPos = getVertPos(a);
            const Point3F bPos = getVertPos(b);
            const Point3F cPos = getVertPos(c);

            if(triBoxOverlap(binBox, aPos, bPos, cPos))
            {
               // Got a hit, add it to the list!
               binList.push_back(v);

               // Update the min/max info. This will be TOO BIG if we have a
               // very large triangle! An optimal implementation will do a clip,
               // then update the bin. This is probably ok for the moment.
               S16 hA = mHeight->sample(a.pos);
               S16 hB = mHeight->sample(b.pos);
               S16 hC = mHeight->sample(c.pos);

               if(hA > binMax) binMax = hA;
               if(hB > binMax) binMax = hB;
               if(hC > binMax) binMax = hC;

               if(hA < binMin) binMin = hA;
               if(hB < binMin) binMin = hB;
               if(hC < binMin) binMin = hC;
            }
         }

		 // Limit the triangle count to 16bits.  While primary meshes support more
		 // than that, collision meshes don't.  If we don't catch that here, we'll
		 // see raycasting issues later in Atlas.
		 AssertISV( binList.size() <= 65536,
			 "AtlasOldMesher::writeCollision - too many triangles! (>65536)  Try again with a deeper tree" );

         // Ok, we're all set for this bin...
         AssertFatal(binMin <= binMax,
            "AtlasOldMesher::writeCollision - empty bin, crap!");
      }
   }

   // Next, generate the quadtree.
   FrameAllocatorMarker qtPool;
   const U32 nodeCount = QuadTreeTracer::getNodeCount(gAtlasColTreeDepth);
   S16 *qtMin = (S16*)qtPool.alloc(sizeof(S16) * nodeCount);
   S16 *qtMax = (S16*)qtPool.alloc(sizeof(S16) * nodeCount);

   // We have to recursively generate this from the bins on up. First we copy
   // the bins from earlier, then we do our recursomatic thingummy. (It's
   // actually not recursive.)
   for(S32 i=0; i<gridSize; i++)
   {
      for(S32 j=0; j<gridSize; j++)
      {
         const U32 qtIdx = QuadTreeTracer::getNodeIndex(gAtlasColTreeDepth-1, Point2I(i,j));

         qtMin[qtIdx] = binsMin[i * gridSize + j];
         qtMax[qtIdx] = binsMax[i * gridSize + j];

         AssertFatal(qtMin[qtIdx] <= qtMax[qtIdx],
            "AtlasOldMesher::writeCollision - bad child quadtree node min/max! (negative a)");

      }
   }

   // Alright, now we go up the bins, generating from the four children of each,
   // till we hit the root.

   // For each empty level from bottom to top...
   for(S32 depth = gAtlasColTreeDepth - 2; depth >= 0; depth--)
   {
      // For each square...
      for(S32 i=0; i<BIT(depth); i++)
      for(S32 j=0; j<BIT(depth); j++)
      {
         const U32 curIdx = QuadTreeTracer::getNodeIndex(depth, Point2I(i,j));

         // For each of this square's 4 children...
         for(S32 subI=0; subI<2; subI++)
         for(S32 subJ=0; subJ<2; subJ++)
         {
            const U32 subIdx =
               QuadTreeTracer::getNodeIndex(depth+1, Point2I(i*2+subI,j*2+subJ));

            // As is the child.
            AssertFatal(qtMin[subIdx] <= qtMax[subIdx],
               "AtlasOldMesher::writeCollision - bad child quadtree node min/max! (a)");

            // Update the min and max of the parent.
            if(qtMin[subIdx] < qtMin[curIdx]) qtMin[curIdx] = qtMin[subIdx];
            if(qtMax[subIdx] > qtMax[curIdx]) qtMax[curIdx] = qtMax[subIdx];

            // Make sure we actually contain the child.
            AssertFatal(qtMin[subIdx] >= qtMin[curIdx],
               "AtlasOldMesher::writeCollision - bad quadtree child min during coltree generation!");
            AssertFatal(qtMax[subIdx] <= qtMax[curIdx],
               "AtlasOldMesher::writeCollision - bad quadtree child max during coltree generation!");

            // And that the parent is still valid.
            AssertFatal(qtMin[curIdx] <= qtMax[curIdx],
               "AtlasOldMesher::writeCollision - bad parent quadtree node min/max!");

            // As is the child.
            AssertFatal(qtMin[subIdx] <= qtMax[subIdx],
               "AtlasOldMesher::writeCollision - bad child quadtree node min/max! (b)");

         }
      }
   }

   // Wasn't that fun? Now we have a ready-to-go quadtree.

   // Now write the quadtree, in proper order
   for(S32 i=0; i<nodeCount; i++)
   {
      AssertFatal(qtMin[i] <= qtMax[i], "AtlasOldMesher::writeCollision - invalid quadtree min/max.");
      s->write(qtMin[i]);
      s->write(qtMax[i]);
   }

   s->write(U32(0xb33fd34d));

   // We have to generate...
   // ... the list of triangle offsets for each bin. (Done above!)
   // ... the triangle buffer which stores the offsets for each bin.
   ChunkTriangleBufferGenerator ctbg(gridSize);

   for(S32 i=0; i<gridSize; i++)
      for(S32 j=0; j<gridSize; j++)
         ctbg.insertBinList(Point2I(i,j), bins[i * gridSize + j]);

   // Finally, write the data out.
   ctbg.write(s);
}
示例#8
0
//--------------------------------------------------------------------------
static bool _writePNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel, U32 strategy, U32 filter)
{
   GFXFormat   format = bitmap->getFormat();

   // ONLY RGB bitmap writing supported at this time!
   AssertFatal(   format == GFXFormatR8G8B8 || 
                  format == GFXFormatR8G8B8A8 || 
                  format == GFXFormatR8G8B8X8 || 
                  format == GFXFormatA8 ||
                  format == GFXFormatR5G6B5, "_writePNG: ONLY RGB bitmap writing supported at this time.");

   if (  format != GFXFormatR8G8B8 && 
         format != GFXFormatR8G8B8A8 && 
         format != GFXFormatR8G8B8X8 && 
         format != GFXFormatA8 &&
         format != GFXFormatR5G6B5 )
      return false;

   png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
      NULL,
      pngFatalErrorFn,
      pngWarningFn,
      NULL,
      pngMallocFn,
      pngFreeFn);
   if (png_ptr == NULL)
      return (false);

   png_infop info_ptr = png_create_info_struct(png_ptr);
   if (info_ptr == NULL)
   {
      png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
      return false;
   }

   png_set_write_fn(png_ptr, &stream, pngWriteDataFn, pngFlushDataFn);

   // Set the compression level and image filters
   png_set_compression_window_bits(png_ptr, 15);
   png_set_compression_level(png_ptr, compressionLevel);
   png_set_filter(png_ptr, 0, filter);

   // Set the image information here.  Width and height are up to 2^31,
   // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
   // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
   // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
   // or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
   // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
   // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED

   U32   width = bitmap->getWidth();
   U32   height = bitmap->getHeight();

   if (format == GFXFormatR8G8B8)
   {
      png_set_IHDR(png_ptr, info_ptr,
         width, height,               // the width & height
         8, PNG_COLOR_TYPE_RGB,       // bit_depth, color_type,
         NULL,                        // no interlace
         NULL,                        // compression type
         NULL);                       // filter type
   }
   else if (format == GFXFormatR8G8B8A8 || format == GFXFormatR8G8B8X8)
   {
      png_set_IHDR(png_ptr, info_ptr,
         width, height,               // the width & height
         8, PNG_COLOR_TYPE_RGB_ALPHA, // bit_depth, color_type,
         NULL,                        // no interlace
         NULL,                        // compression type
         NULL);                       // filter type
   }
   else if (format == GFXFormatA8)
   {
      png_set_IHDR(png_ptr, info_ptr,
         width, height,               // the width & height
         8, PNG_COLOR_TYPE_GRAY,      // bit_depth, color_type,
         NULL,                        // no interlace
         NULL,                        // compression type
         NULL);                       // filter type
   }
   else if (format == GFXFormatR5G6B5) 
   {
      png_set_IHDR(png_ptr, info_ptr,
         width, height,               // the width & height
         16, PNG_COLOR_TYPE_GRAY,     // bit_depth, color_type,
         PNG_INTERLACE_NONE,          // no interlace
         PNG_COMPRESSION_TYPE_DEFAULT,   // compression type
         PNG_FILTER_TYPE_DEFAULT);       // filter type
      
      png_color_8_struct sigBit = { 0 };
      sigBit.gray = 16;
      png_set_sBIT(png_ptr, info_ptr, &sigBit );

      png_set_swap( png_ptr );
   }

   png_write_info(png_ptr, info_ptr);
   FrameAllocatorMarker marker;
   png_bytep* row_pointers = (png_bytep*)marker.alloc( height * sizeof( png_bytep ) );
   for (U32 i=0; i<height; i++)
      row_pointers[i] = const_cast<png_bytep>(bitmap->getAddress(0, i));

   png_write_image(png_ptr, row_pointers);

   // Write S3TC data if present...
   // Write FXT1 data if present...

   png_write_end(png_ptr, info_ptr);
   png_destroy_write_struct(&png_ptr, (png_infopp)NULL);

   return true;
}
示例#9
0
bool GFXD3D9Shader::_compileShader( const Torque::Path &filePath, 
                                    const String& target,                                  
                                    const D3DXMACRO *defines, 
                                    GenericConstBufferLayout* bufferLayoutF, 
                                    GenericConstBufferLayout* bufferLayoutI,
                                    Vector<GFXShaderConstDesc> &samplerDescriptions )
{
   PROFILE_SCOPE( GFXD3D9Shader_CompileShader );

   HRESULT res = D3DERR_INVALIDCALL;
   LPD3DXBUFFER code = NULL;
   LPD3DXBUFFER errorBuff = NULL;

#ifdef TORQUE_DEBUG
   U32 flags = D3DXSHADER_DEBUG;
#else
   U32 flags = 0;
#endif

#ifdef TORQUE_OS_XENON
   flags |= D3DXSHADER_PREFER_FLOW_CONTROL;
#endif

#ifdef D3DXSHADER_USE_LEGACY_D3DX9_31_DLL
   if( D3DX_SDK_VERSION >= 32 )
   {
      // will need to use old compiler for 1_1 shaders - check for pixel
      // or vertex shader with appropriate version.
      if ((target.compare("vs1", 3) == 0) || (target.compare("vs_1", 4) == 0))      
         flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL;

      if ((target.compare("ps1", 3) == 0) || (target.compare("ps_1", 4) == 0))
         flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL;
   }
#endif

#if !defined(TORQUE_OS_XENON) && (D3DX_SDK_VERSION <= 40)
#error This version of the DirectX SDK is too old. Please install a newer version of the DirectX SDK: http://msdn.microsoft.com/en-us/directx/default.aspx
#endif

   ID3DXConstantTable* table = NULL;

   static String sHLSLStr( "hlsl" );
   static String sOBJStr( "obj" );

   // Is it an HLSL shader?
   if ( filePath.getExtension().equal(sHLSLStr, String::NoCase) )   
   {
      FrameAllocatorMarker fam;
      char *buffer = NULL;

      // Set this so that the D3DXInclude::Open will have this 
      // information for relative paths.
      smD3DXInclude->setPath( filePath.getRootAndPath() );

      FileStream s;
      if ( !s.open( filePath, Torque::FS::File::Read ) )
      {
         AssertISV(false, avar("GFXD3D9Shader::initShader - failed to open shader '%s'.", filePath.getFullPath().c_str()));

         if ( smLogErrors )
            Con::errorf( "GFXD3D9Shader::_compileShader - Failed to open shader file '%s'.", 
               filePath.getFullPath().c_str() );

         return false;
      }

      // Convert the path which might have virtualized
      // mount paths to a real file system path.
      Torque::Path realPath;
      if ( !FS::GetFSPath( filePath, realPath ) )
         realPath = filePath;

      // Add a #line pragma so that error and warning messages
      // returned by the HLSL compiler report the right file.
      String linePragma = String::ToString( "#line 1 \"%s\"\r\n", realPath.getFullPath().c_str() );
      U32 linePragmaLen = linePragma.length();

      U32 bufSize = s.getStreamSize();
      buffer = (char *)fam.alloc( bufSize + linePragmaLen + 1 );
      dStrncpy( buffer, linePragma.c_str(), linePragmaLen );
      s.read( bufSize, buffer + linePragmaLen );
      buffer[bufSize+linePragmaLen] = 0;

      res = GFXD3DX.D3DXCompileShader( buffer, bufSize + linePragmaLen, defines, smD3DXInclude, "main", 
         target, flags, &code, &errorBuff, &table );
   }

   // Is it a precompiled obj shader?
   else if ( filePath.getExtension().equal( sOBJStr, String::NoCase ) )
   {     
      FileStream  s;
      if(!s.open(filePath, Torque::FS::File::Read))
      {
         AssertISV(false, avar("GFXD3D9Shader::initShader - failed to open shader '%s'.", filePath.getFullPath().c_str()));

         if ( smLogErrors )
            Con::errorf( "GFXD3D9Shader::_compileShader - Failed to open shader file '%s'.", 
               filePath.getFullPath().c_str() );

         return false;
      }

      res = GFXD3DX.D3DXCreateBuffer(s.getStreamSize(), &code);
      AssertISV(res == D3D_OK, "Unable to create buffer!");
      s.read(s.getStreamSize(), code->GetBufferPointer());
      
      if (res == D3D_OK)
      {
         DWORD* data = (DWORD*) code->GetBufferPointer();
         res = GFXD3DX.D3DXGetShaderConstantTable(data, &table);
      }
   }
   else
   {
      if ( smLogErrors )
         Con::errorf( "GFXD3D9Shader::_compileShader - Unsupported shader file type '%s'.", 
            filePath.getFullPath().c_str() );

      return false;
   }

   if ( res != D3D_OK && smLogErrors )
      Con::errorf( "GFXD3D9Shader::_compileShader - Error compiling shader: %s: %s (%x)", 
         DXGetErrorStringA(res), DXGetErrorDescriptionA(res), res );

   if ( errorBuff )
   {
      // remove \n at end of buffer
      U8 *buffPtr = (U8*) errorBuff->GetBufferPointer();
      U32 len = dStrlen( (const char*) buffPtr );
      buffPtr[len-1] = '\0';

      if( res != D3D_OK )
      {
         if ( smLogErrors )
            Con::errorf( "   %s", (const char*) errorBuff->GetBufferPointer() );
      }
      else
      {
         if ( smLogWarnings )
            Con::warnf( "%s", (const char*) errorBuff->GetBufferPointer() );
      }
   }
   else if ( code == NULL && smLogErrors )
      Con::errorf( "GFXD3D9Shader::_compileShader - no compiled code produced; possibly missing file '%s'.", 
         filePath.getFullPath().c_str() );

   // Create the proper shader if we have code
   if( code != NULL )
   {
      #ifndef TORQUE_SHIPPING

         LPD3DXBUFFER disassem = NULL;
         D3DXDisassembleShader( (DWORD*)code->GetBufferPointer(), false, NULL, &disassem );
         mDissasembly = (const char*)disassem->GetBufferPointer();         
         SAFE_RELEASE( disassem );

         if ( gDisassembleAllShaders )
         {
             String filename = filePath.getFullPath();
            filename.replace( ".hlsl", "_dis.txt" );

            FileStream *fstream = FileStream::createAndOpen( filename, Torque::FS::File::Write );
            if ( fstream )
            {            
               fstream->write( mDissasembly );
               fstream->close();
               delete fstream;   
            }
         }

      #endif

      if (target.compare("ps_", 3) == 0)      
         res = mD3D9Device->CreatePixelShader( (DWORD*)code->GetBufferPointer(), &mPixShader );
      else
         res = mD3D9Device->CreateVertexShader( (DWORD*)code->GetBufferPointer(), &mVertShader );

      if (res == S_OK)
         _getShaderConstants(table, bufferLayoutF, bufferLayoutI, samplerDescriptions);

#ifdef TORQUE_ENABLE_CSF_GENERATION

      // Ok, we've got a valid shader and constants, let's write them all out.
      if ( !_saveCompiledOutput(filePath, code, bufferLayoutF, bufferLayoutI) && smLogErrors )
         Con::errorf( "GFXD3D9Shader::_compileShader - Unable to save shader compile output for: %s", 
            filePath.getFullPath().c_str() );

#endif

      SAFE_RELEASE(table);

      if ( res != S_OK && smLogErrors )
         Con::errorf( "GFXD3D9Shader::_compileShader - Unable to create shader for '%s'.", 
            filePath.getFullPath().c_str() );
   }

   bool result = code != NULL && res == S_OK;

   SAFE_RELEASE( code );
   SAFE_RELEASE( errorBuff );

   return result;
}
示例#10
0
void AtlasFile::syncThreads()
{
   // Compare current time with last, don't update if it's less than 10ms or so.
   const U32 nextTime = Platform::getRealMilliseconds();
   if((nextTime - mLastSyncTime) < 10)
      return;
   

   PROFILE_START(AtlasFile_syncThreads);
   //Con::printf("----------- sync ----------------");

   mFile.sync();

   // Do a sync callback for our TOCs
   PROFILE_START(AtlasFile_syncThreads_callback);
   F32 dt = F32(nextTime - mLastSyncTime) / 1000.f;
   for(S32 i=0; i<mTOCs.size(); i++)
      mTOCs[i]->syncCallback(dt);
   mLastSyncTime = nextTime;
   PROFILE_END();

   // First, let's dequeue all our in-flight loads so we don't queue the same
   // thing twice. To make sure we don't get diddled, we also have to lock
   // the pending queue.

   // We'd better be sure we unlock these. Order is important to prevent
   // deadlocks.
   PROFILE_START(AtlasFile_syncThreads_notes);
   Vector<AtlasReadNote*> &pendingQ = mPendingLoadQueue.lockVector();
   Vector<AtlasReadNote*> &inProcessQ = mLoadingNotes.lockVector();

   // Filter out loads in process.
   for(S32 i=0; i<inProcessQ.size(); i++)
   {
      const AtlasReadNote *arn = inProcessQ[i];
      arn->toc->cbOnChunkReadStarted(arn->stubIdx);
   }

   /*if(inProcessQ.size())
      Con::printf("    %d are in-process", inProcessQ.size()); */

   inProcessQ.clear();

   // Update our load queue.
   Vector<AtlasReadNote*> *updateList = new Vector<AtlasReadNote*>[mTOCs.size()];
   U32 remaining = 0;

   const U32 numToFetch = 5;

   for(S32 i=0; i<mTOCs.size(); i++)
   {
      updateList[i].reserve(numToFetch);
      mTOCs[i]->recalculateUpdates(updateList[i], numToFetch);
      remaining += updateList[i].size();
   }

   /*if(remaining)
      Con::printf("    %d in queue", remaining);*/

   // Round-robin add them to the master queue.
   {
      // Wipe pending ARNs... this is kinda gross.
      for(S32 i=0; i<pendingQ.size(); i++)
      {
         SAFE_DELETE(pendingQ[i]);
      }
      pendingQ.clear();
      
      // And fill it up again, round robin.
      U32 originalRemaining = remaining;
      pendingQ.reserve(remaining);
      while(remaining)
      {
         for(S32 i=0; i<mTOCs.size(); i++)
         {
            if(updateList[i].size())
            {
               pendingQ.push_back(updateList[i].first());
               updateList[i].pop_front();
               remaining--;
            }
         }
      }

      AssertFatal(pendingQ.size() == originalRemaining, 
         "AtlasFile::syncThreads - unexpected pending queue size after population.");
   }

   // Remember what I said about locking order before?
   mLoadingNotes.unlockVector();
   mPendingLoadQueue.unlockVector();

   PROFILE_END();

   // Clean up our temporary queues.
   delete[] updateList;

   PROFILE_START(AtlasFile_syncThreads_instatement);

   // Pass stuff to the TOCs for instatement.
   {
      FrameAllocatorMarker famAlloc;

      // Copy it out, then wipe the master, as instatement may take a while.
      Vector<AtlasReadNote*> &lockedProcessQ = mPendingProcessQueue.lockVector();
      Vector<AtlasReadNote*> &lockedInProcessQ = mLoadingNotes.lockVector();

      //  Copy our pending data to a buffer so we can work on it.
      U32 pendingCount = lockedProcessQ.size();
      AtlasReadNote **pendingData = (AtlasReadNote **)famAlloc.alloc(sizeof(AtlasReadNote*) * pendingCount);
      dMemcpy(pendingData, lockedProcessQ.address(), sizeof(AtlasReadNote*) * pendingCount);
      lockedProcessQ.clear();

      mPendingProcessQueue.unlockVector();

      // And do the instating, removing from the loadNoteQueue as needed.
      for(S32 i=0; i<pendingCount; i++)
      {
         PROFILE_START(AtlasFile_syncThreads_instatement_callback);
         pendingData[i]->toc->cbOnChunkReadComplete(pendingData[i]->stubIdx, pendingData[i]->chunk);
         PROFILE_END();

         // Remove the ARN from the in process queue, so we won't puke
         // trying to mark it as pending later on.
         for(S32 j=0; j<lockedInProcessQ.size(); j++)
         {
            if(lockedInProcessQ[j] == pendingData[i])
            {
               lockedInProcessQ.erase_fast(j);
               break;
            }
         }

         // Get rid of the ARN.
         delete pendingData[i];
      }

      mLoadingNotes.unlockVector();
   }

   PROFILE_END();

   // Make sure we're loading.
   enqueueNextPendingLoad(false);

   PROFILE_END();
}