//----------------------------------------------------------------------- Math::Math( unsigned int trigTableSize ) { msAngleUnit = AU_DEGREE; mTrigTableSize = trigTableSize; mTrigTableFactor = mTrigTableSize / Math::TWO_PI; mSinTable = OGRE_ALLOC_T(Real, mTrigTableSize, MEMCATEGORY_GENERAL); mTanTable = OGRE_ALLOC_T(Real, mTrigTableSize, MEMCATEGORY_GENERAL); buildTrigTables(); }
void SplattingManager::createColourMap(Image& image, const ColourList& colours) { if (colours.size() > mImpl->numTextures) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Given more colours than texture channels available.", __FUNCTION__); #if OGRE_VERSION_MINOR > 4 uchar* data = OGRE_ALLOC_T(uchar, mImpl->width*mImpl->height*3, MEMCATEGORY_GENERAL); #else uchar* data = new uchar[mImpl->width*mImpl->height*3]; #endif for (size_t y = 0; y < mImpl->height; ++y) { for (size_t x = 0; x < mImpl->width; ++x) { ColourValue val (0, 0, 0); for (size_t i = 0; i < colours.size(); ++i) { size_t m = i / mImpl->channels; uint t = (uint) (i % mImpl->channels); val += colours[i] * (float(mImpl->maps[m]->getValue((uint)x, (uint)y, t)) / 255); } size_t pos = (x + y * mImpl->width) * 3; data[pos+0] = uchar(255*val.r); data[pos+1] = uchar(255*val.g); data[pos+2] = uchar(255*val.b); } } image.loadDynamicImage(data, mImpl->width, mImpl->height, 1, PF_BYTE_RGB, true); }
//----------------------------------------------------------------------------- void ManualObject::resizeTempIndexBufferIfNeeded(size_t numInds) { size_t newSize = numInds * sizeof(uint32); if (newSize > mTempIndexSize || !mTempIndexBuffer) { if (!mTempIndexBuffer) { // init newSize = mTempIndexSize; } else { // increase to at least double current newSize = std::max(newSize, mTempIndexSize*2); } numInds = newSize / sizeof(uint32); uint32* tmp = mTempIndexBuffer; mTempIndexBuffer = OGRE_ALLOC_T(uint32, numInds, MEMCATEGORY_GEOMETRY); if (tmp) { memcpy(mTempIndexBuffer, tmp, mTempIndexSize); OGRE_FREE(tmp, MEMCATEGORY_GEOMETRY); } mTempIndexSize = newSize; } }
//----------------------------------------------------------------------------- Image & Image::operator = ( const Image &img ) { if( m_pBuffer && m_bAutoDelete ) { OGRE_FREE(m_pBuffer, MEMCATEGORY_GENERAL); m_pBuffer = NULL; } m_uWidth = img.m_uWidth; m_uHeight = img.m_uHeight; m_uDepth = img.m_uDepth; m_eFormat = img.m_eFormat; m_uSize = img.m_uSize; m_uFlags = img.m_uFlags; m_ucPixelSize = img.m_ucPixelSize; m_uNumMipmaps = img.m_uNumMipmaps; m_bAutoDelete = img.m_bAutoDelete; //Only create/copy when previous data was not dynamic data if( m_bAutoDelete ) { m_pBuffer = OGRE_ALLOC_T(uchar, m_uSize, MEMCATEGORY_GENERAL); memcpy( m_pBuffer, img.m_pBuffer, m_uSize ); } else { m_pBuffer = img.m_pBuffer; } return *this; }
//----------------------------------------------------------------------------- Image & Image::flipAroundX() { if( !mBuffer ) { OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can not flip an uninitialised texture", "Image::flipAroundX" ); } mNumMipmaps = 0; // Image operations lose precomputed mipmaps size_t rowSpan = mWidth * mPixelSize; uchar *pTempBuffer = OGRE_ALLOC_T(uchar, rowSpan * mHeight, MEMCATEGORY_GENERAL); uchar *ptr1 = mBuffer, *ptr2 = pTempBuffer + ( ( mHeight - 1 ) * rowSpan ); for( ushort i = 0; i < mHeight; i++ ) { memcpy( ptr2, ptr1, rowSpan ); ptr1 += rowSpan; ptr2 -= rowSpan; } memcpy( mBuffer, pTempBuffer, rowSpan * mHeight); OGRE_FREE(pTempBuffer, MEMCATEGORY_GENERAL); return *this; }
//----------------------------------------------------------------------------- Image & Image::operator = ( const Image &img ) { freeMemory(); mWidth = img.mWidth; mHeight = img.mHeight; mDepth = img.mDepth; mFormat = img.mFormat; mBufSize = img.mBufSize; mFlags = img.mFlags; mPixelSize = img.mPixelSize; mNumMipmaps = img.mNumMipmaps; mAutoDelete = img.mAutoDelete; //Only create/copy when previous data was not dynamic data if( mAutoDelete ) { mBuffer = OGRE_ALLOC_T(uchar, mBufSize, MEMCATEGORY_GENERAL); memcpy( mBuffer, img.mBuffer, mBufSize ); } else { mBuffer = img.mBuffer; } return *this; }
Image createMinimap(const Image& colourMap, const Image& lightMap) { if (colourMap.getWidth() != lightMap.getWidth() || colourMap.getHeight() != lightMap.getHeight()) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Images must have the same dimensions.", __FUNCTION__); #if OGRE_VERSION_MINOR > 4 uchar* data = OGRE_ALLOC_T(uchar, colourMap.getWidth()*colourMap.getHeight()*3, MEMCATEGORY_GENERAL); #else uchar* data = new uchar[colourMap.getWidth()*colourMap.getHeight()*3]; #endif for (size_t y = 0; y < colourMap.getWidth(); ++y) { for (size_t x = 0; x < colourMap.getHeight(); ++x) { ColourValue val = const_cast<Image&>(colourMap).getColourAt((uint)x, (uint)y, 0) * const_cast<Image&>(lightMap).getColourAt((uint)x, (uint)y, 0); size_t pos = (x + y*colourMap.getWidth()) * 3; data[pos+0] = uchar(255*val.r); data[pos+1] = uchar(255*val.g); data[pos+2] = uchar(255*val.b); } } Image image; image.loadDynamicImage(data, colourMap.getWidth(), colourMap.getHeight(), 1, PF_BYTE_RGB, true); return image; }
//--------------------------------------------------------------------- DataStreamPtr FreeImageCodec::code(MemoryDataStreamPtr& input, Codec::CodecDataPtr& pData) const { // Set error handler FreeImage_SetOutputMessage(FreeImageSaveErrorHandler); FIBITMAP* fiBitmap = encode(input, pData); // open memory chunk allocated by FreeImage FIMEMORY* mem = FreeImage_OpenMemory(); // write data into memory FreeImage_SaveToMemory((FREE_IMAGE_FORMAT)mFreeImageType, fiBitmap, mem); // Grab data information BYTE* data; DWORD size; FreeImage_AcquireMemory(mem, &data, &size); // Copy data into our own buffer // Because we're asking MemoryDataStream to free this, must create in a compatible way BYTE* ourData = OGRE_ALLOC_T(BYTE, size, MEMCATEGORY_GENERAL); memcpy(ourData, data, size); // Wrap data in stream, tell it to free on close DataStreamPtr outstream(OGRE_NEW MemoryDataStream(ourData, size, true)); // Now free FreeImage memory buffers FreeImage_CloseMemory(mem); // Unload bitmap FreeImage_Unload(fiBitmap); return outstream; }
//--------------------------------------------------------------------- void DeflateStream::init() { mpZStream = OGRE_ALLOC_T(z_stream, 1, MEMCATEGORY_GENERAL); mpZStream->zalloc = OgreZalloc; mpZStream->zfree = OgreZfree; if (getAccessMode() == READ) { mpTmp = (unsigned char*)OGRE_MALLOC(OGRE_DEFLATE_TMP_SIZE, MEMCATEGORY_GENERAL); size_t restorePoint = mCompressedStream->tell(); // read early chunk mpZStream->next_in = mpTmp; mpZStream->avail_in = mCompressedStream->read(mpTmp, OGRE_DEFLATE_TMP_SIZE); if (inflateInit(mpZStream) != Z_OK) { mIsCompressedValid = false; } else mIsCompressedValid = true; if (mIsCompressedValid) { // in fact, inflateInit on some implementations doesn't try to read // anything. We need to at least read something to test Bytef testOut[4]; size_t savedIn = mpZStream->avail_in; mpZStream->avail_out = 4; mpZStream->next_out = testOut; if (inflate(mpZStream, Z_SYNC_FLUSH) != Z_OK) mIsCompressedValid = false; // restore for reading mpZStream->avail_in = savedIn; mpZStream->next_in = mpTmp; inflateReset(mpZStream); } if (!mIsCompressedValid) { // Not compressed data! // Fail gracefully, fall back on reading the underlying stream direct destroy(); mCompressedStream->seek(restorePoint); } } else { // Write to temp file char tmpname[L_tmpnam]; tmpnam(tmpname); mTempFileName = tmpname; std::fstream *f = OGRE_NEW_T(std::fstream, MEMCATEGORY_GENERAL)(); f->open(tmpname, std::ios::binary | std::ios::out); mTmpWriteStream = DataStreamPtr(OGRE_NEW FileStreamDataStream(f)); } }
//----------------------------------------------------------------------------- D3D9HardwarePixelBuffer::BufferResources* D3D9HardwarePixelBuffer::createBufferResources() { BufferResources* newResources = OGRE_ALLOC_T(BufferResources, 1, MEMCATEGORY_RENDERSYS); memset(newResources, 0, sizeof(BufferResources)); return newResources; }
void GlobalMap::clear() { Ogre::uchar* buffer = OGRE_ALLOC_T(Ogre::uchar, mWidth * mHeight * 4, Ogre::MEMCATEGORY_GENERAL); memset(buffer, 0, mWidth * mHeight * 4); mOverlayImage.loadDynamicImage(&buffer[0], mWidth, mHeight, 1, Ogre::PF_A8B8G8R8, true); // pass ownership of buffer to image mOverlayTexture->load(); }
//----------------------------------------------------------------------- void RenderTarget::writeContentsToFile(const String& filename) { PixelFormat pf = suggestPixelFormat(); uchar *data = OGRE_ALLOC_T(uchar, mWidth * mHeight * PixelUtil::getNumElemBytes(pf), MEMCATEGORY_RENDERSYS); PixelBox pb(mWidth, mHeight, 1, pf, data); copyContentsToMemory(pb); Image().loadDynamicImage(data, mWidth, mHeight, 1, pf, false, 1, 0).save(filename); OGRE_FREE(data, MEMCATEGORY_RENDERSYS); }
HalfFloatGridSource::HalfFloatGridSource(const String &serializedVolumeFile, const bool trilinearValue, const bool trilinearGradient, const bool sobelGradient) : GridSource(trilinearValue, trilinearGradient, sobelGradient) { Timer t; DataStreamPtr streamRead = Root::getSingleton().openFileStream(serializedVolumeFile); #if OGRE_NO_ZIP_ARCHIVE == 0 DataStreamPtr uncompressStream(OGRE_NEW DeflateStream(serializedVolumeFile, streamRead)); StreamSerialiser ser(uncompressStream); #else StreamSerialiser ser(streamRead); #endif if (!ser.readChunkBegin(VOLUME_CHUNK_ID, VOLUME_CHUNK_VERSION)) { OGRE_EXCEPT(Exception::ERR_INVALID_STATE, "Invalid volume file given!", __FUNCTION__); } // Read header Vector3 readFrom, readTo; ser.read(&readFrom); ser.read(&readTo); float voxelWidth; ser.read<float>(&voxelWidth); size_t width, height, depth; ser.read<size_t>(&width); ser.read<size_t>(&height); ser.read<size_t>(&depth); mWidth = static_cast<int>(width); mHeight = static_cast<int>(height); mDepth = static_cast<int>(depth); mDepthTimesHeight = static_cast<int>(mDepth * mHeight); Vector3 worldDimension = readTo - readFrom; mPosXScale = (Real)1.0 / (Real)worldDimension.x * (Real)mWidth; mPosYScale = (Real)1.0 / (Real)worldDimension.y * (Real)mHeight; mPosZScale = (Real)1.0 / (Real)worldDimension.z * (Real)mDepth; mVolumeSpaceToWorldSpaceFactor = (Real)worldDimension.x * (Real)mWidth; mMaxClampedAbsoluteDensity = 0; // Read data size_t elementCount = mWidth * mHeight * mDepth; mData = OGRE_ALLOC_T(uint16, elementCount, MEMCATEGORY_GENERAL); ser.read(mData, elementCount); ser.readChunkEnd(VOLUME_CHUNK_ID); LogManager::getSingleton().stream() << "Processed serialization in " << t.getMilliseconds() << "ms."; }
void saveBrushToImage(const Brush& brush, Image& image) { // save brush as a 16bit grayscale image #if OGRE_VERSION_MINOR > 4 ushort* data = (ushort*)OGRE_ALLOC_T(uchar, brush.getWidth()*brush.getHeight()*sizeof(ushort), MEMCATEGORY_GENERAL); #else ushort* data = (ushort*)new uchar[brush.getWidth()*brush.getHeight()*sizeof(ushort)]; #endif for (size_t x = 0; x < brush.getWidth(); ++x) for (size_t y = 0; y < brush.getHeight(); ++y) data[y*brush.getWidth() + x] = ushort(brush.at(x, y) * 0xffff); // pass the data to the image, image takes over ownership image.loadDynamicImage((uchar*)data, brush.getWidth(), brush.getHeight(), 1, PF_L16, true); }
// bool publishFrame(Ogre::RenderWindow * render_object, const std::string frame_id) bool publishFrame(Ogre::RenderTexture * render_object, const std::string frame_id) { if (pub_.getTopic() == "") { return false; } if (frame_id == "") { return false; } // RenderTarget::writeContentsToFile() used as example int height = render_object->getHeight(); int width = render_object->getWidth(); // the results of pixel format have to be used to determine // image.encoding Ogre::PixelFormat pf = render_object->suggestPixelFormat(); uint pixelsize = Ogre::PixelUtil::getNumElemBytes(pf); uint datasize = width * height * pixelsize; // 1.05 multiplier is to avoid crash when the window is resized. // There should be a better solution. uchar *data = OGRE_ALLOC_T(uchar, datasize * 1.05, Ogre::MEMCATEGORY_RENDERSYS); Ogre::PixelBox pb(width, height, 1, pf, data); render_object->copyContentsToMemory(pb, Ogre::RenderTarget::FB_AUTO); sensor_msgs::Image image; image.header.stamp = ros::Time::now(); image.header.seq = image_id_++; image.header.frame_id = frame_id; image.height = height; image.width = width; image.step = pixelsize * width; if (pixelsize == 3) image.encoding = sensor_msgs::image_encodings::RGB8; // would break if pf changes else if (pixelsize == 4) image.encoding = sensor_msgs::image_encodings::RGBA8; // would break if pf changes else { ROS_ERROR_STREAM("unknown pixe format " << pixelsize << " " << pf); } image.is_bigendian = (OGRE_ENDIAN == OGRE_ENDIAN_BIG); image.data.resize(datasize); memcpy(&image.data[0], data, datasize); pub_.publish(image); OGRE_FREE(data, Ogre::MEMCATEGORY_RENDERSYS); }
//----------------------------------------------------------------------------- Image& Image::loadDynamicImage( uchar* pData, size_t uWidth, size_t uHeight, size_t depth, PixelFormat eFormat, bool autoDelete, size_t numFaces, size_t numMipMaps) { if( m_pBuffer && m_bAutoDelete ) { OGRE_FREE(m_pBuffer, MEMCATEGORY_GENERAL); m_pBuffer = NULL; } // Set image metadata m_uWidth = uWidth; m_uHeight = uHeight; m_uDepth = depth; m_eFormat = eFormat; m_ucPixelSize = static_cast<uchar>(PixelUtil::getNumElemBytes( m_eFormat )); m_uNumMipmaps = numMipMaps; m_uFlags = 0; // Set flags if (PixelUtil::isCompressed(eFormat)) m_uFlags |= IF_COMPRESSED; if (m_uDepth != 1) m_uFlags |= IF_3D_TEXTURE; if(numFaces == 6) m_uFlags |= IF_CUBEMAP; if(numFaces != 6 && numFaces != 1) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Number of faces currently must be 6 or 1.", "Image::loadDynamicImage"); m_uSize = calculateSize(numMipMaps, numFaces, uWidth, uHeight, depth, eFormat); if (pData) { m_pBuffer = pData; m_bAutoDelete = autoDelete; } else { m_bAutoDelete = true; m_pBuffer = OGRE_ALLOC_T(Ogre::uchar, m_uSize, Ogre::MEMCATEGORY_RESOURCE); } return *this; }
void SplattingManager::createBaseTexture(Image& image, size_t width, size_t height, ImageList textures, float repeatX, float repeatZ) { if (textures.size() > mImpl->numTextures) OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Given more textures than texture channels available.", "ET::SplattingManager::createBaseTexture"); // first resize the textures according to the desired output size and the repeat values ushort scaleWidth = (ushort) (width / repeatX); ushort scaleHeight = (ushort) (height / repeatZ); for (ImageList::iterator it = textures.begin(); it != textures.end(); ++it) it->resize(scaleWidth, scaleHeight); // create the buffer to hold our generated base texture #if OGRE_VERSION_MINOR > 4 uchar* data = OGRE_ALLOC_T(uchar, width*height*3, MEMCATEGORY_GENERAL); #else uchar* data = new uchar[width*height*3]; #endif size_t pos = 0; for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < width; ++x) { ColourValue val (0,0,0); int texX = (int) (x % scaleWidth); int texY = (int) (y % scaleHeight); for (size_t t = 0; t < textures.size(); ++t) { // get interpolated part of this texture at the current pixel float weight = mImpl->interpolateWeight(x, y, width, height, t); // get colour value of the texture image ColourValue col = textures[t].getColourAt(texX, texY, 0); // add to the pixel colour level val += weight*col; } // write colour to our buffer data[pos+0] = uchar(255*val.r); data[pos+1] = uchar(255*val.g); data[pos+2] = uchar(255*val.b); pos += 3; } } image.loadDynamicImage(data, width, height, 1, PF_BYTE_RGB, true); }
//----------------------------------------------------------------------------- void Image::resize(ushort width, ushort height, Filter filter) { // resizing dynamic images is not supported assert(mAutoDelete); assert(mDepth == 1); // reassign buffer to temp image, make sure auto-delete is true Image temp; temp.loadDynamicImage(mBuffer, mWidth, mHeight, 1, mFormat, true); // do not delete[] mBuffer! temp will destroy it // set new dimensions, allocate new buffer mWidth = width; mHeight = height; mBufSize = PixelUtil::getMemorySize(mWidth, mHeight, 1, mFormat); mBuffer = OGRE_ALLOC_T(uchar, mBufSize, MEMCATEGORY_GENERAL); mNumMipmaps = 0; // Loses precomputed mipmaps // scale the image from temp into our resized buffer Image::scale(temp.getPixelBox(), getPixelBox(), filter); }
Vector4* SnowTerrain::convertNormalsToFloats(PixelBox* terrainNormals, bool compressed) { const size_t srcPixelSize = PixelUtil::getNumElemBytes(terrainNormals->format); const size_t dstPixelSize = PixelUtil::getNumElemBytes(PF_FLOAT32_RGBA); size_t w,h,d; w = terrainNormals->getWidth(); h = terrainNormals->getHeight(); d = terrainNormals->getDepth(); assert(terrainNormals->getWidth() == mTerrainSize); size_t terrainNormalSize = terrainNormals->getWidth()*terrainNormals->getHeight(); Vector4* terrainNormalDataCorrected = OGRE_ALLOC_T(Vector4, terrainNormalSize, MEMCATEGORY_GENERAL); size_t i = 0; size_t j = 0; uint8* pixelsBuffer = static_cast<uint8*>(terrainNormals->data); for(; i < terrainNormalSize * srcPixelSize && j < terrainNormalSize * sizeof(Vector4); i+=srcPixelSize) { uint8 r,g,b,a; PixelUtil::unpackColour(&r,&g,&b,&a, terrainNormals->format, static_cast<void*>(&pixelsBuffer[i])); float fr,fg,fb; if(compressed) { //(signed) float packed/compressed into uint8, unpack fr = ((float)(r))/(0.5f * 255.0f) - 1.0f; fg = ((float)(g))/(0.5f * 255.0f) - 1.0f; fb = ((float)(b))/(0.5f * 255.0f) - 1.0f; } else { fr = ((float)(r))/255.0f; fg = ((float)(g))/255.0f; fb = ((float)(b))/255.0f; } Vector3 v = Vector3(fr, fg, fb); v.normalise(); terrainNormalDataCorrected[j++] = Vector4(v); } return terrainNormalDataCorrected; }
//----------------------------------------------------------------------------- Image & Image::loadRawData( DataStreamPtr& stream, uint32 uWidth, uint32 uHeight, uint32 uDepth, PixelFormat eFormat, size_t numFaces, size_t numMipMaps) { size_t size = calculateSize(numMipMaps, numFaces, uWidth, uHeight, uDepth, eFormat); if (size != stream->size()) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Stream size does not match calculated image size", "Image::loadRawData"); } uchar *buffer = OGRE_ALLOC_T(uchar, size, MEMCATEGORY_GENERAL); stream->read(buffer, size); return loadDynamicImage(buffer, uWidth, uHeight, uDepth, eFormat, true, numFaces, numMipMaps); }
//----------------------------------------------------------------------- void ConvexBody::clip( const Plane& pl, bool keepNegative ) { if ( getPolygonCount() == 0 ) return; // current will be used as the reference body ConvexBody current; current.moveDataFromBody(*this); OgreAssert( this->getPolygonCount() == 0, "Body not empty!" ); OgreAssert( current.getPolygonCount() != 0, "Body empty!" ); // holds all intersection edges for the different polygons Polygon::EdgeMap intersectionEdges; // clip all polygons by the intersection plane // add only valid or intersected polygons to *this for ( size_t iPoly = 0; iPoly < current.getPolygonCount(); ++iPoly ) { // fetch vertex count and ignore polygons with less than three vertices // the polygon is not valid and won't be added const size_t vertexCount = current.getVertexCount( iPoly ); if ( vertexCount < 3 ) continue; // current polygon const Polygon& p = current.getPolygon( iPoly ); // the polygon to assemble Polygon *pNew = allocatePolygon(); // the intersection polygon (indeed it's an edge or it's empty) Polygon *pIntersect = allocatePolygon(); // check if polygons lie inside or outside (or on the plane) // for each vertex check where it is situated in regard to the plane // three possibilities appear: Plane::Side clipSide = keepNegative ? Plane::POSITIVE_SIDE : Plane::NEGATIVE_SIDE; // - side is clipSide: vertex will be clipped // - side is !clipSide: vertex will be untouched // - side is NOSIDE: vertex will be untouched Plane::Side *side = OGRE_ALLOC_T(Plane::Side, vertexCount, MEMCATEGORY_SCENE_CONTROL); for ( size_t iVertex = 0; iVertex < vertexCount; ++iVertex ) { side[ iVertex ] = pl.getSide( p.getVertex( iVertex ) ); } // now we check the side combinations for the current and the next vertex // four different combinations exist: // - both points inside (or on the plane): keep the second (add it to the body) // - both points outside: discard both (don't add them to the body) // - first vertex is inside, second is outside: add the intersection point // - first vertex is outside, second is inside: add the intersection point, then the second for ( size_t iVertex = 0; iVertex < vertexCount; ++iVertex ) { // determine the next vertex size_t iNextVertex = ( iVertex + 1 ) % vertexCount; const Vector3& vCurrent = p.getVertex( iVertex ); const Vector3& vNext = p.getVertex( iNextVertex ); // case 1: both points inside (store next) if ( side[ iVertex ] != clipSide && // NEGATIVE or NONE side[ iNextVertex ] != clipSide ) // NEGATIVE or NONE { // keep the second pNew->insertVertex( vNext ); } // case 3: inside -> outside (store intersection) else if ( side[ iVertex ] != clipSide && side[ iNextVertex ] == clipSide ) { // Do an intersection with the plane. We use a ray with a start point and a direction. // The ray is forced to hit the plane with any option available (eigher current or next // is the starting point) // intersect from the outside vertex towards the inside one Vector3 vDirection = vCurrent - vNext; vDirection.normalise(); Ray ray( vNext, vDirection ); std::pair< bool, Real > intersect = ray.intersects( pl ); // store intersection if ( intersect.first ) { // convert distance to vector Vector3 vIntersect = ray.getPoint( intersect.second ); // store intersection pNew->insertVertex( vIntersect ); pIntersect->insertVertex( vIntersect ); } } // case 4: outside -> inside (store intersection, store next) else if ( side[ iVertex ] == clipSide && side[ iNextVertex ] != clipSide ) { // Do an intersection with the plane. We use a ray with a start point and a direction. // The ray is forced to hit the plane with any option available (eigher current or next // is the starting point) // intersect from the outside vertex towards the inside one Vector3 vDirection = vNext - vCurrent; vDirection.normalise(); Ray ray( vCurrent, vDirection ); std::pair< bool, Real > intersect = ray.intersects( pl ); // store intersection if ( intersect.first ) { // convert distance to vector Vector3 vIntersect = ray.getPoint( intersect.second ); // store intersection pNew->insertVertex( vIntersect ); pIntersect->insertVertex( vIntersect ); } pNew->insertVertex( vNext ); } // else: // case 2: both outside (do nothing) } // insert the polygon only, if at least three vertices are present if ( pNew->getVertexCount() >= 3 ) { // in case there are double vertices, remove them pNew->removeDuplicates(); // in case there are still at least three vertices, insert the polygon if ( pNew->getVertexCount() >= 3 ) { this->insertPolygon( pNew ); } else { // delete pNew because it's empty or invalid freePolygon(pNew); pNew = 0; } } else { // delete pNew because it's empty or invalid freePolygon(pNew); pNew = 0; } // insert intersection polygon only, if there are two vertices present if ( pIntersect->getVertexCount() == 2 ) { intersectionEdges.insert( Polygon::Edge( pIntersect->getVertex( 0 ), pIntersect->getVertex( 1 ) ) ); } // delete intersection polygon // vertices were copied (if there were any) freePolygon(pIntersect); pIntersect = 0; // delete side info OGRE_FREE(side, MEMCATEGORY_SCENE_CONTROL); side = 0; } // if the polygon was partially clipped, close it // at least three edges are needed for a polygon if ( intersectionEdges.size() >= 3 ) { Polygon *pClosing = allocatePolygon(); // Analyze the intersection list and insert the intersection points in ccw order // Each point is twice in the list because of the fact that we have a convex body // with convex polygons. All we have to do is order the edges (an even-odd pair) // in a ccw order. The plane normal shows us the direction. Polygon::EdgeMap::iterator it = intersectionEdges.begin(); // check the cross product of the first two edges Vector3 vFirst = it->first; Vector3 vSecond = it->second; // remove inserted edge intersectionEdges.erase( it ); Vector3 vNext; // find mating edge if (findAndEraseEdgePair(vSecond, intersectionEdges, vNext)) { // detect the orientation // the polygon must have the same normal direction as the plane and then n Vector3 vCross = ( vFirst - vSecond ).crossProduct( vNext - vSecond ); bool frontside = ( pl.normal ).directionEquals( vCross, Degree( 1 ) ); // first inserted vertex Vector3 firstVertex; // currently inserted vertex Vector3 currentVertex; // direction equals -> front side (walk ccw) if ( frontside ) { // start with next as first vertex, then second, then first and continue with first to walk ccw pClosing->insertVertex( vNext ); pClosing->insertVertex( vSecond ); pClosing->insertVertex( vFirst ); firstVertex = vNext; currentVertex = vFirst; #ifdef _DEBUG_INTERSECTION_LIST std::cout << "Plane: n=" << pl.normal << ", d=" << pl.d << std::endl; std::cout << "First inserted vertex: " << *next << std::endl; std::cout << "Second inserted vertex: " << *vSecond << std::endl; std::cout << "Third inserted vertex: " << *vFirst << std::endl; #endif } // direction does not equal -> back side (walk cw) else { // start with first as first vertex, then second, then next and continue with next to walk ccw pClosing->insertVertex( vFirst ); pClosing->insertVertex( vSecond ); pClosing->insertVertex( vNext ); firstVertex = vFirst; currentVertex = vNext; #ifdef _DEBUG_INTERSECTION_LIST std::cout << "Plane: n=" << pl.normal << ", d=" << pl.d << std::endl; std::cout << "First inserted vertex: " << *vFirst << std::endl; std::cout << "Second inserted vertex: " << *vSecond << std::endl; std::cout << "Third inserted vertex: " << *next << std::endl; #endif } // search mating edges that have a point in common // continue this operation as long as edges are present while ( !intersectionEdges.empty() ) { if (findAndEraseEdgePair(currentVertex, intersectionEdges, vNext)) { // insert only if it's not the last (which equals the first) vertex if ( !intersectionEdges.empty() ) { currentVertex = vNext; pClosing->insertVertex( vNext ); } } else { // degenerated... break; } } // while intersectionEdges not empty // insert polygon (may be degenerated!) this->insertPolygon( pClosing ); } // mating intersection edge NOT found! else { freePolygon(pClosing); } } // if intersectionEdges contains more than three elements }
//----------------------------------------------------------------------- void AtlasImageTool::process (void) { Ogre::Root root("", "", "atlas.log"); Ogre::ResourceGroupManager::getSingleton().addResourceLocation(mImagePath, "FileSystem"); Ogre::StringVector::iterator itInputFileName; Ogre::StringVector::iterator itFrame; Ogre::StringVector::iterator itAlpha; itAlpha = mAlpha.begin(); if (mInputFrames.empty() || mInputFrames[0] == Ogre::StringUtil::BLANK) { // No Frames are assigned so just add them for (itInputFileName = mInputFileNames.begin(); itInputFileName != mInputFileNames.end(); ++itInputFileName) { Ogre::String imageFileName = *itInputFileName; Ogre::Image image; image.load(imageFileName, "General"); if (itAlpha != mAlpha.end() && *itAlpha != Ogre::StringUtil::BLANK) { Ogre::Real alpha = Ogre::StringConverter::parseReal(*itAlpha); correctAlpha(image, alpha); itAlpha++; } mAtlasImage.addImage(&image); } } else { // Frames are assigned, so generate intermediate images itInputFileName = mInputFileNames.begin(); Ogre::Real alpha = 1.0f; Ogre::String nextImageFileName = *itInputFileName; Ogre::Image nextImage; itFrame = mInputFrames.begin(); size_t nextFrame = Ogre::StringConverter::parseUnsignedInt(*itFrame); nextImage.load(nextImageFileName, "General"); size_t frameCounter = 0; if (!mAlpha.empty() && mAlpha[0] != Ogre::StringUtil::BLANK) { itAlpha = mAlpha.begin(); Ogre::Real alpha = Ogre::StringConverter::parseReal(*itAlpha); correctAlpha(nextImage, alpha); itAlpha++; } mAtlasImage.addImage(&nextImage); frameCounter++; itInputFileName++; itFrame++; while (itInputFileName != mInputFileNames.end()) { // Get the next filename Ogre::Image firstImage(nextImage); nextImageFileName = *itInputFileName; nextImage.load(nextImageFileName, "General"); if (itAlpha != mAlpha.end() && *itAlpha != Ogre::StringUtil::BLANK) { Ogre::Real alpha = Ogre::StringConverter::parseReal(*itAlpha); correctAlpha(nextImage, alpha); itAlpha++; } if (itFrame != mInputFrames.end()) { size_t firstFrame = nextFrame; nextFrame = Ogre::StringConverter::parseUnsignedInt(*itFrame); itFrame++; frameCounter++; // Generate and add interpolated images to the atlas image size_t numberOfFrames = nextFrame - firstFrame; for (size_t i = 1; i < numberOfFrames; ++i) { Ogre::Real fraction = (Ogre::Real)i / (Ogre::Real)numberOfFrames; Ogre::Image interpolatedImage; size_t pixelSize = Ogre::PixelUtil::getNumElemBytes(firstImage.getFormat()); size_t bufferSize = firstImage.getWidth() * firstImage.getHeight() * pixelSize; Ogre::uchar* data = OGRE_ALLOC_T(Ogre::uchar, bufferSize, Ogre::MEMCATEGORY_GENERAL); interpolatedImage.loadDynamicImage(data, firstImage.getWidth(), firstImage.getHeight(), 1, firstImage.getFormat(), true); interpolate (interpolatedImage, firstImage, nextImage, fraction); mAtlasImage.addImage(&interpolatedImage); frameCounter++; } } mAtlasImage.addImage(&nextImage); frameCounter++; itInputFileName++; } } mAtlasImage._compile(); mAtlasImage.save(mImagePath + "//" + mOutputImage); }
void MaterialPreviewDialog::buildPreviewBitmap( const Ogre::String &texName ) { const Ogre::uchar BytePerPixel = 8; // 读取原始image Ogre::Image *oriImage = getPreviewImage(texName); // 源大纹理的大小 size_t oriImageHeight = oriImage->getHeight(); size_t oriImageWidth = oriImage->getWidth(); Ogre::uchar *oriImageData = oriImage->getData(); // 分配一个足够大的空间来保存新建的image的数据 size_t newImagegetRowSpan = oriImageWidth*oriImage->getBPP()/BytePerPixel; // 新建的image的行宽(单位为字节) Ogre::uchar *newImageData = OGRE_ALLOC_T(Ogre::uchar, oriImageHeight*newImagegetRowSpan, Ogre::MEMCATEGORY_GENERAL);//new Ogre::uchar[oriImageHeight*newImagegetRowSpan]; Ogre::uchar *newImageDataPointer = newImageData; Ogre::uchar *oriImagedataPointer = oriImageData; // 把所选的纹理的数据提取出来,并创建一个新的image for ( Ogre::uint i=0; i<oriImageHeight; ++i ) { memcpy(newImageDataPointer, oriImagedataPointer, newImagegetRowSpan); newImageDataPointer += newImagegetRowSpan; oriImagedataPointer += oriImage->getRowSpan(); } Ogre::Image newImage; newImage.loadDynamicImage(newImageData,oriImageWidth,oriImageHeight,1,oriImage->getFormat(),true); // 如果所选纹理大于64*64,就先resize if ( oriImageWidth > mPreviewImageWidth || oriImageHeight > mPreviewImageHeight ) newImage.resize(mPreviewImageWidth, mPreviewImageHeight); // 如果有alpha,要与黑白图进行混合 if ( newImage.getHasAlpha() ) { Ogre::ColourValue col; for ( int i=0; i<mPreviewImageWidth; ++i ) { for ( int j=0; j<mPreviewImageWidth; ++j ) { col = newImage.getColourAt(j,i,0); float alphaValue = col.a; unsigned char r = col.r*255 * alphaValue; unsigned char g = col.g*255 * alphaValue; unsigned char b = col.b*255 * alphaValue; // 设置到image中 mCurrentPreviewImage.SetRGB(j,i,r,g,b); } } } // 没有alpha,就直接拷贝数据 else { Ogre::ColourValue col; for ( int i=0; i<mPreviewImageWidth; ++i ) { for ( int j=0; j<mPreviewImageWidth; ++j ) { col = newImage.getColourAt(j,i,0); unsigned char r = col.r*255; unsigned char g = col.g*255; unsigned char b = col.b*255; // 设置到image中 mCurrentPreviewImage.SetRGB(j,i,r,g,b); } } } }
void BrushSelector::buildPreviewBitmap( const Fairy::TextureInfo texInfo ) { const Ogre::uchar BytePerPixel = 8; // 读取原始image Ogre::Image *oriImage = GetSceneManipulator()->getPreviewImage(texInfo.ownerTextureName); // 源大纹理的大小 size_t oriImageHeight = oriImage->getHeight(); size_t oriImageWidth = oriImage->getWidth(); Ogre::uchar *oriImageData = oriImage->getData(); // 所选纹理的大小 size_t newImageWidth = texInfo.width*TexTileSize; size_t newImageHeight = texInfo.height*TexTileSize; // 分配一个足够大的空间来保存新建的image的数据 size_t newImagegetRowSpan = newImageWidth*oriImage->getBPP()/BytePerPixel; // 新建的image的行宽(单位为字节) Ogre::uchar *newImageData = OGRE_ALLOC_T(Ogre::uchar, oriImageHeight*newImagegetRowSpan, Ogre::MEMCATEGORY_GENERAL);//new Ogre::uchar[newImageHeight*newImagegetRowSpan]; Ogre::uchar *newImageDataPointer = newImageData; // 得知起始像素点 size_t startPoint = ( oriImageWidth * texInfo.topCorner + texInfo.leftCorner ) * TexTileSize * oriImage->getBPP()/BytePerPixel; Ogre::uchar *oriImagedataPointer = oriImageData + startPoint; // 把所选的纹理的数据提取出来,并创建一个新的image for ( Ogre::uint i=0; i<newImageHeight; ++i ) { memcpy(newImageDataPointer, oriImagedataPointer, newImagegetRowSpan); newImageDataPointer += newImagegetRowSpan; oriImagedataPointer += oriImage->getRowSpan(); } Ogre::Image newImage; newImage.loadDynamicImage(newImageData,newImageWidth,newImageHeight,1,oriImage->getFormat(),true); // 如果所选纹理大于64*64,就先resize if ( texInfo.width > 1 || texInfo.height > 1 ) newImage.resize(mPreviewImageWidth, mPreviewImageHeight); // 如果有alpha,要与黑白图进行混合 if ( newImage.getHasAlpha() ) { Ogre::ColourValue col; for ( int i=0; i<mPreviewImageWidth; ++i ) { for ( int j=0; j<mPreviewImageWidth; ++j ) { col = newImage.getColourAt(j,i,0); float alphaValue = col.a; unsigned char r = col.r*255 * alphaValue + mBlackWhitePreviewImage.GetRed(i,j) * ( 1.0f - alphaValue); unsigned char g = col.g*255 * alphaValue + mBlackWhitePreviewImage.GetGreen(i,j) * ( 1.0f - alphaValue); unsigned char b = col.b*255 * alphaValue + mBlackWhitePreviewImage.GetBlue(i,j) * ( 1.0f - alphaValue); // 设置到image中 mCurrentPreviewImage.SetRGB(j,i,r,g,b); } } // 设置到缩略图控件中 mBrushesPreview->SetBitmap(mCurrentPreviewImage); } // 没有alpha,就直接拷贝数据 else { Ogre::ColourValue col; for ( int i=0; i<mPreviewImageWidth; ++i ) { for ( int j=0; j<mPreviewImageWidth; ++j ) { col = newImage.getColourAt(j,i,0); unsigned char r = col.r*255; unsigned char g = col.g*255; unsigned char b = col.b*255; // 设置到image中 mCurrentPreviewImage.SetRGB(j,i,r,g,b); } } mBrushesPreview->SetBitmap(mCurrentPreviewImage); } }
//------------------------------------------------------------------------- void HeightmapTerrainPageSource::requestPage(ushort x, ushort y) { // Only 1 page provided if (x == 0 && y == 0 && !mPage) { // Convert the image data to unscaled floats ulong totalPageSize = mPageSize * mPageSize; Real *heightData = OGRE_ALLOC_T(Real, totalPageSize, MEMCATEGORY_RESOURCE); const uchar* pOrigSrc, *pSrc; Real* pDest = heightData; Real invScale; bool is16bit = false; if (mIsRaw) { pOrigSrc = mRawData->getPtr(); is16bit = (mRawBpp == 2); } else { PixelFormat pf = mImage.getFormat(); if (pf != PF_L8 && pf != PF_L16) { OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "Error: Image is not a grayscale image.", "HeightmapTerrainPageSource::requestPage" ); } pOrigSrc = mImage.getData(); is16bit = (pf == PF_L16); } // Determine mapping from fixed to floating ulong rowSize; if ( is16bit ) { invScale = 1.0f / 65535.0f; rowSize = mPageSize * 2; } else { invScale = 1.0f / 255.0f; rowSize = mPageSize; } // Read the data pSrc = pOrigSrc; for (ulong j = 0; j < mPageSize; ++j) { if (mFlipTerrain) { // Work backwards pSrc = pOrigSrc + (rowSize * (mPageSize - j - 1)); } for (ulong i = 0; i < mPageSize; ++i) { if (is16bit) { #if OGRE_ENDIAN == OGRE_ENDIAN_BIG ushort val = *pSrc++ << 8; val += *pSrc++; #else ushort val = *pSrc++; val += *pSrc++ << 8; #endif *pDest++ = Real(val) * invScale; } else { *pDest++ = Real(*pSrc++) * invScale; } } } // Call listeners firePageConstructed(0, 0, heightData); // Now turn into TerrainPage // Note that we're using a single material for now if (mSceneManager) { mPage = buildPage(heightData, mSceneManager->getOptions().terrainMaterial); mSceneManager->attachPage(0, 0, mPage); } // Free temp store OGRE_FREE(heightData, MEMCATEGORY_RESOURCE); } }
//----------------------------------------------------------------------- bool BspRaySceneQuery::processLeaf(const BspNode* leaf, const Ray& tracingRay, RaySceneQueryListener* listener, Real maxDistance, Real traceDistance) { const BspNode::IntersectingObjectSet& objects = leaf->getObjects(); BspNode::IntersectingObjectSet::const_iterator i, iend; iend = objects.end(); //Check ray against objects for(i = objects.begin(); i != iend; ++i) { // cast away constness, constness of node is nothing to do with objects MovableObject* obj = const_cast<MovableObject*>(*i); // Skip this object if not enabled if(!(obj->getQueryFlags() & mQueryMask) || !((obj->getTypeFlags() & mQueryTypeMask))) continue; // check we haven't reported this one already // (objects can be intersecting more than one node) if (mObjsThisQuery.find(obj) != mObjsThisQuery.end()) continue; //Test object as bounding box std::pair<bool, Real> result = tracingRay.intersects(obj->getWorldBoundingBox()); // if the result came back positive and intersection point is inside // the node, fire the event handler if(result.first && result.second <= maxDistance) { if (!listener->queryResult(obj, result.second + traceDistance)) return false; } } // Check ray against brushes if (mQueryTypeMask & SceneManager::WORLD_GEOMETRY_TYPE_MASK) { const BspNode::NodeBrushList& brushList = leaf->getSolidBrushes(); BspNode::NodeBrushList::const_iterator bi, biend; biend = brushList.end(); bool intersectedBrush = false; for (bi = brushList.begin(); bi != biend; ++bi) { BspNode::Brush* brush = *bi; std::pair<bool, Real> result = Math::intersects(tracingRay, brush->planes, true); // if the result came back positive and intersection point is inside // the node, check if this brush is closer if(result.first && result.second <= maxDistance) { intersectedBrush = true; if(mWorldFragmentType == SceneQuery::WFT_SINGLE_INTERSECTION) { // We're interested in a single intersection // Have to create these SceneQuery::WorldFragment* wf = OGRE_ALLOC_T(SceneQuery::WorldFragment, 1, MEMCATEGORY_SCENE_CONTROL); wf->fragmentType = SceneQuery::WFT_SINGLE_INTERSECTION; wf->singleIntersection = tracingRay.getPoint(result.second); // save this so we can clean up later mSingleIntersections.push_back(wf); if (!listener->queryResult(wf, result.second + traceDistance)) return false; } else if (mWorldFragmentType == SceneQuery::WFT_PLANE_BOUNDED_REGION) { // We want the whole bounded volume assert((*bi)->fragment.fragmentType == SceneQuery::WFT_PLANE_BOUNDED_REGION); if (!listener->queryResult(const_cast<WorldFragment*>(&(brush->fragment)), result.second + traceDistance)) return false; } } } if (intersectedBrush) { return false; // stop here } } return true; }
void createTerrainLightmap(const TerrainInfo& info, Image& image, size_t width, size_t height, Vector3 lightDir, const ColourValue& lightCol, const ColourValue& ambient, bool shadowed) { lightDir.normalise(); // calculate lightmap by multiplying light dir with terrain normals // calculate the step size to use AxisAlignedBox extents = info.getExtents(); Vector3 startPos = extents.getMinimum(); Vector3 step = extents.getMaximum() - extents.getMinimum(); step.x /= width; step.z /= height; Vector3 pos = startPos; #if OGRE_VERSION_MINOR > 4 // Ogre::Image uses the memory allocation macros internally in Shoggoth, // so we must use them as well. uchar* lightMap = OGRE_ALLOC_T(uchar, width*height*3, MEMCATEGORY_GENERAL); #else uchar* lightMap = new uchar[width*height * 3]; #endif memset(lightMap, 255, width*height*3); for (size_t z = 0; z < height; ++z) { for (size_t x = 0; x < width; ++x) { size_t index = (z * width + x)*3; // calculate diffuse light from light source Vector3 norm = info.getNormalAt(pos.x, pos.z); float l = std::max(0.0f, -lightDir.dotProduct(norm)); ColourValue v = ambient; v.r = std::min(1.0f, v.r+l*lightCol.r); v.g = std::min(1.0f, v.g+l*lightCol.g); v.b = std::min(1.0f, v.b+l*lightCol.b); lightMap[index+0] = (uchar) (255*v.r); lightMap[index+1] = (uchar) (255*v.g); lightMap[index+2] = (uchar) (255*v.b); pos.x += step.x; } pos.x = startPos.x; pos.z += step.z; } if (shadowed && (lightDir.x != 0 || lightDir.z != 0)) { // add terrain shadows Impl::addTerrainShadowsToLightmap(lightMap, info, width, height, lightDir, ambient); } // use a box filter to smoothen the lightmap Impl::boxFilterLightmap(lightMap, width, height); // save lightmap to image image.loadDynamicImage(lightMap, width, height, 1, PF_BYTE_RGB, true); // ownership of lightMap was transfered to image, don't need to delete }
//----------------------------------------------------------------------------- Image & Image::flipAroundY() { if( !mBuffer ) { OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can not flip an uninitialised texture", "Image::flipAroundY" ); } mNumMipmaps = 0; // Image operations lose precomputed mipmaps uchar *pTempBuffer1 = NULL; ushort *pTempBuffer2 = NULL; uchar *pTempBuffer3 = NULL; uint *pTempBuffer4 = NULL; uchar *src1 = mBuffer; ushort *src2 = (ushort *)mBuffer; uchar *src3 = mBuffer; uint *src4 = (uint *)mBuffer; ushort y; switch (mPixelSize) { case 1: pTempBuffer1 = OGRE_ALLOC_T(uchar, mWidth * mHeight, MEMCATEGORY_GENERAL); for (y = 0; y < mHeight; y++) { uchar *dst1 = (pTempBuffer1 + ((y * mWidth) + mWidth - 1)); for (ushort x = 0; x < mWidth; x++) memcpy(dst1--, src1++, sizeof(uchar)); } memcpy(mBuffer, pTempBuffer1, mWidth * mHeight * sizeof(uchar)); OGRE_FREE(pTempBuffer1, MEMCATEGORY_GENERAL); break; case 2: pTempBuffer2 = OGRE_ALLOC_T(ushort, mWidth * mHeight, MEMCATEGORY_GENERAL); for (y = 0; y < mHeight; y++) { ushort *dst2 = (pTempBuffer2 + ((y * mWidth) + mWidth - 1)); for (ushort x = 0; x < mWidth; x++) memcpy(dst2--, src2++, sizeof(ushort)); } memcpy(mBuffer, pTempBuffer2, mWidth * mHeight * sizeof(ushort)); OGRE_FREE(pTempBuffer2, MEMCATEGORY_GENERAL); break; case 3: pTempBuffer3 = OGRE_ALLOC_T(uchar, mWidth * mHeight * 3, MEMCATEGORY_GENERAL); for (y = 0; y < mHeight; y++) { size_t offset = ((y * mWidth) + (mWidth - 1)) * 3; uchar *dst3 = pTempBuffer3; dst3 += offset; for (size_t x = 0; x < mWidth; x++) { memcpy(dst3, src3, sizeof(uchar) * 3); dst3 -= 3; src3 += 3; } } memcpy(mBuffer, pTempBuffer3, mWidth * mHeight * sizeof(uchar) * 3); OGRE_FREE(pTempBuffer3, MEMCATEGORY_GENERAL); break; case 4: pTempBuffer4 = OGRE_ALLOC_T(uint, mWidth * mHeight, MEMCATEGORY_GENERAL); for (y = 0; y < mHeight; y++) { uint *dst4 = (pTempBuffer4 + ((y * mWidth) + mWidth - 1)); for (ushort x = 0; x < mWidth; x++) memcpy(dst4--, src4++, sizeof(uint)); } memcpy(mBuffer, pTempBuffer4, mWidth * mHeight * sizeof(uint)); OGRE_FREE(pTempBuffer4, MEMCATEGORY_GENERAL); break; default: OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Unknown pixel depth", "Image::flipAroundY" ); break; } return *this; }
//--------------------------------------------------------------------- void DeflateStream::init() { mZStream = OGRE_ALLOC_T(z_stream, 1, MEMCATEGORY_GENERAL); mZStream->zalloc = OgreZalloc; mZStream->zfree = OgreZfree; if (getAccessMode() == READ) { mTmp = (unsigned char*)OGRE_MALLOC(OGRE_DEFLATE_TMP_SIZE, MEMCATEGORY_GENERAL); size_t restorePoint = mCompressedStream->tell(); // read early chunk mZStream->next_in = mTmp; mZStream->avail_in = static_cast<uint>(mCompressedStream->read(mTmp, getAvailInForSinglePass())); if (inflateInit(mZStream) != Z_OK) { mIsCompressedValid = false; } else mIsCompressedValid = true; if (mIsCompressedValid) { // in fact, inflateInit on some implementations doesn't try to read // anything. We need to at least read something to test Bytef testOut[4]; size_t savedIn = mZStream->avail_in; mZStream->avail_out = 4; mZStream->next_out = testOut; if (inflate(mZStream, Z_SYNC_FLUSH) != Z_OK) mIsCompressedValid = false; // restore for reading mZStream->avail_in = static_cast<uint>(savedIn); mZStream->next_in = mTmp; inflateReset(mZStream); } if (!mIsCompressedValid) { // Not compressed data! // Fail gracefully, fall back on reading the underlying stream direct destroy(); mCompressedStream->seek(restorePoint); } } else { if(mTempFileName.empty()) { // Write to temp file #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WINRT char* tmpname = _tempnam(".", "ogre"); if (!tmpname) { // Having no file name here will cause various problems later. OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Temporary file name generation failed.", "DeflateStream::init"); } else { mTempFileName = tmpname; free(tmpname); } #elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS || OGRE_PLATFORM == OGRE_PLATFORM_APPLE mTempFileName = macTempFileName(); #else char tmpname[] = "/tmp/ogreXXXXXX"; if (mkstemp(tmpname) == -1) OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Temporary file name generation failed.", "DeflateStream::init"); mTempFileName = tmpname; #endif } std::fstream *f = OGRE_NEW_T(std::fstream, MEMCATEGORY_GENERAL)(); f->open(mTempFileName.c_str(), std::ios::binary | std::ios::out); mTmpWriteStream = DataStreamPtr(OGRE_NEW FileStreamDataStream(f)); } }
//--------------------------------------------------------------------- FIBITMAP* FreeImageCodec::encode(MemoryDataStreamPtr& input, CodecDataPtr& pData) const { // Set error handler FreeImage_SetOutputMessage(FreeImageSaveErrorHandler); FIBITMAP* ret = 0; ImageData* pImgData = static_cast< ImageData * >( pData.getPointer() ); PixelBox src(pImgData->width, pImgData->height, pImgData->depth, pImgData->format, input->getPtr()); // The required format, which will adjust to the format // actually supported by FreeImage. PixelFormat requiredFormat = pImgData->format; // determine the settings FREE_IMAGE_TYPE imageType; PixelFormat determiningFormat = pImgData->format; switch(determiningFormat) { case PF_R5G6B5: case PF_B5G6R5: case PF_R8G8B8: case PF_B8G8R8: case PF_A8R8G8B8: case PF_X8R8G8B8: case PF_A8B8G8R8: case PF_X8B8G8R8: case PF_B8G8R8A8: case PF_R8G8B8A8: case PF_A4L4: case PF_BYTE_LA: case PF_R3G3B2: case PF_A4R4G4B4: case PF_A1R5G5B5: case PF_A2R10G10B10: case PF_A2B10G10R10: // I'd like to be able to use r/g/b masks to get FreeImage to load the data // in it's existing format, but that doesn't work, FreeImage needs to have // data in RGB[A] (big endian) and BGR[A] (little endian), always. if (PixelUtil::hasAlpha(determiningFormat)) { #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB requiredFormat = PF_BYTE_RGBA; #else requiredFormat = PF_BYTE_BGRA; #endif } else { #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB requiredFormat = PF_BYTE_RGB; #else requiredFormat = PF_BYTE_BGR; #endif } // fall through case PF_L8: case PF_A8: imageType = FIT_BITMAP; break; case PF_L16: imageType = FIT_UINT16; break; case PF_SHORT_GR: requiredFormat = PF_SHORT_RGB; // fall through case PF_SHORT_RGB: imageType = FIT_RGB16; break; case PF_SHORT_RGBA: imageType = FIT_RGBA16; break; case PF_FLOAT16_R: requiredFormat = PF_FLOAT32_R; // fall through case PF_FLOAT32_R: imageType = FIT_FLOAT; break; case PF_FLOAT16_GR: case PF_FLOAT16_RGB: case PF_FLOAT32_GR: requiredFormat = PF_FLOAT32_RGB; // fall through case PF_FLOAT32_RGB: imageType = FIT_RGBF; break; case PF_FLOAT16_RGBA: requiredFormat = PF_FLOAT32_RGBA; // fall through case PF_FLOAT32_RGBA: imageType = FIT_RGBAF; break; default: OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Invalid image format", "FreeImageCodec::encode"); }; // Check support for this image type & bit depth if (!FreeImage_FIFSupportsExportType((FREE_IMAGE_FORMAT)mFreeImageType, imageType) || !FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, (int)PixelUtil::getNumElemBits(requiredFormat))) { // Ok, need to allocate a fallback // Only deal with RGBA -> RGB for now switch (requiredFormat) { case PF_BYTE_RGBA: requiredFormat = PF_BYTE_RGB; break; case PF_BYTE_BGRA: requiredFormat = PF_BYTE_BGR; break; default: break; }; } bool conversionRequired = false; unsigned char* srcData = input->getPtr(); // Check BPP unsigned bpp = static_cast<unsigned>(PixelUtil::getNumElemBits(requiredFormat)); if (!FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, (int)bpp)) { if (bpp == 32 && PixelUtil::hasAlpha(pImgData->format) && FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, 24)) { // drop to 24 bit (lose alpha) #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB requiredFormat = PF_BYTE_RGB; #else requiredFormat = PF_BYTE_BGR; #endif bpp = 24; } else if (bpp == 128 && PixelUtil::hasAlpha(pImgData->format) && FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, 96)) { // drop to 96-bit floating point requiredFormat = PF_FLOAT32_RGB; } } PixelBox convBox(pImgData->width, pImgData->height, 1, requiredFormat); if (requiredFormat != pImgData->format) { conversionRequired = true; // Allocate memory convBox.data = OGRE_ALLOC_T(uchar, convBox.getConsecutiveSize(), MEMCATEGORY_GENERAL); // perform conversion and reassign source PixelBox src(pImgData->width, pImgData->height, 1, pImgData->format, input->getPtr()); PixelUtil::bulkPixelConversion(src, convBox); srcData = static_cast<unsigned char*>(convBox.data); } ret = FreeImage_AllocateT( imageType, static_cast<int>(pImgData->width), static_cast<int>(pImgData->height), bpp); if (!ret) { if (conversionRequired) OGRE_FREE(convBox.data, MEMCATEGORY_GENERAL); OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "FreeImage_AllocateT failed - possibly out of memory. ", __FUNCTION__); } if (requiredFormat == PF_L8 || requiredFormat == PF_A8) { // Must explicitly tell FreeImage that this is greyscale by setting // a "grey" palette (otherwise it will save as a normal RGB // palettized image). FIBITMAP *tmp = FreeImage_ConvertToGreyscale(ret); FreeImage_Unload(ret); ret = tmp; } size_t dstPitch = FreeImage_GetPitch(ret); size_t srcPitch = pImgData->width * PixelUtil::getNumElemBytes(requiredFormat); // Copy data, invert scanlines and respect FreeImage pitch uchar* pSrc; uchar* pDst = FreeImage_GetBits(ret); for (size_t y = 0; y < pImgData->height; ++y) { pSrc = srcData + (pImgData->height - y - 1) * srcPitch; memcpy(pDst, pSrc, srcPitch); pDst += dstPitch; } if (conversionRequired) { // delete temporary conversion area OGRE_FREE(convBox.data, MEMCATEGORY_GENERAL); } return ret; }