mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Refactoring of image storage: new classes ImageType, ImagePixelData, SoftwareImageType, NativeImageType, OpenGLImageType.
This commit is contained in:
parent
c555cbb9cb
commit
0b1cdf6ab1
21 changed files with 501 additions and 446 deletions
|
|
@ -244,7 +244,7 @@ private:
|
|||
if (w != h || (w != 16 && w != 32 && w != 48 && w != 64))
|
||||
{
|
||||
const int newSize = w >= 128 ? 128 : (w >= 64 ? 64 : (w >= 32 ? 32 : 16));
|
||||
Image newIm (Image::ARGB, newSize, newSize, true, Image::SoftwareImage);
|
||||
Image newIm (Image::ARGB, newSize, newSize, true, SoftwareImageType());
|
||||
Graphics g (newIm);
|
||||
g.drawImageWithin (image, 0, 0, newSize, newSize,
|
||||
RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize, false);
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ Image ProjectExporter::getBestIconForSize (int size, bool returnNullIfNothingBig
|
|||
if (returnNullIfNothingBigEnough && im.getWidth() < size && im.getHeight() < size)
|
||||
return Image::null;
|
||||
|
||||
Image newIm (Image::ARGB, size, size, true, Image::SoftwareImage);
|
||||
Image newIm (Image::ARGB, size, size, true, SoftwareImageType());
|
||||
Graphics g (newIm);
|
||||
g.drawImageWithin (im, 0, 0, size, size,
|
||||
RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize, false);
|
||||
|
|
|
|||
|
|
@ -89,7 +89,8 @@ public:
|
|||
This takes into account the opacity of the pixel being overlaid, and blends
|
||||
it accordingly.
|
||||
*/
|
||||
forcedinline void blend (const PixelARGB& src) noexcept
|
||||
template <class Pixel>
|
||||
forcedinline void blend (const Pixel& src) noexcept
|
||||
{
|
||||
uint32 sargb = src.getARGB();
|
||||
const uint32 alpha = 0x100 - (sargb >> 24);
|
||||
|
|
@ -100,14 +101,6 @@ public:
|
|||
argb = sargb;
|
||||
}
|
||||
|
||||
/** Blends another pixel onto this one.
|
||||
|
||||
This takes into account the opacity of the pixel being overlaid, and blends
|
||||
it accordingly.
|
||||
*/
|
||||
forcedinline void blend (const PixelAlpha& src) noexcept;
|
||||
|
||||
|
||||
/** Blends another pixel onto this one.
|
||||
|
||||
This takes into account the opacity of the pixel being overlaid, and blends
|
||||
|
|
@ -183,7 +176,7 @@ public:
|
|||
|
||||
forcedinline void multiplyAlpha (const float multiplier) noexcept
|
||||
{
|
||||
multiplyAlpha ((int) (multiplier * 256.0f));
|
||||
multiplyAlpha ((int) (multiplier * 255.0f));
|
||||
}
|
||||
|
||||
/** Sets the pixel's colour from individual components. */
|
||||
|
|
@ -257,21 +250,21 @@ public:
|
|||
|
||||
//==============================================================================
|
||||
/** The indexes of the different components in the byte layout of this type of colour. */
|
||||
#if JUCE_BIG_ENDIAN
|
||||
#if JUCE_BIG_ENDIAN
|
||||
enum { indexA = 0, indexR = 1, indexG = 2, indexB = 3 };
|
||||
#else
|
||||
#else
|
||||
enum { indexA = 3, indexR = 2, indexG = 1, indexB = 0 };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct Components
|
||||
{
|
||||
#if JUCE_BIG_ENDIAN
|
||||
#if JUCE_BIG_ENDIAN
|
||||
uint8 a : 8, r : 8, g : 8, b : 8;
|
||||
#else
|
||||
#else
|
||||
uint8 b, g, r, a;
|
||||
#endif
|
||||
#endif
|
||||
} PACKED;
|
||||
|
||||
union
|
||||
|
|
@ -328,7 +321,8 @@ public:
|
|||
This takes into account the opacity of the pixel being overlaid, and blends
|
||||
it accordingly.
|
||||
*/
|
||||
forcedinline void blend (const PixelARGB& src) noexcept
|
||||
template <class Pixel>
|
||||
forcedinline void blend (const Pixel& src) noexcept
|
||||
{
|
||||
uint32 sargb = src.getARGB();
|
||||
const uint32 alpha = 0x100 - (sargb >> 24);
|
||||
|
|
@ -346,8 +340,6 @@ public:
|
|||
set (src);
|
||||
}
|
||||
|
||||
forcedinline void blend (const PixelAlpha& src) noexcept;
|
||||
|
||||
/** Blends another pixel onto this one, applying an extra multiplier to its opacity.
|
||||
|
||||
The opacity of the pixel being overlaid is scaled by the extraAlpha factor before
|
||||
|
|
@ -408,6 +400,9 @@ public:
|
|||
/** Multiplies the colour's alpha value with another one. */
|
||||
forcedinline void multiplyAlpha (int) noexcept {}
|
||||
|
||||
/** Multiplies the colour's alpha value with another one. */
|
||||
forcedinline void multiplyAlpha (float) noexcept {}
|
||||
|
||||
/** Sets the pixel's colour from individual components. */
|
||||
void setARGB (const uint8, const uint8 r_, const uint8 g_, const uint8 b_) noexcept
|
||||
{
|
||||
|
|
@ -429,19 +424,19 @@ public:
|
|||
|
||||
//==============================================================================
|
||||
/** The indexes of the different components in the byte layout of this type of colour. */
|
||||
#if JUCE_MAC
|
||||
#if JUCE_MAC
|
||||
enum { indexR = 0, indexG = 1, indexB = 2 };
|
||||
#else
|
||||
#else
|
||||
enum { indexR = 2, indexG = 1, indexB = 0 };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
#if JUCE_MAC
|
||||
#if JUCE_MAC
|
||||
uint8 r, g, b;
|
||||
#else
|
||||
#else
|
||||
uint8 b, g, r;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
#ifndef DOXYGEN
|
||||
|
|
@ -520,7 +515,7 @@ public:
|
|||
template <class Pixel>
|
||||
forcedinline void tween (const Pixel& src, const uint32 amount) noexcept
|
||||
{
|
||||
a += ((src,getAlpha() - a) * amount) >> 8;
|
||||
a += ((src.getAlpha() - a) * amount) >> 8;
|
||||
}
|
||||
|
||||
/** Copies another pixel colour over this one.
|
||||
|
|
@ -558,18 +553,12 @@ public:
|
|||
}
|
||||
|
||||
/** Premultiplies the pixel's RGB values by its alpha. */
|
||||
forcedinline void premultiply() noexcept
|
||||
{
|
||||
}
|
||||
forcedinline void premultiply() noexcept {}
|
||||
|
||||
/** Unpremultiplies the pixel's RGB values. */
|
||||
forcedinline void unpremultiply() noexcept
|
||||
{
|
||||
}
|
||||
forcedinline void unpremultiply() noexcept {}
|
||||
|
||||
forcedinline void desaturate() noexcept
|
||||
{
|
||||
}
|
||||
forcedinline void desaturate() noexcept {}
|
||||
|
||||
//==============================================================================
|
||||
/** The indexes of the different components in the byte layout of this type of colour. */
|
||||
|
|
@ -584,26 +573,8 @@ private:
|
|||
#endif
|
||||
;
|
||||
|
||||
forcedinline void PixelRGB::blend (const PixelAlpha& src) noexcept
|
||||
{
|
||||
blend (PixelARGB (src.getARGB()));
|
||||
}
|
||||
|
||||
|
||||
forcedinline void PixelARGB::blend (const PixelAlpha& src) noexcept
|
||||
{
|
||||
uint32 sargb = src.getARGB();
|
||||
const uint32 alpha = 0x100 - (sargb >> 24);
|
||||
|
||||
sargb += 0x00ff00ff & ((getRB() * alpha) >> 8);
|
||||
sargb += 0xff00ff00 & (getAG() * alpha);
|
||||
|
||||
argb = sargb;
|
||||
}
|
||||
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma pack (pop)
|
||||
#pragma pack (pop)
|
||||
#endif
|
||||
|
||||
#undef PACKED
|
||||
|
|
|
|||
|
|
@ -223,14 +223,13 @@ private:
|
|||
{
|
||||
fresh = false;
|
||||
|
||||
do
|
||||
for (;;)
|
||||
{
|
||||
firstcode = oldcode
|
||||
= getCode (codeSize, false);
|
||||
}
|
||||
while (firstcode == clearCode);
|
||||
firstcode = oldcode = getCode (codeSize, false);
|
||||
|
||||
return firstcode;
|
||||
if (firstcode != clearCode)
|
||||
return firstcode;
|
||||
}
|
||||
}
|
||||
|
||||
if (sp > stack)
|
||||
|
|
@ -256,8 +255,8 @@ private:
|
|||
return -2;
|
||||
|
||||
uint8 buf [260];
|
||||
|
||||
int n;
|
||||
|
||||
while ((n = readDataBlock (buf)) > 0)
|
||||
{}
|
||||
|
||||
|
|
@ -290,8 +289,7 @@ private:
|
|||
table[1][code] = firstcode;
|
||||
++maxCode;
|
||||
|
||||
if ((maxCode >= maxCodeSize)
|
||||
&& (maxCodeSize < maxGifCode))
|
||||
if (maxCode >= maxCodeSize && maxCodeSize < maxGifCode)
|
||||
{
|
||||
maxCodeSize <<= 1;
|
||||
++codeSize;
|
||||
|
|
@ -345,7 +343,6 @@ private:
|
|||
}
|
||||
|
||||
currentBit += codeSize_;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -389,9 +386,7 @@ private:
|
|||
|
||||
while (ypos >= destData.height)
|
||||
{
|
||||
++pass;
|
||||
|
||||
switch (pass)
|
||||
switch (++pass)
|
||||
{
|
||||
case 1: ypos = 4; yStep = 8; break;
|
||||
case 2: ypos = 2; yStep = 4; break;
|
||||
|
|
@ -436,12 +431,12 @@ bool GIFImageFormat::canUnderstand (InputStream& in)
|
|||
|
||||
Image GIFImageFormat::decodeImage (InputStream& in)
|
||||
{
|
||||
#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER
|
||||
#if (JUCE_MAC || JUCE_IOS) && USE_COREGRAPHICS_RENDERING && JUCE_USE_COREIMAGE_LOADER
|
||||
return juce_loadWithCoreImage (in);
|
||||
#else
|
||||
#else
|
||||
const ScopedPointer <GIFLoader> loader (new GIFLoader (in));
|
||||
return loader->image;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GIFImageFormat::writeImageToStream (const Image& /*sourceImage*/, OutputStream& /*destStream*/)
|
||||
|
|
|
|||
|
|
@ -26,32 +26,58 @@
|
|||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
//==============================================================================
|
||||
Image::SharedImage::SharedImage (const PixelFormat format_, const int width_, const int height_)
|
||||
: format (format_), width (width_), height (height_)
|
||||
ImagePixelData::ImagePixelData (const Image::PixelFormat format, const int w, const int h)
|
||||
: pixelFormat (format), width (w), height (h)
|
||||
{
|
||||
jassert (format_ == RGB || format_ == ARGB || format_ == SingleChannel);
|
||||
jassert (width > 0 && height > 0); // It's illegal to create a zero-sized image!
|
||||
jassert (format == Image::RGB || format == Image::ARGB || format == Image::SingleChannel);
|
||||
jassert (w > 0 && h > 0); // It's illegal to create a zero-sized image!
|
||||
}
|
||||
|
||||
Image::SharedImage::~SharedImage()
|
||||
ImagePixelData::~ImagePixelData()
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class SoftwareSharedImage : public Image::SharedImage
|
||||
ImageType::ImageType() {}
|
||||
ImageType::~ImageType() {}
|
||||
|
||||
Image ImageType::convert (const Image& source) const
|
||||
{
|
||||
if (source.isNull() || getTypeID() == (ScopedPointer<ImageType> (source.getPixelData()->createType())->getTypeID()))
|
||||
return source;
|
||||
|
||||
const Image::BitmapData src (source, Image::BitmapData::readOnly);
|
||||
|
||||
Image newImage (create (src.pixelFormat, src.width, src.height, false));
|
||||
Image::BitmapData dest (newImage, Image::BitmapData::writeOnly);
|
||||
|
||||
jassert (src.pixelStride == dest.pixelStride && src.pixelFormat == dest.pixelFormat);
|
||||
|
||||
for (int y = 0; y < dest.height; ++y)
|
||||
memcpy (dest.getLinePointer (y), src.getLinePointer (y), dest.lineStride);
|
||||
|
||||
return newImage;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
NativeImageType::NativeImageType() {}
|
||||
NativeImageType::~NativeImageType() {}
|
||||
|
||||
int NativeImageType::getTypeID() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class SoftwarePixelData : public ImagePixelData
|
||||
{
|
||||
public:
|
||||
SoftwareSharedImage (const Image::PixelFormat format_, const int width_, const int height_, const bool clearImage)
|
||||
: Image::SharedImage (format_, width_, height_),
|
||||
SoftwarePixelData (const Image::PixelFormat format_, const int w, const int h, const bool clearImage)
|
||||
: ImagePixelData (format_, w, h),
|
||||
pixelStride (format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1)),
|
||||
lineStride ((pixelStride * jmax (1, width_) + 3) & ~3)
|
||||
lineStride ((pixelStride * jmax (1, w) + 3) & ~3)
|
||||
{
|
||||
imageData.allocate ((size_t) (lineStride * jmax (1, height_)), clearImage);
|
||||
}
|
||||
|
||||
Image::ImageType getType() const
|
||||
{
|
||||
return Image::SoftwareImage;
|
||||
imageData.allocate ((size_t) (lineStride * jmax (1, h)), clearImage);
|
||||
}
|
||||
|
||||
LowLevelGraphicsContext* createLowLevelContext()
|
||||
|
|
@ -59,48 +85,53 @@ public:
|
|||
return new LowLevelGraphicsSoftwareRenderer (Image (this));
|
||||
}
|
||||
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/)
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode)
|
||||
{
|
||||
bitmap.data = imageData + x * pixelStride + y * lineStride;
|
||||
bitmap.pixelFormat = format;
|
||||
bitmap.pixelFormat = pixelFormat;
|
||||
bitmap.lineStride = lineStride;
|
||||
bitmap.pixelStride = pixelStride;
|
||||
}
|
||||
|
||||
Image::SharedImage* clone()
|
||||
ImagePixelData* clone()
|
||||
{
|
||||
SoftwareSharedImage* s = new SoftwareSharedImage (format, width, height, false);
|
||||
SoftwarePixelData* s = new SoftwarePixelData (pixelFormat, width, height, false);
|
||||
memcpy (s->imageData, imageData, (size_t) (lineStride * height));
|
||||
return s;
|
||||
}
|
||||
|
||||
ImageType* createType() const { return new SoftwareImageType(); }
|
||||
|
||||
private:
|
||||
HeapBlock<uint8> imageData;
|
||||
const int pixelStride, lineStride;
|
||||
|
||||
JUCE_LEAK_DETECTOR (SoftwareSharedImage);
|
||||
JUCE_LEAK_DETECTOR (SoftwarePixelData);
|
||||
};
|
||||
|
||||
Image::SharedImage* Image::SharedImage::createSoftwareImage (Image::PixelFormat format, int width, int height, bool clearImage)
|
||||
SoftwareImageType::SoftwareImageType() {}
|
||||
SoftwareImageType::~SoftwareImageType() {}
|
||||
|
||||
ImagePixelData* SoftwareImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const
|
||||
{
|
||||
return new SoftwareSharedImage (format, width, height, clearImage);
|
||||
return new SoftwarePixelData (format, width, height, clearImage);
|
||||
}
|
||||
|
||||
int SoftwareImageType::getTypeID() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class SubsectionSharedImage : public Image::SharedImage
|
||||
class SubsectionPixelData : public ImagePixelData
|
||||
{
|
||||
public:
|
||||
SubsectionSharedImage (Image::SharedImage* const image_, const Rectangle<int>& area_)
|
||||
: Image::SharedImage (image_->getPixelFormat(), area_.getWidth(), area_.getHeight()),
|
||||
SubsectionPixelData (ImagePixelData* const image_, const Rectangle<int>& area_)
|
||||
: ImagePixelData (image_->pixelFormat, area_.getWidth(), area_.getHeight()),
|
||||
image (image_), area (area_)
|
||||
{
|
||||
}
|
||||
|
||||
Image::ImageType getType() const
|
||||
{
|
||||
return Image::SoftwareImage;
|
||||
}
|
||||
|
||||
LowLevelGraphicsContext* createLowLevelContext()
|
||||
{
|
||||
LowLevelGraphicsContext* g = image->createLowLevelContext();
|
||||
|
|
@ -114,25 +145,29 @@ public:
|
|||
image->initialiseBitmapData (bitmap, x + area.getX(), y + area.getY(), mode);
|
||||
}
|
||||
|
||||
Image::SharedImage* clone()
|
||||
ImagePixelData* clone()
|
||||
{
|
||||
Image newImage (format, area.getWidth(), area.getHeight(),
|
||||
format != Image::RGB, image->getType());
|
||||
jassert (getReferenceCount() > 0); // (This method can't be used on an unowned pointer, as it will end up self-deleting)
|
||||
const ScopedPointer<ImageType> type (image->createType());
|
||||
|
||||
Image newImage (type->create (pixelFormat, area.getWidth(), area.getHeight(), pixelFormat != Image::RGB));
|
||||
|
||||
{
|
||||
Graphics g (newImage);
|
||||
g.drawImageAt (Image (this), 0, 0);
|
||||
g.drawImageAt (Image (this), -area.getX(), -area.getY());
|
||||
}
|
||||
|
||||
newImage.getSharedImage()->incReferenceCount();
|
||||
return newImage.getSharedImage();
|
||||
newImage.getPixelData()->incReferenceCount();
|
||||
return newImage.getPixelData();
|
||||
}
|
||||
|
||||
ImageType* createType() const { return image->createType(); }
|
||||
|
||||
private:
|
||||
const ReferenceCountedObjectPtr<Image::SharedImage> image;
|
||||
const ReferenceCountedObjectPtr<ImagePixelData> image;
|
||||
const Rectangle<int> area;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SubsectionSharedImage);
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SubsectionPixelData);
|
||||
};
|
||||
|
||||
Image Image::getClippedImage (const Rectangle<int>& area) const
|
||||
|
|
@ -144,7 +179,7 @@ Image Image::getClippedImage (const Rectangle<int>& area) const
|
|||
if (validArea.isEmpty())
|
||||
return Image::null;
|
||||
|
||||
return Image (new SubsectionSharedImage (image, validArea));
|
||||
return Image (new SubsectionPixelData (image, validArea));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -153,21 +188,23 @@ Image::Image()
|
|||
{
|
||||
}
|
||||
|
||||
Image::Image (SharedImage* const instance)
|
||||
Image::Image (ImagePixelData* const instance)
|
||||
: image (instance)
|
||||
{
|
||||
}
|
||||
|
||||
Image::Image (const PixelFormat format,
|
||||
const int width, const int height,
|
||||
const bool clearImage, const ImageType type)
|
||||
: image (type == Image::NativeImage ? SharedImage::createNativeImage (format, width, height, clearImage)
|
||||
: new SoftwareSharedImage (format, width, height, clearImage))
|
||||
Image::Image (const PixelFormat format, int width, int height, bool clearImage)
|
||||
: image (NativeImageType().create (format, width, height, clearImage))
|
||||
{
|
||||
}
|
||||
|
||||
Image::Image (const PixelFormat format, int width, int height, bool clearImage, const ImageType& type)
|
||||
: image (type.create (format, width, height, clearImage))
|
||||
{
|
||||
}
|
||||
|
||||
Image::Image (const Image& other)
|
||||
: image (other.image)
|
||||
: image (other.image)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -179,13 +216,13 @@ Image& Image::operator= (const Image& other)
|
|||
|
||||
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
Image::Image (Image&& other) noexcept
|
||||
: image (static_cast <ReferenceCountedObjectPtr<SharedImage>&&> (other.image))
|
||||
: image (static_cast <ReferenceCountedObjectPtr<ImagePixelData>&&> (other.image))
|
||||
{
|
||||
}
|
||||
|
||||
Image& Image::operator= (Image&& other) noexcept
|
||||
{
|
||||
image = static_cast <ReferenceCountedObjectPtr<SharedImage>&&> (other.image);
|
||||
image = static_cast <ReferenceCountedObjectPtr<ImagePixelData>&&> (other.image);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -196,6 +233,16 @@ Image::~Image()
|
|||
|
||||
const Image Image::null;
|
||||
|
||||
int Image::getReferenceCount() const noexcept { return image == nullptr ? 0 : image->getReferenceCount(); }
|
||||
int Image::getWidth() const noexcept { return image == nullptr ? 0 : image->width; }
|
||||
int Image::getHeight() const noexcept { return image == nullptr ? 0 : image->height; }
|
||||
Rectangle<int> Image::getBounds() const noexcept { return image == nullptr ? Rectangle<int>() : Rectangle<int> (image->width, image->height); }
|
||||
Image::PixelFormat Image::getFormat() const noexcept { return image == nullptr ? UnknownFormat : image->pixelFormat; }
|
||||
bool Image::isARGB() const noexcept { return getFormat() == ARGB; }
|
||||
bool Image::isRGB() const noexcept { return getFormat() == RGB; }
|
||||
bool Image::isSingleChannel() const noexcept { return getFormat() == SingleChannel; }
|
||||
bool Image::hasAlphaChannel() const noexcept { return getFormat() != RGB; }
|
||||
|
||||
LowLevelGraphicsContext* Image::createLowLevelContext() const
|
||||
{
|
||||
return image == nullptr ? nullptr : image->createLowLevelContext();
|
||||
|
|
@ -212,7 +259,8 @@ Image Image::rescaled (const int newWidth, const int newHeight, const Graphics::
|
|||
if (image == nullptr || (image->width == newWidth && image->height == newHeight))
|
||||
return *this;
|
||||
|
||||
Image newImage (image->format, newWidth, newHeight, hasAlphaChannel(), image->getType());
|
||||
const ScopedPointer<ImageType> type (image->createType());
|
||||
Image newImage (type->create (image->pixelFormat, newWidth, newHeight, hasAlphaChannel()));
|
||||
|
||||
Graphics g (newImage);
|
||||
g.setImageResamplingQuality (quality);
|
||||
|
|
@ -223,11 +271,13 @@ Image Image::rescaled (const int newWidth, const int newHeight, const Graphics::
|
|||
|
||||
Image Image::convertedToFormat (PixelFormat newFormat) const
|
||||
{
|
||||
if (image == nullptr || newFormat == image->format)
|
||||
if (image == nullptr || newFormat == image->pixelFormat)
|
||||
return *this;
|
||||
|
||||
const int w = image->width, h = image->height;
|
||||
Image newImage (newFormat, w, h, false, image->getType());
|
||||
|
||||
const ScopedPointer<ImageType> type (image->createType());
|
||||
Image newImage (type->create (image->pixelFormat, w, h, false));
|
||||
|
||||
if (newFormat == SingleChannel)
|
||||
{
|
||||
|
|
@ -250,7 +300,7 @@ Image Image::convertedToFormat (PixelFormat newFormat) const
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (image->format == SingleChannel && newFormat == Image::ARGB)
|
||||
else if (image->pixelFormat == SingleChannel && newFormat == Image::ARGB)
|
||||
{
|
||||
const BitmapData destData (newImage, 0, 0, w, h, BitmapData::writeOnly);
|
||||
const BitmapData srcData (*this, 0, 0, w, h);
|
||||
|
|
@ -347,9 +397,9 @@ void Image::BitmapData::setPixelColour (const int x, const int y, const Colour&
|
|||
|
||||
switch (pixelFormat)
|
||||
{
|
||||
case Image::ARGB: ((PixelARGB*) pixel)->set (col); break;
|
||||
case Image::RGB: ((PixelRGB*) pixel)->set (col); break;
|
||||
case Image::SingleChannel: *pixel = col.getAlpha(); break;
|
||||
case Image::ARGB: ((PixelARGB*) pixel)->set (col); break;
|
||||
case Image::RGB: ((PixelRGB*) pixel)->set (col); break;
|
||||
case Image::SingleChannel: ((PixelAlpha*) pixel)->set (col); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
|
|
@ -357,51 +407,13 @@ void Image::BitmapData::setPixelColour (const int x, const int y, const Colour&
|
|||
//==============================================================================
|
||||
void Image::clear (const Rectangle<int>& area, const Colour& colourToClearTo)
|
||||
{
|
||||
const Rectangle<int> clipped (area.getIntersection (getBounds()));
|
||||
|
||||
if (! clipped.isEmpty())
|
||||
{
|
||||
const PixelARGB col (colourToClearTo.getPixelARGB());
|
||||
|
||||
const BitmapData destData (*this, clipped.getX(), clipped.getY(), clipped.getWidth(), clipped.getHeight(), BitmapData::writeOnly);
|
||||
uint8* dest = destData.data;
|
||||
int dh = clipped.getHeight();
|
||||
|
||||
while (--dh >= 0)
|
||||
{
|
||||
uint8* line = dest;
|
||||
dest += destData.lineStride;
|
||||
|
||||
if (isARGB())
|
||||
{
|
||||
for (int x = clipped.getWidth(); --x >= 0;)
|
||||
{
|
||||
((PixelARGB*) line)->set (col);
|
||||
line += destData.pixelStride;
|
||||
}
|
||||
}
|
||||
else if (isRGB())
|
||||
{
|
||||
for (int x = clipped.getWidth(); --x >= 0;)
|
||||
{
|
||||
((PixelRGB*) line)->set (col);
|
||||
line += destData.pixelStride;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int x = clipped.getWidth(); --x >= 0;)
|
||||
{
|
||||
*line = col.getAlpha();
|
||||
line += destData.pixelStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const ScopedPointer<LowLevelGraphicsContext> g (image->createLowLevelContext());
|
||||
g->setFill (colourToClearTo);
|
||||
g->fillRect (area, true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const Colour Image::getPixelAt (const int x, const int y) const
|
||||
Colour Image::getPixelAt (const int x, const int y) const
|
||||
{
|
||||
if (isPositiveAndBelow (x, getWidth()) && isPositiveAndBelow (y, getHeight()))
|
||||
{
|
||||
|
|
@ -435,77 +447,75 @@ void Image::multiplyAlphaAt (const int x, const int y, const float multiplier)
|
|||
}
|
||||
}
|
||||
|
||||
void Image::multiplyAllAlphas (const float amountToMultiplyBy)
|
||||
template <class PixelType>
|
||||
struct PixelIterator
|
||||
{
|
||||
if (hasAlphaChannel())
|
||||
template <class PixelOperation>
|
||||
static void iterate (const Image::BitmapData& data, const PixelOperation& pixelOp)
|
||||
{
|
||||
const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite);
|
||||
|
||||
if (isARGB())
|
||||
for (int y = 0; y < data.height; ++y)
|
||||
{
|
||||
for (int y = 0; y < destData.height; ++y)
|
||||
{
|
||||
uint8* p = destData.getLinePointer (y);
|
||||
uint8* p = data.getLinePointer (y);
|
||||
|
||||
for (int x = 0; x < destData.width; ++x)
|
||||
{
|
||||
((PixelARGB*) p)->multiplyAlpha (amountToMultiplyBy);
|
||||
p += destData.pixelStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < destData.height; ++y)
|
||||
for (int x = 0; x < data.width; ++x)
|
||||
{
|
||||
uint8* p = destData.getLinePointer (y);
|
||||
|
||||
for (int x = 0; x < destData.width; ++x)
|
||||
{
|
||||
*p = (uint8) (*p * amountToMultiplyBy);
|
||||
p += destData.pixelStride;
|
||||
}
|
||||
pixelOp (*(PixelType*) p);
|
||||
p += data.pixelStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
};
|
||||
|
||||
template <class PixelOperation>
|
||||
static void performPixelOp (const Image::BitmapData& data, const PixelOperation& pixelOp)
|
||||
{
|
||||
switch (data.pixelFormat)
|
||||
{
|
||||
jassertfalse; // can't do this without an alpha-channel!
|
||||
case Image::ARGB: PixelIterator<PixelARGB> ::iterate (data, pixelOp); break;
|
||||
case Image::RGB: PixelIterator<PixelRGB> ::iterate (data, pixelOp); break;
|
||||
case Image::SingleChannel: PixelIterator<PixelAlpha>::iterate (data, pixelOp); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
|
||||
struct AlphaMultiplyOp
|
||||
{
|
||||
AlphaMultiplyOp (float alpha_) noexcept : alpha (alpha_) {}
|
||||
|
||||
const float alpha;
|
||||
|
||||
template <class PixelType>
|
||||
void operator() (PixelType& pixel) const
|
||||
{
|
||||
pixel.multiplyAlpha (alpha);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (AlphaMultiplyOp);
|
||||
};
|
||||
|
||||
void Image::multiplyAllAlphas (const float amountToMultiplyBy)
|
||||
{
|
||||
jassert (hasAlphaChannel());
|
||||
|
||||
const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite);
|
||||
performPixelOp (destData, AlphaMultiplyOp (amountToMultiplyBy));
|
||||
}
|
||||
|
||||
struct DesaturateOp
|
||||
{
|
||||
template <class PixelType>
|
||||
void operator() (PixelType& pixel) const
|
||||
{
|
||||
pixel.desaturate();
|
||||
}
|
||||
};
|
||||
|
||||
void Image::desaturate()
|
||||
{
|
||||
if (isARGB() || isRGB())
|
||||
{
|
||||
const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite);
|
||||
|
||||
if (isARGB())
|
||||
{
|
||||
for (int y = 0; y < destData.height; ++y)
|
||||
{
|
||||
uint8* p = destData.getLinePointer (y);
|
||||
|
||||
for (int x = 0; x < destData.width; ++x)
|
||||
{
|
||||
((PixelARGB*) p)->desaturate();
|
||||
p += destData.pixelStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < destData.height; ++y)
|
||||
{
|
||||
uint8* p = destData.getLinePointer (y);
|
||||
|
||||
for (int x = 0; x < destData.width; ++x)
|
||||
{
|
||||
((PixelRGB*) p)->desaturate();
|
||||
p += destData.pixelStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
performPixelOp (destData, DesaturateOp());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -594,7 +604,7 @@ void Image::moveImageSection (int dx, int dy,
|
|||
const int minX = jmin (dx, sx);
|
||||
const int minY = jmin (dy, sy);
|
||||
|
||||
w = jmin (w, getWidth() - jmax (sx, dx));
|
||||
w = jmin (w, getWidth() - jmax (sx, dx));
|
||||
h = jmin (h, getHeight() - jmax (sy, dy));
|
||||
|
||||
if (w > 0 && h > 0)
|
||||
|
|
@ -629,5 +639,4 @@ void Image::moveImageSection (int dx, int dy,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@
|
|||
#include "../colour/juce_Colour.h"
|
||||
#include "../contexts/juce_GraphicsContext.h"
|
||||
|
||||
class ImageType;
|
||||
class ImagePixelData;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
|
|
@ -66,18 +69,26 @@ public:
|
|||
SingleChannel /**<< each pixel is a 1-byte alpha channel value. */
|
||||
};
|
||||
|
||||
/**
|
||||
*/
|
||||
enum ImageType
|
||||
{
|
||||
SoftwareImage = 0,
|
||||
NativeImage
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a null image. */
|
||||
Image();
|
||||
|
||||
/** Creates an image with a specified size and format.
|
||||
|
||||
The image's internal type will be of the NativeImageType class - to specify a
|
||||
different type, use the other constructor, which takes an ImageType to use.
|
||||
|
||||
@param format the number of colour channels in the image
|
||||
@param imageWidth the desired width of the image, in pixels - this value must be
|
||||
greater than zero (otherwise a width of 1 will be used)
|
||||
@param imageHeight the desired width of the image, in pixels - this value must be
|
||||
greater than zero (otherwise a height of 1 will be used)
|
||||
@param clearImage if true, the image will initially be cleared to black (if it's RGB)
|
||||
or transparent black (if it's ARGB). If false, the image may contain
|
||||
junk initially, so you need to make sure you overwrite it thoroughly.
|
||||
*/
|
||||
Image (PixelFormat format, int imageWidth, int imageHeight, bool clearImage);
|
||||
|
||||
/** Creates an image with a specified size and format.
|
||||
|
||||
@param format the number of colour channels in the image
|
||||
|
|
@ -88,14 +99,10 @@ public:
|
|||
@param clearImage if true, the image will initially be cleared to black (if it's RGB)
|
||||
or transparent black (if it's ARGB). If false, the image may contain
|
||||
junk initially, so you need to make sure you overwrite it thoroughly.
|
||||
@param type the type of image - this lets you specify whether you want a purely
|
||||
memory-based image, or one that may be managed by the OS if possible.
|
||||
@param type the type of image - this lets you specify the internal format that will
|
||||
be used to allocate and manage the image data.
|
||||
*/
|
||||
Image (PixelFormat format,
|
||||
int imageWidth,
|
||||
int imageHeight,
|
||||
bool clearImage,
|
||||
ImageType type = NativeImage);
|
||||
Image (PixelFormat format, int imageWidth, int imageHeight, bool clearImage, const ImageType& type);
|
||||
|
||||
/** Creates a shared reference to another image.
|
||||
|
||||
|
|
@ -150,30 +157,30 @@ public:
|
|||
|
||||
//==============================================================================
|
||||
/** Returns the image's width (in pixels). */
|
||||
int getWidth() const noexcept { return image == nullptr ? 0 : image->width; }
|
||||
int getWidth() const noexcept;
|
||||
|
||||
/** Returns the image's height (in pixels). */
|
||||
int getHeight() const noexcept { return image == nullptr ? 0 : image->height; }
|
||||
int getHeight() const noexcept;
|
||||
|
||||
/** Returns a rectangle with the same size as this image.
|
||||
The rectangle's origin is always (0, 0).
|
||||
*/
|
||||
Rectangle<int> getBounds() const noexcept { return image == nullptr ? Rectangle<int>() : Rectangle<int> (image->width, image->height); }
|
||||
Rectangle<int> getBounds() const noexcept;
|
||||
|
||||
/** Returns the image's pixel format. */
|
||||
PixelFormat getFormat() const noexcept { return image == nullptr ? UnknownFormat : image->format; }
|
||||
PixelFormat getFormat() const noexcept;
|
||||
|
||||
/** True if the image's format is ARGB. */
|
||||
bool isARGB() const noexcept { return getFormat() == ARGB; }
|
||||
bool isARGB() const noexcept;
|
||||
|
||||
/** True if the image's format is RGB. */
|
||||
bool isRGB() const noexcept { return getFormat() == RGB; }
|
||||
bool isRGB() const noexcept;
|
||||
|
||||
/** True if the image's format is a single-channel alpha map. */
|
||||
bool isSingleChannel() const noexcept { return getFormat() == SingleChannel; }
|
||||
bool isSingleChannel() const noexcept;
|
||||
|
||||
/** True if the image contains an alpha-channel. */
|
||||
bool hasAlphaChannel() const noexcept { return getFormat() != RGB; }
|
||||
bool hasAlphaChannel() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Clears a section of the image with a given colour.
|
||||
|
|
@ -236,7 +243,7 @@ public:
|
|||
|
||||
@see setPixelAt, Image::BitmapData::getPixelColour
|
||||
*/
|
||||
const Colour getPixelAt (int x, int y) const;
|
||||
Colour getPixelAt (int x, int y) const;
|
||||
|
||||
/** Sets the colour of one of the image's pixels.
|
||||
|
||||
|
|
@ -387,55 +394,118 @@ public:
|
|||
|
||||
@see duplicateIfShared
|
||||
*/
|
||||
int getReferenceCount() const noexcept { return image == nullptr ? 0 : image->getReferenceCount(); }
|
||||
int getReferenceCount() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** This is a base class for task-specific types of image.
|
||||
|
||||
Don't use this class directly! It's used internally by the Image class.
|
||||
*/
|
||||
class SharedImage : public ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
SharedImage (PixelFormat format, int width, int height);
|
||||
~SharedImage();
|
||||
|
||||
virtual LowLevelGraphicsContext* createLowLevelContext() = 0;
|
||||
virtual SharedImage* clone() = 0;
|
||||
virtual ImageType getType() const = 0;
|
||||
virtual void initialiseBitmapData (BitmapData& bitmapData, int x, int y, BitmapData::ReadWriteMode mode) = 0;
|
||||
|
||||
static SharedImage* createNativeImage (PixelFormat format, int width, int height, bool clearImage);
|
||||
static SharedImage* createSoftwareImage (PixelFormat format, int width, int height, bool clearImage);
|
||||
|
||||
PixelFormat getPixelFormat() const noexcept { return format; }
|
||||
int getWidth() const noexcept { return width; }
|
||||
int getHeight() const noexcept { return height; }
|
||||
|
||||
protected:
|
||||
friend class Image;
|
||||
friend class BitmapData;
|
||||
const PixelFormat format;
|
||||
const int width, height;
|
||||
NamedValueSet userData;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedImage);
|
||||
};
|
||||
/** @internal */
|
||||
ImagePixelData* getPixelData() const noexcept { return image; }
|
||||
|
||||
/** @internal */
|
||||
SharedImage* getSharedImage() const noexcept { return image; }
|
||||
/** @internal */
|
||||
explicit Image (SharedImage* instance);
|
||||
explicit Image (ImagePixelData*);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
friend class SharedImage;
|
||||
friend class BitmapData;
|
||||
|
||||
ReferenceCountedObjectPtr<SharedImage> image;
|
||||
ReferenceCountedObjectPtr<ImagePixelData> image;
|
||||
|
||||
JUCE_LEAK_DETECTOR (Image);
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This is a base class for holding image data in implementation-specific ways.
|
||||
|
||||
You may never need to use this class directly - it's used internally
|
||||
by the Image class to store the actual image data. To access pixel data directly,
|
||||
you should use Image::BitmapData rather than this class.
|
||||
|
||||
ImagePixelData objects are created indirectly, by subclasses of ImageType.
|
||||
@see Image, ImageType
|
||||
*/
|
||||
class JUCE_API ImagePixelData : public ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
ImagePixelData (Image::PixelFormat, int width, int height);
|
||||
~ImagePixelData();
|
||||
|
||||
/** Creates a context that will draw into this image. */
|
||||
virtual LowLevelGraphicsContext* createLowLevelContext() = 0;
|
||||
/** Creates a copy of this image. */
|
||||
virtual ImagePixelData* clone() = 0;
|
||||
/** Creates an instance of the type of this image. */
|
||||
virtual ImageType* createType() const = 0;
|
||||
/** Initialises a BitmapData object. */
|
||||
virtual void initialiseBitmapData (Image::BitmapData&, int x, int y, Image::BitmapData::ReadWriteMode) = 0;
|
||||
|
||||
/** The pixel format of the image data. */
|
||||
const Image::PixelFormat pixelFormat;
|
||||
const int width, height;
|
||||
|
||||
/** User-defined settings that are attached to this image.
|
||||
@see Image::getProperties().
|
||||
*/
|
||||
NamedValueSet userData;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImagePixelData);
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This base class is for handlers that control a type of image manipulation format,
|
||||
e.g. an in-memory bitmap, an OpenGL image, CoreGraphics image, etc.
|
||||
|
||||
@see SoftwareImageType, NativeImageType, OpenGLImageType
|
||||
*/
|
||||
class JUCE_API ImageType
|
||||
{
|
||||
public:
|
||||
ImageType();
|
||||
virtual ~ImageType();
|
||||
|
||||
/** Creates a new image of this type, and the specified parameters. */
|
||||
virtual ImagePixelData* create (Image::PixelFormat format, int width, int height, bool shouldClearImage) const = 0;
|
||||
|
||||
/** Must return a unique number to identify this type. */
|
||||
virtual int getTypeID() const = 0;
|
||||
|
||||
/** Returns an image which is a copy of the source image, but using this type of storage mechanism.
|
||||
For example, to make sure that an image is stored in-memory, you could use:
|
||||
@code myImage = SoftwareImageType().convert (myImage); @endcode
|
||||
*/
|
||||
virtual Image convert (const Image& source) const;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An image storage type which holds the pixels in-memory as a simple block of values.
|
||||
@see ImageType, NativeImageType
|
||||
*/
|
||||
class JUCE_API SoftwareImageType : public ImageType
|
||||
{
|
||||
public:
|
||||
SoftwareImageType();
|
||||
~SoftwareImageType();
|
||||
|
||||
ImagePixelData* create (Image::PixelFormat, int width, int height, bool clearImage) const;
|
||||
int getTypeID() const;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An image storage type which holds the pixels using whatever is the default storage
|
||||
format on the current platform.
|
||||
@see ImageType, SoftwareImageType
|
||||
*/
|
||||
class JUCE_API NativeImageType : public ImageType
|
||||
{
|
||||
public:
|
||||
NativeImageType();
|
||||
~NativeImageType();
|
||||
|
||||
ImagePixelData* create (Image::PixelFormat, int width, int height, bool clearImage) const;
|
||||
int getTypeID() const;
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCE_IMAGE_JUCEHEADER__
|
||||
|
|
|
|||
|
|
@ -158,18 +158,17 @@ DECLARE_JNI_CLASS (RadialGradientClass, "android/graphics/RadialGradient");
|
|||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
class AndroidImage : public Image::SharedImage
|
||||
class AndroidImage : public ImagePixelData
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
AndroidImage (const int width_, const int height_, const bool clearImage)
|
||||
: Image::SharedImage (Image::ARGB, width_, height_),
|
||||
: ImagePixelData (Image::ARGB, width_, height_),
|
||||
bitmap (createBitmap (width_, height_, false))
|
||||
{
|
||||
}
|
||||
|
||||
AndroidImage (const int width_, const int height_, const GlobalRef& bitmap_)
|
||||
: Image::SharedImage (Image::ARGB, width_, height_),
|
||||
: ImagePixelData (Image::ARGB, width_, height_),
|
||||
bitmap (bitmap_)
|
||||
{
|
||||
}
|
||||
|
|
@ -180,7 +179,6 @@ public:
|
|||
bitmap.callVoidMethod (BitmapClass.recycle);
|
||||
}
|
||||
|
||||
Image::ImageType getType() const { return Image::NativeImage; }
|
||||
LowLevelGraphicsContext* createLowLevelContext();
|
||||
|
||||
void initialiseBitmapData (Image::BitmapData& bm, int x, int y, Image::BitmapData::ReadWriteMode mode)
|
||||
|
|
@ -191,7 +189,7 @@ public:
|
|||
bm.dataReleaser = new CopyHandler (*this, bm, x, y, mode);
|
||||
}
|
||||
|
||||
SharedImage* clone()
|
||||
ImagePixelData* clone()
|
||||
{
|
||||
JNIEnv* env = getEnv();
|
||||
jobject mode = env->GetStaticObjectField (BitmapConfig, BitmapConfig.ARGB_8888);
|
||||
|
|
@ -201,6 +199,8 @@ public:
|
|||
return new AndroidImage (width, height, newCopy);
|
||||
}
|
||||
|
||||
ImageType* createType() const { return new NativeImageType(); }
|
||||
|
||||
static jobject createBitmap (int width, int height, bool asSingleChannel)
|
||||
{
|
||||
JNIEnv* env = getEnv();
|
||||
|
|
@ -282,14 +282,14 @@ private:
|
|||
};
|
||||
#endif
|
||||
|
||||
Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage)
|
||||
ImagePixelData* NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const
|
||||
{
|
||||
#if USE_ANDROID_CANVAS
|
||||
if (format != Image::SingleChannel)
|
||||
if (pixelFormat != Image::SingleChannel)
|
||||
return new AndroidImage (width, height, clearImage);
|
||||
#endif
|
||||
|
||||
return createSoftwareImage (format, width, height, clearImage);
|
||||
return SoftwareImageType().create (format, width, height, clearImage);
|
||||
}
|
||||
|
||||
#if USE_ANDROID_CANVAS
|
||||
|
|
@ -452,7 +452,7 @@ public:
|
|||
|
||||
void drawImage (const Image& sourceImage, const AffineTransform& transform)
|
||||
{
|
||||
AndroidImage* androidImage = dynamic_cast <AndroidImage*> (sourceImage.getSharedImage());
|
||||
AndroidImage* androidImage = dynamic_cast <AndroidImage*> (sourceImage.getPixelData());
|
||||
|
||||
if (androidImage != 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,14 +27,13 @@
|
|||
#include "juce_mac_CoreGraphicsContext.h"
|
||||
|
||||
//==============================================================================
|
||||
class CoreGraphicsImage : public Image::SharedImage
|
||||
class CoreGraphicsImage : public ImagePixelData
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
CoreGraphicsImage (const Image::PixelFormat format_, const int width_, const int height_, const bool clearImage)
|
||||
: Image::SharedImage (format_, width_, height_)
|
||||
CoreGraphicsImage (const Image::PixelFormat format, const int width_, const int height_, const bool clearImage)
|
||||
: ImagePixelData (format, width_, height_)
|
||||
{
|
||||
pixelStride = format_ == Image::RGB ? 3 : ((format_ == Image::ARGB) ? 4 : 1);
|
||||
pixelStride = format == Image::RGB ? 3 : ((format == Image::ARGB) ? 4 : 1);
|
||||
lineStride = (pixelStride * jmax (1, width) + 3) & ~3;
|
||||
|
||||
imageData.allocate (lineStride * jmax (1, height), clearImage);
|
||||
|
|
@ -43,7 +42,7 @@ public:
|
|||
: CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
context = CGBitmapContextCreate (imageData, width, height, 8, lineStride,
|
||||
colourSpace, getCGImageFlags (format_));
|
||||
colourSpace, getCGImageFlags (format));
|
||||
|
||||
CGColorSpaceRelease (colourSpace);
|
||||
}
|
||||
|
|
@ -53,29 +52,30 @@ public:
|
|||
CGContextRelease (context);
|
||||
}
|
||||
|
||||
Image::ImageType getType() const { return Image::NativeImage; }
|
||||
LowLevelGraphicsContext* createLowLevelContext();
|
||||
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/)
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode)
|
||||
{
|
||||
bitmap.data = imageData + x * pixelStride + y * lineStride;
|
||||
bitmap.pixelFormat = format;
|
||||
bitmap.pixelFormat = pixelFormat;
|
||||
bitmap.lineStride = lineStride;
|
||||
bitmap.pixelStride = pixelStride;
|
||||
}
|
||||
|
||||
SharedImage* clone()
|
||||
ImagePixelData* clone()
|
||||
{
|
||||
CoreGraphicsImage* im = new CoreGraphicsImage (format, width, height, false);
|
||||
CoreGraphicsImage* im = new CoreGraphicsImage (pixelFormat, width, height, false);
|
||||
memcpy (im->imageData, imageData, lineStride * height);
|
||||
return im;
|
||||
}
|
||||
|
||||
ImageType* createType() const { return new NativeImageType(); }
|
||||
|
||||
//==============================================================================
|
||||
static CGImageRef createImage (const Image& juceImage, const bool forAlpha,
|
||||
CGColorSpaceRef colourSpace, const bool mustOutliveSource)
|
||||
{
|
||||
const CoreGraphicsImage* nativeImage = dynamic_cast <const CoreGraphicsImage*> (juceImage.getSharedImage());
|
||||
const CoreGraphicsImage* nativeImage = dynamic_cast <const CoreGraphicsImage*> (juceImage.getPixelData());
|
||||
|
||||
if (nativeImage != nullptr && (juceImage.getFormat() == Image::SingleChannel || ! forAlpha))
|
||||
{
|
||||
|
|
@ -125,9 +125,9 @@ private:
|
|||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsImage);
|
||||
};
|
||||
|
||||
Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage)
|
||||
ImagePixelData* NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const
|
||||
{
|
||||
return new CoreGraphicsImage (format == RGB ? ARGB : format, width, height, clearImage);
|
||||
return new CoreGraphicsImage (format == Image::RGB ? Image::ARGB : format, width, height, clearImage);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -818,11 +818,12 @@ Image juce_loadWithCoreImage (InputStream& input)
|
|||
&& alphaInfo != kCGImageAlphaNoneSkipLast
|
||||
&& alphaInfo != kCGImageAlphaNoneSkipFirst);
|
||||
|
||||
Image image (Image::ARGB, // (CoreImage doesn't work with 24-bit images)
|
||||
(int) CGImageGetWidth (loadedImage), (int) CGImageGetHeight (loadedImage),
|
||||
hasAlphaChan, Image::NativeImage);
|
||||
Image image (NativeImageType().create (Image::ARGB, // (CoreImage doesn't work with 24-bit images)
|
||||
(int) CGImageGetWidth (loadedImage),
|
||||
(int) CGImageGetHeight (loadedImage),
|
||||
hasAlphaChan));
|
||||
|
||||
CoreGraphicsImage* const cgImage = dynamic_cast<CoreGraphicsImage*> (image.getSharedImage());
|
||||
CoreGraphicsImage* const cgImage = dynamic_cast<CoreGraphicsImage*> (image.getPixelData());
|
||||
jassert (cgImage != nullptr); // if USE_COREGRAPHICS_RENDERING is set, the CoreGraphicsImage class should have been used.
|
||||
|
||||
CGContextDrawImage (cgImage->context, CGRectMake (0, 0, image.getWidth(), image.getHeight()), loadedImage);
|
||||
|
|
@ -863,7 +864,7 @@ CGImageRef juce_createCoreGraphicsImage (const Image& juceImage, const bool forA
|
|||
|
||||
CGContextRef juce_getImageContext (const Image& image)
|
||||
{
|
||||
CoreGraphicsImage* const cgi = dynamic_cast <CoreGraphicsImage*> (image.getSharedImage());
|
||||
CoreGraphicsImage* const cgi = dynamic_cast <CoreGraphicsImage*> (image.getPixelData());
|
||||
jassert (cgi != nullptr);
|
||||
return cgi != nullptr ? cgi->context : 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1789,7 +1789,7 @@ void Component::paintComponent (Graphics& g)
|
|||
if (bufferedImage.isNull())
|
||||
{
|
||||
bufferedImage = Image (flags.opaqueFlag ? Image::RGB : Image::ARGB,
|
||||
getWidth(), getHeight(), ! flags.opaqueFlag, Image::NativeImage);
|
||||
getWidth(), getHeight(), ! flags.opaqueFlag);
|
||||
|
||||
Graphics imG (bufferedImage);
|
||||
paint (imG);
|
||||
|
|
@ -1893,7 +1893,7 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel)
|
|||
if (effect != nullptr)
|
||||
{
|
||||
Image effectImage (flags.opaqueFlag ? Image::RGB : Image::ARGB,
|
||||
getWidth(), getHeight(), ! flags.opaqueFlag, Image::NativeImage);
|
||||
getWidth(), getHeight(), ! flags.opaqueFlag);
|
||||
{
|
||||
Graphics g2 (effectImage);
|
||||
paintComponentAndChildren (g2);
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ void DropShadower::updateShadows()
|
|||
|
||||
if (bigIm.isNull())
|
||||
{
|
||||
bigIm = Image (Image::ARGB, shadowEdge * 5, shadowEdge * 5, true, Image::NativeImage);
|
||||
bigIm = Image (Image::ARGB, shadowEdge * 5, shadowEdge * 5, true);
|
||||
|
||||
Graphics bigG (bigIm);
|
||||
bigG.setColour (Colours::black.withAlpha (alpha));
|
||||
|
|
@ -280,7 +280,7 @@ void DropShadower::updateShadows()
|
|||
void DropShadower::setShadowImage (const Image& src, const int num, const int w, const int h,
|
||||
const int sx, const int sy)
|
||||
{
|
||||
shadowImageSections[num] = Image (Image::ARGB, w, h, true, Image::NativeImage);
|
||||
shadowImageSections[num] = Image (Image::ARGB, w, h, true);
|
||||
|
||||
Graphics g (shadowImageSections[num]);
|
||||
g.drawImage (src, 0, 0, w, h, sx, sy, w, h);
|
||||
|
|
|
|||
|
|
@ -498,11 +498,11 @@ private:
|
|||
bool usingAndroidGraphics, fullScreen;
|
||||
int sizeAllocated;
|
||||
|
||||
class PreallocatedImage : public Image::SharedImage
|
||||
class PreallocatedImage : public ImagePixelData
|
||||
{
|
||||
public:
|
||||
PreallocatedImage (const int width_, const int height_, jint* data_, bool hasAlpha_)
|
||||
: Image::SharedImage (Image::ARGB, width_, height_), data (data_), hasAlpha (hasAlpha_)
|
||||
: ImagePixelData (Image::ARGB, width_, height_), data (data_), hasAlpha (hasAlpha_)
|
||||
{
|
||||
if (hasAlpha_)
|
||||
zeromem (data_, width * height * sizeof (jint));
|
||||
|
|
@ -522,7 +522,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
Image::ImageType getType() const { return Image::SoftwareImage; }
|
||||
ImageType* createType() const { return new SoftwareImageType(); }
|
||||
LowLevelGraphicsContext* createLowLevelContext() { return new LowLevelGraphicsSoftwareRenderer (Image (this)); }
|
||||
|
||||
void initialiseBitmapData (Image::BitmapData& bm, int x, int y, Image::BitmapData::ReadWriteMode mode)
|
||||
|
|
@ -533,7 +533,7 @@ private:
|
|||
bm.data = (uint8*) (data + x + y * width);
|
||||
}
|
||||
|
||||
SharedImage* clone()
|
||||
ImagePixelData* clone()
|
||||
{
|
||||
PreallocatedImage* s = new PreallocatedImage (width, height, 0, hasAlpha);
|
||||
s->allocatedData.malloc (sizeof (jint) * width * height);
|
||||
|
|
|
|||
|
|
@ -436,18 +436,18 @@ namespace Visuals
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
class XBitmapImage : public Image::SharedImage
|
||||
class XBitmapImage : public ImagePixelData
|
||||
{
|
||||
public:
|
||||
XBitmapImage (const Image::PixelFormat format_, const int w, const int h,
|
||||
XBitmapImage (const Image::PixelFormat format, const int w, const int h,
|
||||
const bool clearImage, const int imageDepth_, Visual* visual)
|
||||
: Image::SharedImage (format_, w, h),
|
||||
: ImagePixelData (format, w, h),
|
||||
imageDepth (imageDepth_),
|
||||
gc (None)
|
||||
{
|
||||
jassert (format_ == Image::RGB || format_ == Image::ARGB);
|
||||
jassert (format == Image::RGB || format == Image::ARGB);
|
||||
|
||||
pixelStride = (format_ == Image::RGB) ? 3 : 4;
|
||||
pixelStride = (format == Image::RGB) ? 3 : 4;
|
||||
lineStride = ((w * pixelStride + 3) & ~3);
|
||||
|
||||
ScopedXLock xlock;
|
||||
|
|
@ -499,7 +499,7 @@ public:
|
|||
if (! usingXShm)
|
||||
#endif
|
||||
{
|
||||
imageDataAllocated.allocate (lineStride * h, format_ == Image::ARGB && clearImage);
|
||||
imageDataAllocated.allocate (lineStride * h, format == Image::ARGB && clearImage);
|
||||
imageData = imageDataAllocated;
|
||||
|
||||
xImage = (XImage*) ::calloc (1, sizeof (XImage));
|
||||
|
|
@ -567,27 +567,27 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
Image::ImageType getType() const { return Image::NativeImage; }
|
||||
|
||||
LowLevelGraphicsContext* createLowLevelContext()
|
||||
{
|
||||
return new LowLevelGraphicsSoftwareRenderer (Image (this));
|
||||
}
|
||||
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/)
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode)
|
||||
{
|
||||
bitmap.data = imageData + x * pixelStride + y * lineStride;
|
||||
bitmap.pixelFormat = format;
|
||||
bitmap.pixelFormat = pixelFormat;
|
||||
bitmap.lineStride = lineStride;
|
||||
bitmap.pixelStride = pixelStride;
|
||||
}
|
||||
|
||||
SharedImage* clone()
|
||||
ImagePixelData* clone()
|
||||
{
|
||||
jassertfalse;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ImageType* createType() const { return new NativeImageType(); }
|
||||
|
||||
void blitToWindow (Window window, int dx, int dy, int dw, int dh, int sx, int sy)
|
||||
{
|
||||
ScopedXLock xlock;
|
||||
|
|
@ -1774,7 +1774,7 @@ private:
|
|||
#endif
|
||||
const Rectangle<int>& r = *i.getRectangle();
|
||||
|
||||
static_cast<XBitmapImage*> (image.getSharedImage())
|
||||
static_cast<XBitmapImage*> (image.getPixelData())
|
||||
->blitToWindow (peer->windowH,
|
||||
r.getX(), r.getY(), r.getWidth(), r.getHeight(),
|
||||
r.getX() - totalArea.getX(), r.getY() - totalArea.getY());
|
||||
|
|
@ -3008,9 +3008,9 @@ Image juce_createIconForFile (const File& file)
|
|||
return Image::null;
|
||||
}
|
||||
|
||||
Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage)
|
||||
ImagePixelData* NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const
|
||||
{
|
||||
return createSoftwareImage (format, width, height, clearImage);
|
||||
return SoftwareImageType().create (format, width, height, clearImage);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ Image juce_createIconForFile (const File& file)
|
|||
|
||||
NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())];
|
||||
|
||||
Image result (Image::ARGB, (int) [image size].width, (int) [image size].height, true, Image::NativeImage);
|
||||
Image result (Image::ARGB, (int) [image size].width, (int) [image size].height, true);
|
||||
|
||||
[NSGraphicsContext saveGraphicsState];
|
||||
[NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (result) flipped: false]];
|
||||
|
|
|
|||
|
|
@ -194,16 +194,16 @@ const int KeyPress::rewindKey = 0x30003;
|
|||
|
||||
|
||||
//==============================================================================
|
||||
class WindowsBitmapImage : public Image::SharedImage
|
||||
class WindowsBitmapImage : public ImagePixelData
|
||||
{
|
||||
public:
|
||||
WindowsBitmapImage (const Image::PixelFormat format_,
|
||||
WindowsBitmapImage (const Image::PixelFormat format,
|
||||
const int w, const int h, const bool clearImage)
|
||||
: Image::SharedImage (format_, w, h)
|
||||
: ImagePixelData (format, w, h)
|
||||
{
|
||||
jassert (format_ == Image::RGB || format_ == Image::ARGB);
|
||||
jassert (format == Image::RGB || format == Image::ARGB);
|
||||
|
||||
pixelStride = (format_ == Image::RGB) ? 3 : 4;
|
||||
pixelStride = (format == Image::RGB) ? 3 : 4;
|
||||
lineStride = -((w * pixelStride + 3) & ~3);
|
||||
|
||||
zerostruct (bitmapInfo);
|
||||
|
|
@ -214,7 +214,7 @@ public:
|
|||
bitmapInfo.bV4CSType = 1;
|
||||
bitmapInfo.bV4BitCount = (unsigned short) (pixelStride * 8);
|
||||
|
||||
if (format_ == Image::ARGB)
|
||||
if (format == Image::ARGB)
|
||||
{
|
||||
bitmapInfo.bV4AlphaMask = 0xff000000;
|
||||
bitmapInfo.bV4RedMask = 0xff0000;
|
||||
|
|
@ -238,7 +238,7 @@ public:
|
|||
|
||||
previousBitmap = SelectObject (hdc, hBitmap);
|
||||
|
||||
if (format_ == Image::ARGB && clearImage)
|
||||
if (format == Image::ARGB && clearImage)
|
||||
zeromem (bitmapData, (size_t) std::abs (h * lineStride));
|
||||
|
||||
imageData = bitmapData - (lineStride * (h - 1));
|
||||
|
|
@ -251,24 +251,24 @@ public:
|
|||
DeleteObject (hBitmap);
|
||||
}
|
||||
|
||||
Image::ImageType getType() const { return Image::NativeImage; }
|
||||
ImageType* createType() const { return new NativeImageType(); }
|
||||
|
||||
LowLevelGraphicsContext* createLowLevelContext()
|
||||
{
|
||||
return new LowLevelGraphicsSoftwareRenderer (Image (this));
|
||||
}
|
||||
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/)
|
||||
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode)
|
||||
{
|
||||
bitmap.data = imageData + x * pixelStride + y * lineStride;
|
||||
bitmap.pixelFormat = format;
|
||||
bitmap.pixelFormat = pixelFormat;
|
||||
bitmap.lineStride = lineStride;
|
||||
bitmap.pixelStride = pixelStride;
|
||||
}
|
||||
|
||||
Image::SharedImage* clone()
|
||||
ImagePixelData* clone()
|
||||
{
|
||||
WindowsBitmapImage* im = new WindowsBitmapImage (format, width, height, false);
|
||||
WindowsBitmapImage* im = new WindowsBitmapImage (pixelFormat, width, height, false);
|
||||
|
||||
for (int i = 0; i < height; ++i)
|
||||
memcpy (im->imageData + i * lineStride, imageData + i * lineStride, (size_t) lineStride);
|
||||
|
|
@ -1367,7 +1367,7 @@ private:
|
|||
}
|
||||
|
||||
if (! dontRepaint)
|
||||
static_cast <WindowsBitmapImage*> (offscreenImage.getSharedImage())
|
||||
static_cast <WindowsBitmapImage*> (offscreenImage.getPixelData())
|
||||
->blitToWindow (hwnd, dc, transparent, x, y, maskedRegion, updateLayeredWindowAlpha);
|
||||
}
|
||||
|
||||
|
|
@ -2851,9 +2851,9 @@ void Desktop::setMousePosition (const Point<int>& newPosition)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
Image::SharedImage* Image::SharedImage::createNativeImage (PixelFormat format, int width, int height, bool clearImage)
|
||||
ImagePixelData* NativeImageType::create (Image::PixelFormat format, int width, int height, bool clearImage) const
|
||||
{
|
||||
return createSoftwareImage (format, width, height, clearImage);
|
||||
return SoftwareImageType().create (format, width, height, clearImage);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -882,7 +882,7 @@ Image ListBox::createSnapshotOfSelectedRows (int& imageX, int& imageY)
|
|||
imageArea = imageArea.getIntersection (getLocalBounds());
|
||||
imageX = imageArea.getX();
|
||||
imageY = imageArea.getY();
|
||||
Image snapshot (Image::ARGB, imageArea.getWidth(), imageArea.getHeight(), true, Image::NativeImage);
|
||||
Image snapshot (Image::ARGB, imageArea.getWidth(), imageArea.getHeight(), true);
|
||||
|
||||
for (i = getNumRowsOnScreen() + 2; --i >= 0;)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ void OpenGLComponent::internalRepaint (int x, int y, int w, int h)
|
|||
Component::internalRepaint (x, y, w, h);
|
||||
}
|
||||
|
||||
void OpenGLComponent::updateEmbeddedPosition (const Rectangle<int>&)
|
||||
{
|
||||
}
|
||||
|
||||
bool OpenGLHelpers::isContextActive()
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -350,8 +350,8 @@ void OpenGLFrameBuffer::setCurrentFrameBufferTarget (GLuint frameBufferID)
|
|||
|
||||
GLuint OpenGLFrameBuffer::getCurrentFrameBufferTarget()
|
||||
{
|
||||
GLint fb;
|
||||
glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fb);
|
||||
GLint fb;
|
||||
glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fb);
|
||||
return (GLuint) fb;
|
||||
}
|
||||
|
||||
|
|
@ -398,26 +398,22 @@ bool OpenGLFrameBuffer::writePixels (const PixelARGB* data, const Rectangle<int>
|
|||
glDisable (GL_DEPTH_TEST);
|
||||
glDisable (GL_BLEND);
|
||||
|
||||
OpenGLTexture tex;
|
||||
tex.load (data, area.getWidth(), area.getHeight());
|
||||
|
||||
#if JUCE_OPENGL_ES
|
||||
{
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
OpenGLTexture tex;
|
||||
tex.load (data, area.getWidth(), area.getHeight());
|
||||
tex.bind();
|
||||
|
||||
const GLint cropRect[4] = { 0, 0, area.getWidth(), area.getHeight() };
|
||||
const GLint cropRect[4] = { 0, tex.getHeight() - area.getHeight(), area.getWidth(), area.getHeight() };
|
||||
glTexParameteriv (GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
|
||||
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
|
||||
glDrawTexiOES (area.getX(), area.getY(), 1, area.getWidth(), area.getHeight());
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
}
|
||||
#else
|
||||
{
|
||||
OpenGLTexture tex;
|
||||
tex.load (data, area.getWidth(), area.getHeight());
|
||||
|
||||
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
|
|
|
|||
|
|
@ -985,11 +985,8 @@ public:
|
|||
{
|
||||
const Rectangle<int>& clipBounds = clip->getClipBounds();
|
||||
|
||||
OpenGLFrameBufferImage* fbi = new OpenGLFrameBufferImage (clipBounds.getWidth(), clipBounds.getHeight());
|
||||
fbi->frameBuffer.clear (Colours::transparentBlack);
|
||||
|
||||
s->transparencyLayer = Image (fbi);
|
||||
s->target = OpenGLTarget (fbi->frameBuffer, clipBounds.getPosition());
|
||||
s->transparencyLayer = Image (OpenGLImageType().create (Image::ARGB, clipBounds.getWidth(), clipBounds.getHeight(), true));
|
||||
s->target = OpenGLTarget (*OpenGLImageType::getFrameBufferFrom (s->transparencyLayer), clipBounds.getPosition());
|
||||
s->transparencyLayerAlpha = opacity;
|
||||
s->cloneClipIfMultiplyReferenced();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -703,11 +703,11 @@ OpenGLTextureFromImage::OpenGLTextureFromImage (const Image& image)
|
|||
: width (image.getWidth()),
|
||||
height (image.getHeight())
|
||||
{
|
||||
OpenGLFrameBufferImage* glImage = dynamic_cast <OpenGLFrameBufferImage*> (image.getSharedImage());
|
||||
OpenGLFrameBuffer* const fb = OpenGLImageType::getFrameBufferFrom (image);
|
||||
|
||||
if (glImage != nullptr)
|
||||
if (fb != nullptr)
|
||||
{
|
||||
textureID = glImage->frameBuffer.getTextureID();
|
||||
textureID = fb->getTextureID();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,44 +25,62 @@
|
|||
|
||||
BEGIN_JUCE_NAMESPACE
|
||||
|
||||
OpenGLFrameBufferImage::OpenGLFrameBufferImage (int width, int height)
|
||||
: Image::SharedImage (Image::ARGB, width, height),
|
||||
pixelStride (4),
|
||||
lineStride (width * pixelStride)
|
||||
|
||||
//==============================================================================
|
||||
class OpenGLFrameBufferImage : public ImagePixelData
|
||||
{
|
||||
frameBuffer.initialise (width, height);
|
||||
frameBuffer.clear (Colours::transparentBlack);
|
||||
}
|
||||
|
||||
OpenGLFrameBufferImage::~OpenGLFrameBufferImage() {}
|
||||
|
||||
LowLevelGraphicsContext* OpenGLFrameBufferImage::createLowLevelContext()
|
||||
{
|
||||
return new OpenGLRenderer (frameBuffer);
|
||||
}
|
||||
|
||||
Image::SharedImage* OpenGLFrameBufferImage::clone()
|
||||
{
|
||||
OpenGLFrameBufferImage* im = new OpenGLFrameBufferImage (getWidth(), getHeight());
|
||||
im->incReferenceCount();
|
||||
|
||||
public:
|
||||
OpenGLFrameBufferImage (int width, int height)
|
||||
: ImagePixelData (Image::ARGB, width, height),
|
||||
pixelStride (4),
|
||||
lineStride (width * pixelStride)
|
||||
{
|
||||
Image newImage (im);
|
||||
Graphics g (newImage);
|
||||
g.drawImageAt (Image (this), 0, 0, false);
|
||||
frameBuffer.initialise (width, height);
|
||||
frameBuffer.clear (Colours::transparentBlack);
|
||||
}
|
||||
|
||||
im->resetReferenceCount();
|
||||
return im;
|
||||
}
|
||||
LowLevelGraphicsContext* createLowLevelContext()
|
||||
{
|
||||
return new OpenGLRenderer (frameBuffer);
|
||||
}
|
||||
|
||||
Image::ImageType OpenGLFrameBufferImage::getType() const
|
||||
{
|
||||
return Image::NativeImage;
|
||||
}
|
||||
ImageType* createType() const { return new OpenGLImageType(); }
|
||||
|
||||
ImagePixelData* clone()
|
||||
{
|
||||
OpenGLFrameBufferImage* im = new OpenGLFrameBufferImage (width, height);
|
||||
im->incReferenceCount();
|
||||
|
||||
{
|
||||
Image newImage (im);
|
||||
Graphics g (newImage);
|
||||
g.drawImageAt (Image (this), 0, 0, false);
|
||||
}
|
||||
|
||||
im->resetReferenceCount();
|
||||
return im;
|
||||
}
|
||||
|
||||
void initialiseBitmapData (Image::BitmapData& bitmapData, int x, int y, Image::BitmapData::ReadWriteMode mode)
|
||||
{
|
||||
bitmapData.pixelFormat = pixelFormat;
|
||||
bitmapData.lineStride = lineStride;
|
||||
bitmapData.pixelStride = pixelStride;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case Image::BitmapData::writeOnly: DataReleaser<Dummy, Writer>::initialise (frameBuffer, bitmapData, x, y); break;
|
||||
case Image::BitmapData::readOnly: DataReleaser<Reader, Dummy> ::initialise (frameBuffer, bitmapData, x, y); break;
|
||||
case Image::BitmapData::readWrite: DataReleaser<Reader, Writer>::initialise (frameBuffer, bitmapData, x, y); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
|
||||
OpenGLFrameBuffer frameBuffer;
|
||||
|
||||
private:
|
||||
int pixelStride, lineStride;
|
||||
|
||||
namespace OpenGLImageHelpers
|
||||
{
|
||||
struct Dummy
|
||||
{
|
||||
Dummy (OpenGLFrameBuffer&, int, int, int, int) noexcept {}
|
||||
|
|
@ -145,24 +163,35 @@ namespace OpenGLImageHelpers
|
|||
HeapBlock<PixelARGB> data;
|
||||
WriterType writer;
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLFrameBufferImage);
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
OpenGLImageType::OpenGLImageType() {}
|
||||
OpenGLImageType::~OpenGLImageType() {}
|
||||
|
||||
int OpenGLImageType::getTypeID() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
void OpenGLFrameBufferImage::initialiseBitmapData (Image::BitmapData& bitmapData, int x, int y,
|
||||
Image::BitmapData::ReadWriteMode mode)
|
||||
ImagePixelData* OpenGLImageType::create (Image::PixelFormat, int width, int height, bool shouldClearImage) const
|
||||
{
|
||||
using namespace OpenGLImageHelpers;
|
||||
OpenGLFrameBufferImage* im = new OpenGLFrameBufferImage (width, height);
|
||||
|
||||
bitmapData.pixelFormat = format;
|
||||
bitmapData.lineStride = lineStride;
|
||||
bitmapData.pixelStride = pixelStride;
|
||||
if (shouldClearImage)
|
||||
im->frameBuffer.clear (Colours::transparentBlack);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case Image::BitmapData::writeOnly: DataReleaser<Dummy, Writer>::initialise (frameBuffer, bitmapData, x, y); break;
|
||||
case Image::BitmapData::readOnly: DataReleaser<Reader, Dummy> ::initialise (frameBuffer, bitmapData, x, y); break;
|
||||
case Image::BitmapData::readWrite: DataReleaser<Reader, Writer>::initialise (frameBuffer, bitmapData, x, y); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
return im;
|
||||
}
|
||||
|
||||
OpenGLFrameBuffer* OpenGLImageType::getFrameBufferFrom (const Image& image)
|
||||
{
|
||||
OpenGLFrameBufferImage* const glImage = dynamic_cast<OpenGLFrameBufferImage*> (image.getPixelData());
|
||||
|
||||
return glImage != nullptr ? &(glImage->frameBuffer) : nullptr;
|
||||
}
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -29,42 +29,25 @@
|
|||
|
||||
//==============================================================================
|
||||
/**
|
||||
A type of Image::SharedImage that stores its image data in an OpenGL
|
||||
A type of ImagePixelData that stores its image data in an OpenGL
|
||||
framebuffer, allowing a JUCE Image object to wrap a framebuffer.
|
||||
|
||||
By creating an Image from an instance of an OpenGLFrameBufferImage,
|
||||
you can then use a Graphics object to draw into the framebuffer using normal
|
||||
JUCE 2D operations.
|
||||
|
||||
@see Image, Image::SharedImage, OpenGLFrameBuffer
|
||||
@see Image, ImageType, ImagePixelData, OpenGLFrameBuffer
|
||||
*/
|
||||
class JUCE_API OpenGLFrameBufferImage : public Image::SharedImage
|
||||
class JUCE_API OpenGLImageType : public ImageType
|
||||
{
|
||||
public:
|
||||
OpenGLFrameBufferImage (int width, int height);
|
||||
OpenGLImageType();
|
||||
~OpenGLImageType();
|
||||
|
||||
/** Destructor. */
|
||||
~OpenGLFrameBufferImage();
|
||||
ImagePixelData* create (Image::PixelFormat, int width, int height, bool shouldClearImage) const;
|
||||
int getTypeID() const;
|
||||
|
||||
/** The underlying framebuffer.
|
||||
Although this is exposed to allow access to use it as a texture, etc, be
|
||||
careful not to change its size while the image is using it.
|
||||
*/
|
||||
OpenGLFrameBuffer frameBuffer;
|
||||
|
||||
/** @internal */
|
||||
LowLevelGraphicsContext* createLowLevelContext();
|
||||
/** @internal */
|
||||
SharedImage* clone();
|
||||
/** @internal */
|
||||
Image::ImageType getType() const;
|
||||
/** @internal */
|
||||
void initialiseBitmapData (Image::BitmapData&, int, int, Image::BitmapData::ReadWriteMode);
|
||||
|
||||
private:
|
||||
int pixelStride, lineStride;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLFrameBufferImage);
|
||||
static OpenGLFrameBuffer* getFrameBufferFrom (const Image&);
|
||||
};
|
||||
|
||||
#endif // __JUCE_OPENGLIMAGE_JUCEHEADER__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue