Browse Source

Refactoring of image storage: new classes ImageType, ImagePixelData, SoftwareImageType, NativeImageType, OpenGLImageType.

tags/2021-05-28
jules 14 years ago
parent
commit
0b1cdf6ab1
21 changed files with 493 additions and 438 deletions
  1. +1
    -1
      extras/Introjucer/Source/Project Saving/jucer_ProjectExport_XCode.h
  2. +1
    -1
      extras/Introjucer/Source/Project Saving/jucer_ProjectExporter.cpp
  3. +25
    -54
      modules/juce_graphics/colour/juce_PixelFormats.h
  4. +11
    -16
      modules/juce_graphics/image_formats/juce_GIFLoader.cpp
  5. +162
    -153
      modules/juce_graphics/images/juce_Image.cpp
  6. +129
    -59
      modules/juce_graphics/images/juce_Image.h
  7. +10
    -10
      modules/juce_graphics/native/juce_android_GraphicsContext.cpp
  8. +20
    -19
      modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm
  9. +2
    -2
      modules/juce_gui_basics/components/juce_Component.cpp
  10. +2
    -2
      modules/juce_gui_basics/misc/juce_DropShadower.cpp
  11. +4
    -4
      modules/juce_gui_basics/native/juce_android_Windowing.cpp
  12. +14
    -14
      modules/juce_gui_basics/native/juce_linux_Windowing.cpp
  13. +1
    -1
      modules/juce_gui_basics/native/juce_mac_Windowing.mm
  14. +15
    -15
      modules/juce_gui_basics/native/juce_win32_Windowing.cpp
  15. +1
    -1
      modules/juce_gui_basics/widgets/juce_ListBox.cpp
  16. +4
    -0
      modules/juce_opengl/native/juce_android_OpenGLComponent.cpp
  17. +8
    -12
      modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp
  18. +2
    -5
      modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp
  19. +3
    -3
      modules/juce_opengl/opengl/juce_OpenGLHelpers.cpp
  20. +70
    -41
      modules/juce_opengl/opengl/juce_OpenGLImage.cpp
  21. +8
    -25
      modules/juce_opengl/opengl/juce_OpenGLImage.h

+ 1
- 1
extras/Introjucer/Source/Project Saving/jucer_ProjectExport_XCode.h View File

@@ -244,7 +244,7 @@ private:
if (w != h || (w != 16 && w != 32 && w != 48 && w != 64)) if (w != h || (w != 16 && w != 32 && w != 48 && w != 64))
{ {
const int newSize = w >= 128 ? 128 : (w >= 64 ? 64 : (w >= 32 ? 32 : 16)); 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); Graphics g (newIm);
g.drawImageWithin (image, 0, 0, newSize, newSize, g.drawImageWithin (image, 0, 0, newSize, newSize,
RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize, false); RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize, false);


+ 1
- 1
extras/Introjucer/Source/Project Saving/jucer_ProjectExporter.cpp View File

@@ -274,7 +274,7 @@ Image ProjectExporter::getBestIconForSize (int size, bool returnNullIfNothingBig
if (returnNullIfNothingBigEnough && im.getWidth() < size && im.getHeight() < size) if (returnNullIfNothingBigEnough && im.getWidth() < size && im.getHeight() < size)
return Image::null; return Image::null;
Image newIm (Image::ARGB, size, size, true, Image::SoftwareImage);
Image newIm (Image::ARGB, size, size, true, SoftwareImageType());
Graphics g (newIm); Graphics g (newIm);
g.drawImageWithin (im, 0, 0, size, size, g.drawImageWithin (im, 0, 0, size, size,
RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize, false); RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize, false);


+ 25
- 54
modules/juce_graphics/colour/juce_PixelFormats.h View File

@@ -89,7 +89,8 @@ public:
This takes into account the opacity of the pixel being overlaid, and blends This takes into account the opacity of the pixel being overlaid, and blends
it accordingly. it accordingly.
*/ */
forcedinline void blend (const PixelARGB& src) noexcept
template <class Pixel>
forcedinline void blend (const Pixel& src) noexcept
{ {
uint32 sargb = src.getARGB(); uint32 sargb = src.getARGB();
const uint32 alpha = 0x100 - (sargb >> 24); const uint32 alpha = 0x100 - (sargb >> 24);
@@ -100,14 +101,6 @@ public:
argb = sargb; 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. /** Blends another pixel onto this one.
This takes into account the opacity of the pixel being overlaid, and blends 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 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. */ /** 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. */ /** 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 }; enum { indexA = 0, indexR = 1, indexG = 2, indexB = 3 };
#else
#else
enum { indexA = 3, indexR = 2, indexG = 1, indexB = 0 }; enum { indexA = 3, indexR = 2, indexG = 1, indexB = 0 };
#endif
#endif
private: private:
//============================================================================== //==============================================================================
struct Components struct Components
{ {
#if JUCE_BIG_ENDIAN
#if JUCE_BIG_ENDIAN
uint8 a : 8, r : 8, g : 8, b : 8; uint8 a : 8, r : 8, g : 8, b : 8;
#else
#else
uint8 b, g, r, a; uint8 b, g, r, a;
#endif
#endif
} PACKED; } PACKED;
union union
@@ -328,7 +321,8 @@ public:
This takes into account the opacity of the pixel being overlaid, and blends This takes into account the opacity of the pixel being overlaid, and blends
it accordingly. it accordingly.
*/ */
forcedinline void blend (const PixelARGB& src) noexcept
template <class Pixel>
forcedinline void blend (const Pixel& src) noexcept
{ {
uint32 sargb = src.getARGB(); uint32 sargb = src.getARGB();
const uint32 alpha = 0x100 - (sargb >> 24); const uint32 alpha = 0x100 - (sargb >> 24);
@@ -346,8 +340,6 @@ public:
set (src); set (src);
} }
forcedinline void blend (const PixelAlpha& src) noexcept;
/** Blends another pixel onto this one, applying an extra multiplier to its opacity. /** 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 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. */ /** Multiplies the colour's alpha value with another one. */
forcedinline void multiplyAlpha (int) noexcept {} 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. */ /** Sets the pixel's colour from individual components. */
void setARGB (const uint8, const uint8 r_, const uint8 g_, const uint8 b_) noexcept 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. */ /** 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 }; enum { indexR = 0, indexG = 1, indexB = 2 };
#else
#else
enum { indexR = 2, indexG = 1, indexB = 0 }; enum { indexR = 2, indexG = 1, indexB = 0 };
#endif
#endif
private: private:
//============================================================================== //==============================================================================
#if JUCE_MAC
#if JUCE_MAC
uint8 r, g, b; uint8 r, g, b;
#else
#else
uint8 b, g, r; uint8 b, g, r;
#endif
#endif
} }
#ifndef DOXYGEN #ifndef DOXYGEN
@@ -520,7 +515,7 @@ public:
template <class Pixel> template <class Pixel>
forcedinline void tween (const Pixel& src, const uint32 amount) noexcept 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. /** Copies another pixel colour over this one.
@@ -558,18 +553,12 @@ public:
} }
/** Premultiplies the pixel's RGB values by its alpha. */ /** Premultiplies the pixel's RGB values by its alpha. */
forcedinline void premultiply() noexcept
{
}
forcedinline void premultiply() noexcept {}
/** Unpremultiplies the pixel's RGB values. */ /** 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. */ /** The indexes of the different components in the byte layout of this type of colour. */
@@ -584,26 +573,8 @@ private:
#endif #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 #if JUCE_MSVC
#pragma pack (pop)
#pragma pack (pop)
#endif #endif
#undef PACKED #undef PACKED


+ 11
- 16
modules/juce_graphics/image_formats/juce_GIFLoader.cpp View File

@@ -223,14 +223,13 @@ private:
{ {
fresh = false; 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) if (sp > stack)
@@ -256,8 +255,8 @@ private:
return -2; return -2;
uint8 buf [260]; uint8 buf [260];
int n; int n;
while ((n = readDataBlock (buf)) > 0) while ((n = readDataBlock (buf)) > 0)
{} {}
@@ -290,8 +289,7 @@ private:
table[1][code] = firstcode; table[1][code] = firstcode;
++maxCode; ++maxCode;
if ((maxCode >= maxCodeSize)
&& (maxCodeSize < maxGifCode))
if (maxCode >= maxCodeSize && maxCodeSize < maxGifCode)
{ {
maxCodeSize <<= 1; maxCodeSize <<= 1;
++codeSize; ++codeSize;
@@ -345,7 +343,6 @@ private:
} }
currentBit += codeSize_; currentBit += codeSize_;
return result; return result;
} }
@@ -389,9 +386,7 @@ private:
while (ypos >= destData.height) while (ypos >= destData.height)
{ {
++pass;
switch (pass)
switch (++pass)
{ {
case 1: ypos = 4; yStep = 8; break; case 1: ypos = 4; yStep = 8; break;
case 2: ypos = 2; yStep = 4; break; case 2: ypos = 2; yStep = 4; break;
@@ -436,12 +431,12 @@ bool GIFImageFormat::canUnderstand (InputStream& in)
Image GIFImageFormat::decodeImage (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); return juce_loadWithCoreImage (in);
#else
#else
const ScopedPointer <GIFLoader> loader (new GIFLoader (in)); const ScopedPointer <GIFLoader> loader (new GIFLoader (in));
return loader->image; return loader->image;
#endif
#endif
} }
bool GIFImageFormat::writeImageToStream (const Image& /*sourceImage*/, OutputStream& /*destStream*/) bool GIFImageFormat::writeImageToStream (const Image& /*sourceImage*/, OutputStream& /*destStream*/)


+ 162
- 153
modules/juce_graphics/images/juce_Image.cpp View File

@@ -26,32 +26,58 @@
BEGIN_JUCE_NAMESPACE 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: 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)), 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() LowLevelGraphicsContext* createLowLevelContext()
@@ -59,48 +85,53 @@ public:
return new LowLevelGraphicsSoftwareRenderer (Image (this)); 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.data = imageData + x * pixelStride + y * lineStride;
bitmap.pixelFormat = format;
bitmap.pixelFormat = pixelFormat;
bitmap.lineStride = lineStride; bitmap.lineStride = lineStride;
bitmap.pixelStride = pixelStride; 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)); memcpy (s->imageData, imageData, (size_t) (lineStride * height));
return s; return s;
} }
ImageType* createType() const { return new SoftwareImageType(); }
private: private:
HeapBlock<uint8> imageData; HeapBlock<uint8> imageData;
const int pixelStride, lineStride; 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: 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 (image_), area (area_)
{ {
} }
Image::ImageType getType() const
{
return Image::SoftwareImage;
}
LowLevelGraphicsContext* createLowLevelContext() LowLevelGraphicsContext* createLowLevelContext()
{ {
LowLevelGraphicsContext* g = image->createLowLevelContext(); LowLevelGraphicsContext* g = image->createLowLevelContext();
@@ -114,25 +145,29 @@ public:
image->initialiseBitmapData (bitmap, x + area.getX(), y + area.getY(), mode); 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); 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: private:
const ReferenceCountedObjectPtr<Image::SharedImage> image;
const ReferenceCountedObjectPtr<ImagePixelData> image;
const Rectangle<int> area; 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 Image Image::getClippedImage (const Rectangle<int>& area) const
@@ -144,7 +179,7 @@ Image Image::getClippedImage (const Rectangle<int>& area) const
if (validArea.isEmpty()) if (validArea.isEmpty())
return Image::null; 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 (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::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 #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
Image::Image (Image&& other) noexcept 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& Image::operator= (Image&& other) noexcept
{ {
image = static_cast <ReferenceCountedObjectPtr<SharedImage>&&> (other.image);
image = static_cast <ReferenceCountedObjectPtr<ImagePixelData>&&> (other.image);
return *this; return *this;
} }
#endif #endif
@@ -196,6 +233,16 @@ Image::~Image()
const Image Image::null; 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 LowLevelGraphicsContext* Image::createLowLevelContext() const
{ {
return image == nullptr ? nullptr : image->createLowLevelContext(); 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)) if (image == nullptr || (image->width == newWidth && image->height == newHeight))
return *this; 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); Graphics g (newImage);
g.setImageResamplingQuality (quality); g.setImageResamplingQuality (quality);
@@ -223,11 +271,13 @@ Image Image::rescaled (const int newWidth, const int newHeight, const Graphics::
Image Image::convertedToFormat (PixelFormat newFormat) const Image Image::convertedToFormat (PixelFormat newFormat) const
{ {
if (image == nullptr || newFormat == image->format)
if (image == nullptr || newFormat == image->pixelFormat)
return *this; return *this;
const int w = image->width, h = image->height; 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) 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 destData (newImage, 0, 0, w, h, BitmapData::writeOnly);
const BitmapData srcData (*this, 0, 0, w, h); 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) 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; 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) 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())) 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;
} }
} }
void Image::desaturate()
struct AlphaMultiplyOp
{ {
if (isARGB() || isRGB())
AlphaMultiplyOp (float alpha_) noexcept : alpha (alpha_) {}
const float alpha;
template <class PixelType>
void operator() (PixelType& pixel) const
{ {
const BitmapData destData (*this, 0, 0, getWidth(), getHeight(), BitmapData::readWrite);
pixel.multiplyAlpha (alpha);
}
if (isARGB())
{
for (int y = 0; y < destData.height; ++y)
{
uint8* p = destData.getLinePointer (y);
JUCE_DECLARE_NON_COPYABLE (AlphaMultiplyOp);
};
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);
void Image::multiplyAllAlphas (const float amountToMultiplyBy)
{
jassert (hasAlphaChannel());
for (int x = 0; x < destData.width; ++x)
{
((PixelRGB*) p)->desaturate();
p += destData.pixelStride;
}
}
}
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);
performPixelOp (destData, DesaturateOp());
} }
} }
@@ -594,7 +604,7 @@ void Image::moveImageSection (int dx, int dy,
const int minX = jmin (dx, sx); const int minX = jmin (dx, sx);
const int minY = jmin (dy, sy); 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)); h = jmin (h, getHeight() - jmax (sy, dy));
if (w > 0 && h > 0) if (w > 0 && h > 0)
@@ -629,5 +639,4 @@ void Image::moveImageSection (int dx, int dy,
} }
} }
END_JUCE_NAMESPACE END_JUCE_NAMESPACE

+ 129
- 59
modules/juce_graphics/images/juce_Image.h View File

@@ -29,6 +29,9 @@
#include "../colour/juce_Colour.h" #include "../colour/juce_Colour.h"
#include "../contexts/juce_GraphicsContext.h" #include "../contexts/juce_GraphicsContext.h"
class ImageType;
class ImagePixelData;
//============================================================================== //==============================================================================
/** /**
@@ -66,20 +69,15 @@ public:
SingleChannel /**<< each pixel is a 1-byte alpha channel value. */ SingleChannel /**<< each pixel is a 1-byte alpha channel value. */
}; };
/**
*/
enum ImageType
{
SoftwareImage = 0,
NativeImage
};
//============================================================================== //==============================================================================
/** Creates a null image. */ /** Creates a null image. */
Image(); Image();
/** Creates an image with a specified size and format. /** 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 format the number of colour channels in the image
@param imageWidth the desired width of the image, in pixels - this value must be @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) greater than zero (otherwise a width of 1 will be used)
@@ -88,14 +86,23 @@ public:
@param clearImage if true, the image will initially be cleared to black (if it's RGB) @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 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. 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.
*/ */
Image (PixelFormat format,
int imageWidth,
int imageHeight,
bool clearImage,
ImageType type = NativeImage);
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
@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.
@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, const ImageType& type);
/** Creates a shared reference to another image. /** Creates a shared reference to another image.
@@ -150,30 +157,30 @@ public:
//============================================================================== //==============================================================================
/** Returns the image's width (in pixels). */ /** 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). */ /** 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. /** Returns a rectangle with the same size as this image.
The rectangle's origin is always (0, 0). 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. */ /** 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. */ /** 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. */ /** 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. */ /** 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. */ /** 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. /** Clears a section of the image with a given colour.
@@ -236,7 +243,7 @@ public:
@see setPixelAt, Image::BitmapData::getPixelColour @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. /** Sets the colour of one of the image's pixels.
@@ -387,54 +394,117 @@ public:
@see duplicateIfShared @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.
/** @internal */
ImagePixelData* getPixelData() const noexcept { return 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();
/** @internal */
explicit Image (ImagePixelData*);
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;
private:
//==============================================================================
ReferenceCountedObjectPtr<ImagePixelData> image;
static SharedImage* createNativeImage (PixelFormat format, int width, int height, bool clearImage);
static SharedImage* createSoftwareImage (PixelFormat format, int width, int height, bool clearImage);
JUCE_LEAK_DETECTOR (Image);
};
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;
//==============================================================================
/**
This is a base class for holding image data in implementation-specific ways.
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedImage);
};
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.
/** @internal */
SharedImage* getSharedImage() const noexcept { return image; }
/** @internal */
explicit Image (SharedImage* instance);
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: private:
//==============================================================================
friend class SharedImage;
friend class BitmapData;
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();
ReferenceCountedObjectPtr<SharedImage> image;
/** 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;
JUCE_LEAK_DETECTOR (Image);
/** 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;
}; };


+ 10
- 10
modules/juce_graphics/native/juce_android_GraphicsContext.cpp View File

@@ -158,18 +158,17 @@ DECLARE_JNI_CLASS (RadialGradientClass, "android/graphics/RadialGradient");
#undef JNI_CLASS_MEMBERS #undef JNI_CLASS_MEMBERS
//============================================================================== //==============================================================================
class AndroidImage : public Image::SharedImage
class AndroidImage : public ImagePixelData
{ {
public: public:
//==============================================================================
AndroidImage (const int width_, const int height_, const bool clearImage) 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)) bitmap (createBitmap (width_, height_, false))
{ {
} }
AndroidImage (const int width_, const int height_, const GlobalRef& bitmap_) AndroidImage (const int width_, const int height_, const GlobalRef& bitmap_)
: Image::SharedImage (Image::ARGB, width_, height_),
: ImagePixelData (Image::ARGB, width_, height_),
bitmap (bitmap_) bitmap (bitmap_)
{ {
} }
@@ -180,7 +179,6 @@ public:
bitmap.callVoidMethod (BitmapClass.recycle); bitmap.callVoidMethod (BitmapClass.recycle);
} }
Image::ImageType getType() const { return Image::NativeImage; }
LowLevelGraphicsContext* createLowLevelContext(); LowLevelGraphicsContext* createLowLevelContext();
void initialiseBitmapData (Image::BitmapData& bm, int x, int y, Image::BitmapData::ReadWriteMode mode) 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); bm.dataReleaser = new CopyHandler (*this, bm, x, y, mode);
} }
SharedImage* clone()
ImagePixelData* clone()
{ {
JNIEnv* env = getEnv(); JNIEnv* env = getEnv();
jobject mode = env->GetStaticObjectField (BitmapConfig, BitmapConfig.ARGB_8888); jobject mode = env->GetStaticObjectField (BitmapConfig, BitmapConfig.ARGB_8888);
@@ -201,6 +199,8 @@ public:
return new AndroidImage (width, height, newCopy); return new AndroidImage (width, height, newCopy);
} }
ImageType* createType() const { return new NativeImageType(); }
static jobject createBitmap (int width, int height, bool asSingleChannel) static jobject createBitmap (int width, int height, bool asSingleChannel)
{ {
JNIEnv* env = getEnv(); JNIEnv* env = getEnv();
@@ -282,14 +282,14 @@ private:
}; };
#endif #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 USE_ANDROID_CANVAS
if (format != Image::SingleChannel)
if (pixelFormat != Image::SingleChannel)
return new AndroidImage (width, height, clearImage); return new AndroidImage (width, height, clearImage);
#endif #endif
return createSoftwareImage (format, width, height, clearImage);
return SoftwareImageType().create (format, width, height, clearImage);
} }
#if USE_ANDROID_CANVAS #if USE_ANDROID_CANVAS
@@ -452,7 +452,7 @@ public:
void drawImage (const Image& sourceImage, const AffineTransform& transform) 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) if (androidImage != 0)
{ {


+ 20
- 19
modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm View File

@@ -27,14 +27,13 @@
#include "juce_mac_CoreGraphicsContext.h" #include "juce_mac_CoreGraphicsContext.h"
//============================================================================== //==============================================================================
class CoreGraphicsImage : public Image::SharedImage
class CoreGraphicsImage : public ImagePixelData
{ {
public: 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; lineStride = (pixelStride * jmax (1, width) + 3) & ~3;
imageData.allocate (lineStride * jmax (1, height), clearImage); imageData.allocate (lineStride * jmax (1, height), clearImage);
@@ -43,7 +42,7 @@ public:
: CGColorSpaceCreateDeviceRGB(); : CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate (imageData, width, height, 8, lineStride, context = CGBitmapContextCreate (imageData, width, height, 8, lineStride,
colourSpace, getCGImageFlags (format_));
colourSpace, getCGImageFlags (format));
CGColorSpaceRelease (colourSpace); CGColorSpaceRelease (colourSpace);
} }
@@ -53,29 +52,30 @@ public:
CGContextRelease (context); CGContextRelease (context);
} }
Image::ImageType getType() const { return Image::NativeImage; }
LowLevelGraphicsContext* createLowLevelContext(); 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.data = imageData + x * pixelStride + y * lineStride;
bitmap.pixelFormat = format;
bitmap.pixelFormat = pixelFormat;
bitmap.lineStride = lineStride; bitmap.lineStride = lineStride;
bitmap.pixelStride = pixelStride; 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); memcpy (im->imageData, imageData, lineStride * height);
return im; return im;
} }
ImageType* createType() const { return new NativeImageType(); }
//============================================================================== //==============================================================================
static CGImageRef createImage (const Image& juceImage, const bool forAlpha, static CGImageRef createImage (const Image& juceImage, const bool forAlpha,
CGColorSpaceRef colourSpace, const bool mustOutliveSource) 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)) if (nativeImage != nullptr && (juceImage.getFormat() == Image::SingleChannel || ! forAlpha))
{ {
@@ -125,9 +125,9 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsImage); 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 != kCGImageAlphaNoneSkipLast
&& alphaInfo != kCGImageAlphaNoneSkipFirst); && 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. 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); 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) 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); jassert (cgi != nullptr);
return cgi != nullptr ? cgi->context : 0; return cgi != nullptr ? cgi->context : 0;
} }


+ 2
- 2
modules/juce_gui_basics/components/juce_Component.cpp View File

@@ -1789,7 +1789,7 @@ void Component::paintComponent (Graphics& g)
if (bufferedImage.isNull()) if (bufferedImage.isNull())
{ {
bufferedImage = Image (flags.opaqueFlag ? Image::RGB : Image::ARGB, bufferedImage = Image (flags.opaqueFlag ? Image::RGB : Image::ARGB,
getWidth(), getHeight(), ! flags.opaqueFlag, Image::NativeImage);
getWidth(), getHeight(), ! flags.opaqueFlag);
Graphics imG (bufferedImage); Graphics imG (bufferedImage);
paint (imG); paint (imG);
@@ -1893,7 +1893,7 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel)
if (effect != nullptr) if (effect != nullptr)
{ {
Image effectImage (flags.opaqueFlag ? Image::RGB : Image::ARGB, Image effectImage (flags.opaqueFlag ? Image::RGB : Image::ARGB,
getWidth(), getHeight(), ! flags.opaqueFlag, Image::NativeImage);
getWidth(), getHeight(), ! flags.opaqueFlag);
{ {
Graphics g2 (effectImage); Graphics g2 (effectImage);
paintComponentAndChildren (g2); paintComponentAndChildren (g2);


+ 2
- 2
modules/juce_gui_basics/misc/juce_DropShadower.cpp View File

@@ -196,7 +196,7 @@ void DropShadower::updateShadows()
if (bigIm.isNull()) 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); Graphics bigG (bigIm);
bigG.setColour (Colours::black.withAlpha (alpha)); 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, void DropShadower::setShadowImage (const Image& src, const int num, const int w, const int h,
const int sx, const int sy) 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]); Graphics g (shadowImageSections[num]);
g.drawImage (src, 0, 0, w, h, sx, sy, w, h); g.drawImage (src, 0, 0, w, h, sx, sy, w, h);


+ 4
- 4
modules/juce_gui_basics/native/juce_android_Windowing.cpp View File

@@ -498,11 +498,11 @@ private:
bool usingAndroidGraphics, fullScreen; bool usingAndroidGraphics, fullScreen;
int sizeAllocated; int sizeAllocated;
class PreallocatedImage : public Image::SharedImage
class PreallocatedImage : public ImagePixelData
{ {
public: public:
PreallocatedImage (const int width_, const int height_, jint* data_, bool hasAlpha_) 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_) if (hasAlpha_)
zeromem (data_, width * height * sizeof (jint)); 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)); } LowLevelGraphicsContext* createLowLevelContext() { return new LowLevelGraphicsSoftwareRenderer (Image (this)); }
void initialiseBitmapData (Image::BitmapData& bm, int x, int y, Image::BitmapData::ReadWriteMode mode) 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); bm.data = (uint8*) (data + x + y * width);
} }
SharedImage* clone()
ImagePixelData* clone()
{ {
PreallocatedImage* s = new PreallocatedImage (width, height, 0, hasAlpha); PreallocatedImage* s = new PreallocatedImage (width, height, 0, hasAlpha);
s->allocatedData.malloc (sizeof (jint) * width * height); s->allocatedData.malloc (sizeof (jint) * width * height);


+ 14
- 14
modules/juce_gui_basics/native/juce_linux_Windowing.cpp View File

@@ -436,18 +436,18 @@ namespace Visuals
} }
//============================================================================== //==============================================================================
class XBitmapImage : public Image::SharedImage
class XBitmapImage : public ImagePixelData
{ {
public: 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) const bool clearImage, const int imageDepth_, Visual* visual)
: Image::SharedImage (format_, w, h),
: ImagePixelData (format, w, h),
imageDepth (imageDepth_), imageDepth (imageDepth_),
gc (None) 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); lineStride = ((w * pixelStride + 3) & ~3);
ScopedXLock xlock; ScopedXLock xlock;
@@ -499,7 +499,7 @@ public:
if (! usingXShm) if (! usingXShm)
#endif #endif
{ {
imageDataAllocated.allocate (lineStride * h, format_ == Image::ARGB && clearImage);
imageDataAllocated.allocate (lineStride * h, format == Image::ARGB && clearImage);
imageData = imageDataAllocated; imageData = imageDataAllocated;
xImage = (XImage*) ::calloc (1, sizeof (XImage)); xImage = (XImage*) ::calloc (1, sizeof (XImage));
@@ -567,27 +567,27 @@ public:
} }
} }
Image::ImageType getType() const { return Image::NativeImage; }
LowLevelGraphicsContext* createLowLevelContext() LowLevelGraphicsContext* createLowLevelContext()
{ {
return new LowLevelGraphicsSoftwareRenderer (Image (this)); 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.data = imageData + x * pixelStride + y * lineStride;
bitmap.pixelFormat = format;
bitmap.pixelFormat = pixelFormat;
bitmap.lineStride = lineStride; bitmap.lineStride = lineStride;
bitmap.pixelStride = pixelStride; bitmap.pixelStride = pixelStride;
} }
SharedImage* clone()
ImagePixelData* clone()
{ {
jassertfalse; jassertfalse;
return nullptr; return nullptr;
} }
ImageType* createType() const { return new NativeImageType(); }
void blitToWindow (Window window, int dx, int dy, int dw, int dh, int sx, int sy) void blitToWindow (Window window, int dx, int dy, int dw, int dh, int sx, int sy)
{ {
ScopedXLock xlock; ScopedXLock xlock;
@@ -1774,7 +1774,7 @@ private:
#endif #endif
const Rectangle<int>& r = *i.getRectangle(); const Rectangle<int>& r = *i.getRectangle();
static_cast<XBitmapImage*> (image.getSharedImage())
static_cast<XBitmapImage*> (image.getPixelData())
->blitToWindow (peer->windowH, ->blitToWindow (peer->windowH,
r.getX(), r.getY(), r.getWidth(), r.getHeight(), r.getX(), r.getY(), r.getWidth(), r.getHeight(),
r.getX() - totalArea.getX(), r.getY() - totalArea.getY()); r.getX() - totalArea.getX(), r.getY() - totalArea.getY());
@@ -3008,9 +3008,9 @@ Image juce_createIconForFile (const File& file)
return Image::null; 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);
} }
//============================================================================== //==============================================================================


+ 1
- 1
modules/juce_gui_basics/native/juce_mac_Windowing.mm View File

@@ -328,7 +328,7 @@ Image juce_createIconForFile (const File& file)
NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())]; 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 saveGraphicsState];
[NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (result) flipped: false]]; [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (result) flipped: false]];


+ 15
- 15
modules/juce_gui_basics/native/juce_win32_Windowing.cpp View File

@@ -194,16 +194,16 @@ const int KeyPress::rewindKey = 0x30003;
//============================================================================== //==============================================================================
class WindowsBitmapImage : public Image::SharedImage
class WindowsBitmapImage : public ImagePixelData
{ {
public: public:
WindowsBitmapImage (const Image::PixelFormat format_,
WindowsBitmapImage (const Image::PixelFormat format,
const int w, const int h, const bool clearImage) 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); lineStride = -((w * pixelStride + 3) & ~3);
zerostruct (bitmapInfo); zerostruct (bitmapInfo);
@@ -214,7 +214,7 @@ public:
bitmapInfo.bV4CSType = 1; bitmapInfo.bV4CSType = 1;
bitmapInfo.bV4BitCount = (unsigned short) (pixelStride * 8); bitmapInfo.bV4BitCount = (unsigned short) (pixelStride * 8);
if (format_ == Image::ARGB)
if (format == Image::ARGB)
{ {
bitmapInfo.bV4AlphaMask = 0xff000000; bitmapInfo.bV4AlphaMask = 0xff000000;
bitmapInfo.bV4RedMask = 0xff0000; bitmapInfo.bV4RedMask = 0xff0000;
@@ -238,7 +238,7 @@ public:
previousBitmap = SelectObject (hdc, hBitmap); previousBitmap = SelectObject (hdc, hBitmap);
if (format_ == Image::ARGB && clearImage)
if (format == Image::ARGB && clearImage)
zeromem (bitmapData, (size_t) std::abs (h * lineStride)); zeromem (bitmapData, (size_t) std::abs (h * lineStride));
imageData = bitmapData - (lineStride * (h - 1)); imageData = bitmapData - (lineStride * (h - 1));
@@ -251,24 +251,24 @@ public:
DeleteObject (hBitmap); DeleteObject (hBitmap);
} }
Image::ImageType getType() const { return Image::NativeImage; }
ImageType* createType() const { return new NativeImageType(); }
LowLevelGraphicsContext* createLowLevelContext() LowLevelGraphicsContext* createLowLevelContext()
{ {
return new LowLevelGraphicsSoftwareRenderer (Image (this)); 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.data = imageData + x * pixelStride + y * lineStride;
bitmap.pixelFormat = format;
bitmap.pixelFormat = pixelFormat;
bitmap.lineStride = lineStride; bitmap.lineStride = lineStride;
bitmap.pixelStride = pixelStride; 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) for (int i = 0; i < height; ++i)
memcpy (im->imageData + i * lineStride, imageData + i * lineStride, (size_t) lineStride); memcpy (im->imageData + i * lineStride, imageData + i * lineStride, (size_t) lineStride);
@@ -1367,7 +1367,7 @@ private:
} }
if (! dontRepaint) if (! dontRepaint)
static_cast <WindowsBitmapImage*> (offscreenImage.getSharedImage())
static_cast <WindowsBitmapImage*> (offscreenImage.getPixelData())
->blitToWindow (hwnd, dc, transparent, x, y, maskedRegion, updateLayeredWindowAlpha); ->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);
} }
//============================================================================== //==============================================================================


+ 1
- 1
modules/juce_gui_basics/widgets/juce_ListBox.cpp View File

@@ -882,7 +882,7 @@ Image ListBox::createSnapshotOfSelectedRows (int& imageX, int& imageY)
imageArea = imageArea.getIntersection (getLocalBounds()); imageArea = imageArea.getIntersection (getLocalBounds());
imageX = imageArea.getX(); imageX = imageArea.getX();
imageY = imageArea.getY(); 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;) for (i = getNumRowsOnScreen() + 2; --i >= 0;)
{ {


+ 4
- 0
modules/juce_opengl/native/juce_android_OpenGLComponent.cpp View File

@@ -39,6 +39,10 @@ void OpenGLComponent::internalRepaint (int x, int y, int w, int h)
Component::internalRepaint (x, y, w, h); Component::internalRepaint (x, y, w, h);
} }
void OpenGLComponent::updateEmbeddedPosition (const Rectangle<int>&)
{
}
bool OpenGLHelpers::isContextActive() bool OpenGLHelpers::isContextActive()
{ {
return false; return false;


+ 8
- 12
modules/juce_opengl/opengl/juce_OpenGLFrameBuffer.cpp View File

@@ -350,8 +350,8 @@ void OpenGLFrameBuffer::setCurrentFrameBufferTarget (GLuint frameBufferID)
GLuint OpenGLFrameBuffer::getCurrentFrameBufferTarget() GLuint OpenGLFrameBuffer::getCurrentFrameBufferTarget()
{ {
GLint fb;
glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fb);
GLint fb;
glGetIntegerv (GL_FRAMEBUFFER_BINDING_EXT, &fb);
return (GLuint) fb; return (GLuint) fb;
} }
@@ -398,26 +398,22 @@ bool OpenGLFrameBuffer::writePixels (const PixelARGB* data, const Rectangle<int>
glDisable (GL_DEPTH_TEST); glDisable (GL_DEPTH_TEST);
glDisable (GL_BLEND); glDisable (GL_BLEND);
OpenGLTexture tex;
tex.load (data, area.getWidth(), area.getHeight());
#if JUCE_OPENGL_ES #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(); 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); 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()); glDrawTexiOES (area.getX(), area.getY(), 1, area.getWidth(), area.getHeight());
glBindTexture (GL_TEXTURE_2D, 0); glBindTexture (GL_TEXTURE_2D, 0);
} }
#else #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_MIN_FILTER, GL_LINEAR);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_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); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);


+ 2
- 5
modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp View File

@@ -985,11 +985,8 @@ public:
{ {
const Rectangle<int>& clipBounds = clip->getClipBounds(); 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->transparencyLayerAlpha = opacity;
s->cloneClipIfMultiplyReferenced(); s->cloneClipIfMultiplyReferenced();
} }


+ 3
- 3
modules/juce_opengl/opengl/juce_OpenGLHelpers.cpp View File

@@ -703,11 +703,11 @@ OpenGLTextureFromImage::OpenGLTextureFromImage (const Image& image)
: width (image.getWidth()), : width (image.getWidth()),
height (image.getHeight()) 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 else
{ {


+ 70
- 41
modules/juce_opengl/opengl/juce_OpenGLImage.cpp View File

@@ -25,44 +25,62 @@
BEGIN_JUCE_NAMESPACE 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);
}
public:
OpenGLFrameBufferImage (int width, int height)
: ImagePixelData (Image::ARGB, width, height),
pixelStride (4),
lineStride (width * pixelStride)
{
frameBuffer.initialise (width, height);
frameBuffer.clear (Colours::transparentBlack);
}
OpenGLFrameBufferImage::~OpenGLFrameBufferImage() {}
LowLevelGraphicsContext* createLowLevelContext()
{
return new OpenGLRenderer (frameBuffer);
}
LowLevelGraphicsContext* OpenGLFrameBufferImage::createLowLevelContext()
{
return new OpenGLRenderer (frameBuffer);
}
ImageType* createType() const { return new OpenGLImageType(); }
Image::SharedImage* OpenGLFrameBufferImage::clone()
{
OpenGLFrameBufferImage* im = new OpenGLFrameBufferImage (getWidth(), getHeight());
im->incReferenceCount();
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)
{ {
Image newImage (im);
Graphics g (newImage);
g.drawImageAt (Image (this), 0, 0, false);
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;
}
} }
im->resetReferenceCount();
return im;
}
OpenGLFrameBuffer frameBuffer;
Image::ImageType OpenGLFrameBufferImage::getType() const
{
return Image::NativeImage;
}
private:
int pixelStride, lineStride;
namespace OpenGLImageHelpers
{
struct Dummy struct Dummy
{ {
Dummy (OpenGLFrameBuffer&, int, int, int, int) noexcept {} Dummy (OpenGLFrameBuffer&, int, int, int, int) noexcept {}
@@ -145,24 +163,35 @@ namespace OpenGLImageHelpers
HeapBlock<PixelARGB> data; HeapBlock<PixelARGB> data;
WriterType writer; 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 END_JUCE_NAMESPACE

+ 8
- 25
modules/juce_opengl/opengl/juce_OpenGLImage.h View File

@@ -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. framebuffer, allowing a JUCE Image object to wrap a framebuffer.
By creating an Image from an instance of an OpenGLFrameBufferImage, By creating an Image from an instance of an OpenGLFrameBufferImage,
you can then use a Graphics object to draw into the framebuffer using normal you can then use a Graphics object to draw into the framebuffer using normal
JUCE 2D operations. 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: 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__ #endif // __JUCE_OPENGLIMAGE_JUCEHEADER__

Loading…
Cancel
Save