blob: 6db2cc95d3279f09404d650f04c70fe98c79ed2b [file] [log] [blame]
/*
* Project: VizKit
* Version: 2.3
* Date: 20090823
* File: VisualTextureContainer.cpp
*
*/
/***************************************************************************
Copyright (c) 2004-2009 Heiko Wichmann (http://www.imagomat.de/vizkit)
This software is provided 'as-is', without any expressed or implied warranty.
In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated
but is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
***************************************************************************/
#include "VisualTextureContainer.h"
#include "VisualGraphicTypes.h"
#include "VisualVertex.h"
#include "VisualConvolutionFilter.h"
#include "VisualStyledString.h"
#include "VisualFile.h"
#include "VisualGraphics.h"
#include "VisualColorTools.h"
#include "VisualErrorHandling.h"
#include "VisualDispatch.h"
#include "VisualCamera.h"
#if TARGET_OS_MAC
#include <ApplicationServices/../Frameworks/ImageIO.framework/Headers/ImageIO.h> // CGImage...
#endif
#if TARGET_OS_WIN
#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
#endif
using namespace VizKit;
VisualTextureContainer::TextureRefCountMap VisualTextureContainer::textureRefCountMap;
VisualTextureContainer::VisualTextureContainer() {
aTextureIsSet = false;
textureName = 0;
textureRect.width = 0;
textureRect.height = 0;
logicalSize.width = 0.0;
logicalSize.height = 0.0;
imageRect.width = 0;
imageRect.height = 0;
useRectExtension = false;
}
VisualTextureContainer::~VisualTextureContainer() {
this->releaseTextureData();
}
VisualTextureContainer::VisualTextureContainer(const VisualTextureContainer& other) {
copy(other);
}
VisualTextureContainer& VisualTextureContainer::operator=(const VisualTextureContainer& other) {
if (this == &other) return *this;
if ((this->aTextureIsSet) && (this->textureName != other.textureName)) {
this->releaseTextureData();
}
this->copy(other);
return *this;
}
bool VisualTextureContainer::initWithFile(VisualFile& aFile) {
bool success = true;
this->releaseTextureData();
void* encodedImageData = NULL;
size_t encodedImageDataSize = 0;
success = aFile.getData(&encodedImageData, encodedImageDataSize);
if (!success) {
return success;
}
success = this->initWithEncodedData((const char* const)encodedImageData, encodedImageDataSize);
return success;
}
bool VisualTextureContainer::initWithEncodedData(const char* const bufferData, size_t size) {
bool success = true;
bool debug = false;
this->releaseTextureData();
uint32* aPixelBuffer = NULL;
#if TARGET_OS_WIN
HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, (SIZE_T)size);
if (!hGlobal)
return false;
BYTE* pDest = (BYTE*)::GlobalLock(hGlobal);
memcpy(pDest, bufferData, size);
::GlobalUnlock(hGlobal);
IStream* pStream = NULL;
if (::CreateStreamOnHGlobal(hGlobal, FALSE, &pStream) != S_OK)
return false;
Gdiplus::Bitmap* bitmap = Gdiplus::Bitmap::FromStream(pStream);
bitmap->RotateFlip(Gdiplus::RotateNoneFlipY);
this->imageRect.width = bitmap->GetWidth();
this->imageRect.height = bitmap->GetHeight();
VisualGraphics* theVisualGraphics = VisualGraphics::getInstance();
this->useRectExtension = theVisualGraphics->canUseTextureRectExtension();
if (this->useRectExtension == false) {
this->textureRect.width = theVisualGraphics->power2Ceiling(this->imageRect.width);
this->textureRect.height = theVisualGraphics->power2Ceiling(this->imageRect.height);
} else {
this->textureRect.width = this->imageRect.width;
this->textureRect.height = this->imageRect.height;
}
aPixelBuffer = (uint32*)malloc(this->imageRect.width * this->imageRect.height * sizeof(uint32));
Gdiplus::Rect rect(0, 0, this->imageRect.width, this->imageRect.height);
Gdiplus::BitmapData* bitmapData = new Gdiplus::BitmapData;
bitmapData->Width = this->imageRect.width;
bitmapData->Height = this->imageRect.height;
bitmapData->Stride = sizeof(uint32) * bitmapData->Width;
bitmapData->PixelFormat = PixelFormat32bppARGB;
bitmapData->Scan0 = (VOID*)aPixelBuffer;
Gdiplus::Status status = Gdiplus::Ok;
status = bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeUserInputBuf, PixelFormat32bppPARGB, bitmapData);
#endif
#if TARGET_OS_MAC
CFDataRef dataRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8*)bufferData, (CFIndex)size, kCFAllocatorDefault);
CFDictionaryRef options = NULL;
CGImageSourceRef imageSourceRef = CGImageSourceCreateWithData(dataRef, options);
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSourceRef, 0, options);
this->imageRect.width = CGImageGetWidth(imageRef);
this->imageRect.height = CGImageGetHeight(imageRef);
VisualGraphics* theVisualGraphics = VisualGraphics::getInstance();
this->useRectExtension = theVisualGraphics->canUseTextureRectExtension();
if (this->useRectExtension == false) {
this->textureRect.width = theVisualGraphics->power2Ceiling(this->imageRect.width);
this->textureRect.height = theVisualGraphics->power2Ceiling(this->imageRect.height);
} else {
this->textureRect.width = this->imageRect.width;
this->textureRect.height = this->imageRect.height;
}
CGContextRef contextPtr = theVisualGraphics->createBitmapContext(this->imageRect.width, this->imageRect.height);
CGContextTranslateCTM(contextPtr, 0, this->imageRect.height);
CGContextScaleCTM(contextPtr, 1.0f, -1.0f);
CGRect rect = CGRectMake(0, 0, this->imageRect.width, this->imageRect.height);
CGContextDrawImage(contextPtr, rect, imageRef);
aPixelBuffer = static_cast<uint32*>(CGBitmapContextGetData(contextPtr));
#endif
PixelColor* interleavedARGBColorPixelBuffer = NULL;
if (debug == true) {
interleavedARGBColorPixelBuffer = VisualColorTools::createARGBCheckPixels(this->textureRect.width, this->textureRect.height);
} else {
interleavedARGBColorPixelBuffer = static_cast<PixelColor*>(aPixelBuffer);
}
success = this->initWithARGBPixelData(interleavedARGBColorPixelBuffer, this->imageRect.width, this->imageRect.height);
#if TARGET_OS_MAC
CGContextRelease(contextPtr);
CGImageRelease(imageRef);
#endif
#if TARGET_OS_WIN
bitmap->UnlockBits(bitmapData);
#endif
return success;
}
bool VisualTextureContainer::initWithARGBPixelData(PixelColor* argbPixels, size_t imageWidth, size_t imageHeight, bool debug) {
bool success = true;
this->imageRect.width = imageWidth;
this->imageRect.height = imageHeight;
VisualGraphics* theVisualGraphics = VisualGraphics::getInstance();
this->useRectExtension = theVisualGraphics->canUseTextureRectExtension();
if (this->useRectExtension == false) {
this->textureRect.width = theVisualGraphics->power2Ceiling(this->imageRect.width);
this->textureRect.height = theVisualGraphics->power2Ceiling(this->imageRect.height);
} else {
this->textureRect.width = this->imageRect.width;
this->textureRect.height = this->imageRect.height;
}
this->textureName = theVisualGraphics->getNextFreeTextureName();
this->aTextureIsSet = true;
VisualTextureContainer::textureRefCountMap[this->textureName] = 1;
success = theVisualGraphics->copyARGBBitmapDataToTexture(this->textureName, this->imageRect.width, this->imageRect.height, this->useRectExtension, const_cast<const uint32**>(&(argbPixels)), debug);
if (this->useRectExtension == false) {
this->logicalSize.width = (double)this->imageRect.width / (double)this->textureRect.width;
this->logicalSize.height = (double)this->imageRect.height / (double)this->textureRect.height;
} else {
this->logicalSize.width = (double)this->textureRect.width;
this->logicalSize.height = (double)this->textureRect.height;
}
return success;
}
bool VisualTextureContainer::initWithBGRAPixelData(PixelColor* bgraPixels, size_t imageWidth, size_t imageHeight, bool debug) {
uint32 numberOfPixels = imageWidth * imageHeight;
VisualColorTools::convertInterleavedPixels1234To4321(bgraPixels, numberOfPixels);
return this->initWithARGBPixelData(bgraPixels, imageWidth, imageHeight, debug);
}
bool VisualTextureContainer::initWithStyledString(VisualStyledString& styledString) {
this->releaseTextureData();
bool success = true;
const VisualString* aVisualString = &(styledString);
VisualStringStyle& stringStyle = styledString.getStyle();
if (aVisualString->getNumberOfCharacters() == 0) {
return false;
}
VisualGraphics* theVisualGraphics = VisualGraphics::getInstance();
uint32 maxPixelWidth = theVisualGraphics->getCanvasPixelWidth();
uint32 maxPixelHeight = theVisualGraphics->getCanvasPixelHeight();
this->textureName = theVisualGraphics->getNextFreeTextureName();
this->aTextureIsSet = true;
VisualTextureContainer::textureRefCountMap[this->textureName] = 1;
this->useRectExtension = theVisualGraphics->canUseTextureRectExtension();
#if TARGET_OS_MAC
char alignmentStr[32];
switch (stringStyle.horizontalAlignment) {
case (kLeftAligned):
strcpy(alignmentStr, "left");
break;
case(kCenterAligned):
strcpy(alignmentStr, "center");
break;
case(kRightAligned):
strcpy(alignmentStr, "right");
break;
default:
break;
}
success = getDimensionsOfCocoaStringBitmap((void*)aVisualString, (void*)&stringStyle, &(this->imageRect.width), &(this->imageRect.height), maxPixelWidth, maxPixelHeight, alignmentStr);
if (!success) {
return success;
}
if (this->useRectExtension == false) {
this->textureRect.width = theVisualGraphics->power2Ceiling(this->imageRect.width);
this->textureRect.height = theVisualGraphics->power2Ceiling(this->imageRect.height);
} else {
this->textureRect.width = this->imageRect.width;
this->textureRect.height = this->imageRect.height;
}
PixelColor* pixelBuffer = (uint32*)calloc(this->textureRect.width * this->textureRect.height, sizeof(uint32));
success = getCocoaStringBitmapData((void*)&styledString, this->textureRect.width, this->textureRect.height, alignmentStr, &(pixelBuffer));
success = theVisualGraphics->copyARGBBitmapDataToTexture(this->textureName, this->textureRect.width, this->textureRect.height, this->useRectExtension, const_cast<const uint32**>(&(pixelBuffer)));
#endif
#if TARGET_OS_WIN
wchar_t* stringValueRef = (wchar_t*)(styledString.getCharactersPointer());
uint8 red = (uint8)(stringStyle.fontColor.r * 255.0f);
uint8 green = (uint8)(stringStyle.fontColor.g * 255.0f);
uint8 blue = (uint8)(stringStyle.fontColor.b * 255.0f);
if (!stringValueRef) {
success = false;
return success;
}
success = theVisualGraphics->makeTextureOfStringWin(stringValueRef, styledString.getNumberOfCharacters(), this->textureName, this->textureRect.width, this->textureRect.height, this->imageRect.width, this->imageRect.height, stringStyle.fontNameStr, (uint16)stringStyle.fontSize, red, green, blue, stringStyle.horizontalAlignment, maxPixelWidth, maxPixelHeight);
#endif
if (this->useRectExtension == false) {
this->logicalSize.width = (double)this->imageRect.width / (double)this->textureRect.width;
this->logicalSize.height = (double)this->imageRect.height / (double)this->textureRect.height;
} else {
this->logicalSize.width = (double)this->textureRect.width;
this->logicalSize.height = (double)this->textureRect.height;
}
return success;
}
void VisualTextureContainer::clean() {
this->releaseTextureData();
}
bool VisualTextureContainer::initWithFramebuffer(const BottomLeftPositionedPixelRect& clipRect) {
bool success = true;
uint16 dataType;
uint16 pixelFormat = kGL_BGRA;
// BGRA on intel machines and ARGB on ppc
#if TARGET_OS_WIN
dataType = kGL_UNSIGNED_BYTE;
#else
#if __BIG_ENDIAN__
dataType = kGL_UNSIGNED_INT_8_8_8_8_REV;
#else
dataType = kGL_UNSIGNED_INT_8_8_8_8;
#endif
#endif
VisualGraphics* theVisualGraphics = VisualGraphics::getInstance();
this->releaseTextureData();
this->textureName = theVisualGraphics->getNextFreeTextureName();
this->aTextureIsSet = true;
VisualTextureContainer::textureRefCountMap[this->textureName] = 1;
this->useRectExtension = theVisualGraphics->canUseTextureRectExtension();
int prevReadBuffer = theVisualGraphics->getCurrentColorBufferForPixelReadingOperations();
theVisualGraphics->setColorBufferForPixelReadingOperations(kGL_BACK_COLOR_BUFFER);
int prevDrawBuffer = theVisualGraphics->getCurrentColorBufferForPixelDrawingOperations();
theVisualGraphics->setColorBufferForPixelDrawingOperations(kGL_BACK_COLOR_BUFFER);
theVisualGraphics->enableTexturing(this->useRectExtension);
theVisualGraphics->copyFramebufferToTexture(this->textureName, this->useRectExtension, clipRect, pixelFormat, dataType);
theVisualGraphics->disableTexturing(this->useRectExtension);
theVisualGraphics->setColorBufferForPixelDrawingOperations(prevDrawBuffer);
theVisualGraphics->setColorBufferForPixelReadingOperations(prevReadBuffer);
this->imageRect.width = clipRect.pixelRect.width;
this->imageRect.height = clipRect.pixelRect.height;
this->useRectExtension = theVisualGraphics->canUseTextureRectExtension();
if (this->useRectExtension == false) {
this->textureRect.width = theVisualGraphics->power2Ceiling(this->imageRect.width);
this->textureRect.height = theVisualGraphics->power2Ceiling(this->imageRect.height);
} else {
this->textureRect.width = this->imageRect.width;
this->textureRect.height = this->imageRect.height;
}
return success;
}
PixelColor* VisualTextureContainer::createARGBImagePixels(bool debug) {
PixelColor* pixelBuffer = NULL;
VisualGraphics* theVisualGraphics = VisualGraphics::getInstance();
if (debug == true) {
pixelBuffer = VisualColorTools::createARGBCheckPixels(this->textureRect.width, this->textureRect.height);
return pixelBuffer;
}
theVisualGraphics->enableTexturing(this->useRectExtension);
theVisualGraphics->bindTexture(this->textureName, this->useRectExtension);
theVisualGraphics->setPixelStorageParams();
uint16 format = kGL_BGRA;
uint16 type;
// GL_BGRA/GL_UNSIGNED_BYTE and GL_BGRA/GL_UNSIGNED_INT_8_8_8_8_REV are equivalent on little endian machines
if (this->useRectExtension == false) {
pixelBuffer = (PixelColor*)malloc(this->textureRect.width * this->textureRect.height * sizeof(PixelColor));
type = kGL_UNSIGNED_BYTE;
theVisualGraphics->getPixelsOfCurrentTexture(this->useRectExtension, format, type, &(pixelBuffer));
#if __BIG_ENDIAN__
VisualColorTools::convertInterleavedPixels1234To4321(pixelBuffer, this->textureRect.width * this->textureRect.height);
#endif
if ((this->textureRect.width != this->imageRect.width) || (this->textureRect.height != this->imageRect.height)) {
// copy actual image pixel data out of texture pixel data
Pixel topLeftPosition;
topLeftPosition.x = 0;
topLeftPosition.y = 0;
TopLeftPositionedPixelRect clipRect;
clipRect.topLeftPixel = topLeftPosition;
clipRect.pixelRect = this->imageRect;
PixelColor* clippedPixelData = theVisualGraphics->clipPixelData(pixelBuffer, this->textureRect, clipRect);
free(pixelBuffer);
pixelBuffer = clippedPixelData;
}
} else {
pixelBuffer = (PixelColor*)malloc(this->imageRect.width * this->imageRect.height * sizeof(PixelColor));
type = kGL_UNSIGNED_INT_8_8_8_8_REV;
theVisualGraphics->getPixelsOfCurrentTexture(this->useRectExtension, format, type, &pixelBuffer);
}
theVisualGraphics->disableTexturing(this->useRectExtension);
return pixelBuffer;
}
PixelColor* VisualTextureContainer::createReadPixels(const uint16 format, const uint16 type) {
PixelColor* pixels = NULL;
PixelColor* prevPixels = NULL;
char errStr[512];
double scaleFactor = 1.0;
uint8 numberOfBytesPerChannel = 0;
uint8 numberOfChannels = 0; // channel == color resp. alpha channel
uint8 numberOfBytesPerPixel = 0;
uint32 numberOfBytesPerRow = 0;
if ((format == kGL_RGBA) || (format == kGL_BGRA)) {
numberOfChannels = 4;
} else {
sprintf(errStr, "unknown format %d in file: %s (line: %d) [%s])", format, __FILE__, __LINE__, __FUNCTION__);
writeLog(errStr);
return pixels;
}
if ((type == kGL_UNSIGNED_INT_8_8_8_8_REV) || (type == kGL_UNSIGNED_INT_8_8_8_8) || (type == kGL_UNSIGNED_BYTE)) {
numberOfBytesPerChannel = 1; // // 1 byte (== 8 bits) per color/channel
} else {
sprintf(errStr, "unknown type %d in file: %s (line: %d) [%s])", type, __FILE__, __LINE__, __FUNCTION__);
writeLog(errStr);
return pixels;
}
numberOfBytesPerPixel = numberOfBytesPerChannel * numberOfChannels;
numberOfBytesPerRow = numberOfBytesPerPixel * this->textureRect.width;
VisualGraphics* theVisualGraphics = VisualGraphics::getInstance();
Coord coord;
VisualCamera aCamera;
aCamera.setOrthographicProjection();
coord.x = aCamera.getMaxLeftCoord() * scaleFactor;
coord.y = (aCamera.getMaxBottomCoord() + theVisualGraphics->yPixelToCoord(this->textureRect.height, aCamera)) * scaleFactor;
coord.z = aCamera.getMaxNearPos();
VertexChain aVertexChain;
TexCoord texCoord;
texCoord.s = 0.0;
texCoord.t = this->getTextureLogicalHeight();
VisualVertex* topLeftFrontVertex = new VisualVertex(coord, texCoord, white);
aVertexChain.push_back(topLeftFrontVertex);
coord.x = aCamera.getMaxLeftCoord() * scaleFactor;
coord.y = aCamera.getMaxBottomCoord() * scaleFactor;
coord.z = aCamera.getMaxNearPos();
texCoord.s = 0.0;
texCoord.t = 0.0;
VisualVertex* bottomLeftFrontVertex = new VisualVertex(coord, texCoord, white);
aVertexChain.push_back(bottomLeftFrontVertex);
coord.x = (aCamera.getMaxLeftCoord() + theVisualGraphics->xPixelToCoord(this->textureRect.width, aCamera)) * scaleFactor;
coord.y = aCamera.getMaxBottomCoord() * scaleFactor;
coord.z = aCamera.getMaxNearPos();
texCoord.s = this->getTextureLogicalWidth();
texCoord.t = 0.0;
VisualVertex* bottomRightFrontVertex = new VisualVertex(coord, texCoord, white);
aVertexChain.push_back(bottomRightFrontVertex);
coord.x = (aCamera.getMaxLeftCoord() + theVisualGraphics->xPixelToCoord(this->textureRect.width, aCamera)) * scaleFactor;
coord.y = (aCamera.getMaxBottomCoord() + theVisualGraphics->yPixelToCoord(this->textureRect.height, aCamera)) * scaleFactor;
coord.z = aCamera.getMaxNearPos();
texCoord.s = this->getTextureLogicalWidth();
texCoord.t = this->getTextureLogicalHeight();
VisualVertex* topRightFrontVertex = new VisualVertex(coord, texCoord, white);
aVertexChain.push_back(topRightFrontVertex);
// read previous pixels
if ((format == kGL_RGBA) || (format == kGL_BGRA)) {
prevPixels = (uint32*)calloc((numberOfBytesPerRow / numberOfBytesPerPixel) * this->textureRect.height, numberOfBytesPerPixel);
}
theVisualGraphics->readPixels(aCamera.getMaxLeftCoord(), aCamera.getMaxBottomCoord(), this->textureRect.width, this->textureRect.height, &prevPixels, format, type, aCamera);
// draw current texture
theVisualGraphics->drawTexture(this->textureName, &aVertexChain, this->getUseRectExtension(), kReplace);
// read pixels of current texture
if ((format == kGL_RGBA) || (format == kGL_BGRA)) {
pixels = (uint32*)calloc((numberOfBytesPerRow / numberOfBytesPerPixel) * this->textureRect.height, numberOfBytesPerPixel);
}
theVisualGraphics->readPixels(aCamera.getMaxLeftCoord(), aCamera.getMaxBottomCoord(), this->textureRect.width, this->textureRect.height, &pixels, format, type, aCamera);
// restore previous pixels
theVisualGraphics->drawPixels(&prevPixels, aCamera.getMaxLeftCoord(), aCamera.getMaxBottomCoord(), this->textureRect.width, this->textureRect.height, format, type);
for (VertexChainIterator chainIt = aVertexChain.begin(); chainIt != aVertexChain.end(); chainIt++) {
delete *chainIt;
*chainIt = NULL;
}
aVertexChain.clear();
free(prevPixels);
return pixels;
}
void VisualTextureContainer::copy(const VisualTextureContainer& other) {
if (other.aTextureIsSet) {
VisualTextureContainer::textureRefCountMap[other.textureName]++;
}
this->aTextureIsSet = other.aTextureIsSet;
this->textureName = other.textureName;
this->textureRect = other.textureRect;
this->logicalSize = other.logicalSize;
this->imageRect = other.imageRect;
this->useRectExtension = other.useRectExtension;
}
uint32 VisualTextureContainer::getTextureName() const {
return this->textureName;
}
size_t VisualTextureContainer::getTextureWidth() const {
return this->textureRect.width;
}
size_t VisualTextureContainer::getTextureHeight() const {
return this->textureRect.height;
}
double VisualTextureContainer::getTextureLogicalWidth() const {
return this->logicalSize.width;
}
double VisualTextureContainer::getTextureLogicalHeight() const {
return this->logicalSize.height;
}
size_t VisualTextureContainer::getImageWidth() const {
return this->imageRect.width;
}
size_t VisualTextureContainer::getImageHeight() const {
return this->imageRect.height;
}
bool VisualTextureContainer::getUseRectExtension() const {
return this->useRectExtension;
}
void VisualTextureContainer::releaseTextureData() {
if (this->aTextureIsSet) {
VisualTextureContainer::textureRefCountMap[this->textureName]--;
if (VisualTextureContainer::textureRefCountMap[this->textureName] == 0) {
VisualGraphics* theVisualGraphics = VisualGraphics::getInstance();
theVisualGraphics->deleteTextures(1, &(this->textureName));
this->textureName = 0;
this->aTextureIsSet = false;
}
}
}
bool VisualTextureContainer::textureIsSet() {
return this->aTextureIsSet;
}
void VisualTextureContainer::applyConvolutionFilter(const VisualConvolutionFilter& aConvolutionFilter) {
VisualGraphics* theVisualGraphics = VisualGraphics::getInstance();
uint16 dataType;
uint16 pixelFormat = kGL_BGRA;
// BGRA on intel machines and ARGB on ppc
#if TARGET_OS_WIN
dataType = kGL_UNSIGNED_BYTE;
#else
#if __BIG_ENDIAN__
dataType = kGL_UNSIGNED_INT_8_8_8_8_REV;
#else
dataType = kGL_UNSIGNED_INT_8_8_8_8;
#endif
#endif
if (theVisualGraphics->doesSupportGLConvolutionFilter()) {
int prevReadBuffer = theVisualGraphics->getCurrentColorBufferForPixelReadingOperations();
theVisualGraphics->setColorBufferForPixelReadingOperations(kGL_BACK_COLOR_BUFFER);
int prevDrawBuffer = theVisualGraphics->getCurrentColorBufferForPixelDrawingOperations();
theVisualGraphics->setColorBufferForPixelDrawingOperations(kGL_BACK_COLOR_BUFFER);
uint32* prevPixels = NULL;
char errStr[512];
uint8 numberOfBytesPerChannel = 0;
uint8 numberOfChannels = 0; // channel == color resp. alpha channel
uint8 numberOfBytesPerPixel = 0;
uint32 numberOfBytesPerRow = 0;
if ((pixelFormat == kGL_RGBA) || (pixelFormat == kGL_BGRA)) {
numberOfChannels = 4;
} else {
sprintf(errStr, "unknown format %d in file: %s (line: %d) [%s])", pixelFormat, __FILE__, __LINE__, __FUNCTION__);
writeLog(errStr);
return;
}
if ((dataType == kGL_UNSIGNED_INT_8_8_8_8_REV) || (dataType == kGL_UNSIGNED_INT_8_8_8_8) || (dataType == kGL_UNSIGNED_BYTE)) {
numberOfBytesPerChannel = 1; // // 1 byte (== 8 bits) per color/channel
} else {
sprintf(errStr, "unknown type %d in file: %s (line: %d) [%s])", dataType, __FILE__, __LINE__, __FUNCTION__);
writeLog(errStr);
return;
}
numberOfBytesPerPixel = numberOfBytesPerChannel * numberOfChannels;
numberOfBytesPerRow = numberOfBytesPerPixel * this->textureRect.width;
// read previous pixels
if ((pixelFormat == kGL_RGBA) || (pixelFormat == kGL_BGRA)) {
prevPixels = (uint32*)calloc((numberOfBytesPerRow / numberOfBytesPerPixel) * this->textureRect.height, numberOfBytesPerPixel);
}
VisualCamera aCamera;
aCamera.setOrthographicProjection();
theVisualGraphics->readPixels(aCamera.getMaxLeftCoord(), aCamera.getMaxBottomCoord(), this->textureRect.width, this->textureRect.height, &prevPixels, pixelFormat, dataType, aCamera);
PixelColor* pixels = NULL;
pixels = this->createARGBImagePixels();
if (pixels == NULL) {
sprintf(errStr, "pixels == NULL in file: %s (line: %d) [%s])", __FILE__, __LINE__, __FUNCTION__);
writeLog(errStr);
return;
}
theVisualGraphics->drawPixels(&pixels, aCamera.getMaxLeftCoord(), aCamera.getMaxBottomCoord(), this->imageRect.width, this->imageRect.height, pixelFormat, dataType, &aConvolutionFilter);
free(pixels);
pixels = NULL;
BottomLeftPositionedPixelRect clipRect;
clipRect.bottomLeftPixel.x = 0;
clipRect.bottomLeftPixel.y = 0;
clipRect.pixelRect.width = this->textureRect.width;
clipRect.pixelRect.height = this->textureRect.height;
theVisualGraphics->enableTexturing(this->useRectExtension);
theVisualGraphics->copyFramebufferToTexture(this->textureName, this->useRectExtension, clipRect, pixelFormat, dataType);
theVisualGraphics->disableTexturing(this->useRectExtension);
// restore previous pixels
theVisualGraphics->drawPixels(&prevPixels, aCamera.getMaxLeftCoord(), aCamera.getMaxBottomCoord(), this->textureRect.width, this->textureRect.height, pixelFormat, dataType);
free(prevPixels);
theVisualGraphics->setColorBufferForPixelDrawingOperations(prevDrawBuffer);
theVisualGraphics->setColorBufferForPixelReadingOperations(prevReadBuffer);
} else {
PixelColor* pixels = this->createARGBImagePixels();
PixelColor* filteredPixels = NULL;
aConvolutionFilter.applyToPixelData(pixels, this->imageRect.width, this->imageRect.height, pixelFormat, dataType, &filteredPixels);
free(pixels);
pixels = NULL;
bool success = false;
const PixelColor* constFilteredPixels = const_cast<const PixelColor*>(filteredPixels);
success = theVisualGraphics->copyARGBBitmapDataToTexture(this->textureName, this->imageRect.width, this->imageRect.height, this->useRectExtension, &constFilteredPixels);
if (filteredPixels != NULL) {
free(filteredPixels);
}
}
}
void VisualTextureContainer::resample(const PixelRect& pixelRect) {
PixelColor* pixels = this->createARGBImagePixels();
PixelColor* pixelsOut = (PixelColor*)malloc(pixelRect.width * pixelRect.height * sizeof(PixelColor));
VisualGraphics* theVisualGraphics = VisualGraphics::getInstance();
uint16 aPixelFormat = kGL_RGBA;
uint16 dataTypeIn = kGL_UNSIGNED_BYTE;
uint16 dataTypeOut = dataTypeIn;
theVisualGraphics->resample(aPixelFormat, this->imageRect.width, this->imageRect.height, dataTypeIn, pixels, pixelRect.width, pixelRect.height, dataTypeOut, &pixelsOut);
free(pixels);
this->initWithARGBPixelData(pixelsOut, pixelRect.width, pixelRect.height);
free(pixelsOut);
}