Implement Array, Cubemap, and Volume texture types (issue #1111).

- Add love.graphics.newArrayImage, newCubeImage, and newVolumeImage.
- Add love.graphics.newCanvas(w, h, layers) and newCanvas(w, h, layers, settings). Add ‘type’ field to the settings table of newCanvas.

- Add new love.graphics.setCanvas variants: setCanvas(canvas, slice), and setCanvas(canvastable) where canvastable is in the format: {{canvas1, layer=2}, {canvas2, face=5}}

- Add Texture:getTextureType, getDepth, getLayerCount, getMipmapCount, and getFormat.

- Remove Image:getData and Image:refresh.
- Add Image:replacePixels(imagedata [, slice] [, mipmap]).

- Update Canvas:newImageData to accept a slice argument.

- Add love.image.newCubeFaces(imagedata).

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2017-02-20 14:58:13 -04:00
parent d70fe5cb89
commit 73fd45558b
91 changed files with 3160 additions and 2003 deletions
+162 -14
View File
@@ -19,6 +19,10 @@
**/
#include "Image.h"
#include "Graphics.h"
// C++
#include <algorithm>
namespace love
{
@@ -29,9 +33,16 @@ love::Type Image::type("Image", &Texture::type);
int Image::imageCount = 0;
Image::Image(const Settings &settings)
: settings(settings)
Image::Image(const Slices &data, const Settings &settings, bool validatedata)
: Texture(data.getTextureType())
, settings(settings)
, data(data)
, mipmapsType(settings.mipmaps ? MIPMAPS_GENERATED : MIPMAPS_NONE)
, sRGB(isGammaCorrect() && !settings.linear)
{
if (validatedata && data.validate() == MIPMAPS_DATA)
mipmapsType = MIPMAPS_DATA;
++imageCount;
}
@@ -40,29 +51,166 @@ Image::~Image()
--imageCount;
}
const Image::Settings &Image::getFlags() const
Image::Slices::Slices(TextureType textype)
: textureType(textype)
{
return settings;
}
bool Image::getConstant(const char *in, SettingType &out)
void Image::Slices::clear()
{
return settingTypes.find(in, out);
data.clear();
}
bool Image::getConstant(SettingType in, const char *&out)
void Image::Slices::set(int slice, int mipmap, love::image::ImageDataBase *d)
{
return settingTypes.find(in, out);
if (textureType == TEXTURE_VOLUME)
{
if (mipmap >= (int) data.size())
data.resize(mipmap + 1);
if (slice >= (int) data[mipmap].size())
data[mipmap].resize(slice + 1);
data[mipmap][slice].set(d);
}
else
{
if (slice >= (int) data.size())
data.resize(slice + 1);
if (mipmap >= (int) data[slice].size())
data[slice].resize(mipmap + 1);
data[slice][mipmap].set(d);
}
}
StringMap<Image::SettingType, Image::SETTING_MAX_ENUM>::Entry Image::settingTypeEntries[] =
love::image::ImageDataBase *Image::Slices::get(int slice, int mipmap) const
{
{ "mipmaps", SETTING_MIPMAPS },
{ "linear", SETTING_LINEAR },
{ "pixeldensity", SETTING_PIXELDENSITY },
};
if (slice < 0 || slice >= getSliceCount(mipmap))
return nullptr;
StringMap<Image::SettingType, Image::SETTING_MAX_ENUM> Image::settingTypes(Image::settingTypeEntries, sizeof(Image::settingTypeEntries));
if (mipmap < 0 || mipmap >= getMipmapCount(slice))
return nullptr;
if (textureType == TEXTURE_VOLUME)
return data[mipmap][slice].get();
else
return data[slice][mipmap].get();
}
void Image::Slices::add(love::image::CompressedImageData *cdata, int startslice, int startmip, bool addallslices, bool addallmips)
{
int slicecount = addallslices ? cdata->getSliceCount() : 1;
int mipcount = addallmips ? cdata->getMipmapCount() : 1;
for (int mip = 0; mip < mipcount; mip++)
{
for (int slice = 0; slice < slicecount; slice++)
set(startslice + slice, startmip + mip, cdata->getSlice(slice, mip));
}
}
int Image::Slices::getSliceCount(int mip) const
{
if (textureType == TEXTURE_VOLUME)
{
if (mip < 0 || mip >= (int) data.size())
return 0;
return (int) data[mip].size();
}
else
return (int) data.size();
}
int Image::Slices::getMipmapCount(int slice) const
{
if (textureType == TEXTURE_VOLUME)
return (int) data.size();
else
{
if (slice < 0 || slice >= (int) data.size())
return 0;
return data[slice].size();
}
}
Image::MipmapsType Image::Slices::validate() const
{
int slicecount = getSliceCount();
int mipcount = getMipmapCount(0);
if (slicecount == 0 || mipcount == 0)
throw love::Exception("At least one ImageData or CompressedImageData is required!");
if (textureType == TEXTURE_CUBE && slicecount != 6)
throw love::Exception("Cube textures must have exactly 6 sides.");
image::ImageDataBase *firstdata = get(0, 0);
int w = firstdata->getWidth();
int h = firstdata->getHeight();
PixelFormat format = firstdata->getFormat();
int expectedmips = Texture::getMipmapCount(w, h);
if (mipcount != expectedmips && mipcount != 1)
throw love::Exception("Image does not have all required mipmap levels (expected %d, got %d)", expectedmips, mipcount);
if (textureType == TEXTURE_CUBE && w != h)
throw love::Exception("Cube images must have equal widths and heights for each cube face.");
int mipw = w;
int miph = h;
int mipslices = slicecount;
for (int mip = 0; mip < mipcount; mip++)
{
if (textureType == TEXTURE_VOLUME)
{
slicecount = getSliceCount(mip);
if (slicecount != mipslices)
throw love::Exception("Invalid number of image data layers in mipmap level %d (expected %d, got %d)", mip+1, mipslices, slicecount);
}
for (int slice = 0; slice < slicecount; slice++)
{
auto slicedata = get(slice, mip);
if (slicedata == nullptr)
throw love::Exception("Missing image data (slice %d, mipmap level %d)", slice+1, mip+1);
int realw = slicedata->getWidth();
int realh = slicedata->getHeight();
if (getMipmapCount(slice) != mipcount)
throw love::Exception("All Image layers must have the same mipmap count.");
if (mipw != realw)
throw love::Exception("Width of image data (slice %d, mipmap level %d) is incorrect (expected %d, got %d)", slice+1, mip+1, mipw, realw);
if (miph != realh)
throw love::Exception("Height of image data (slice %d, mipmap level %d) is incorrect (expected %d, got %d)", slice+1, mip+1, miph, realh);
if (format != slicedata->getFormat())
throw love::Exception("All Image slices and mipmaps must have the same pixel format.");
}
mipw = std::max(mipw / 2, 1);
miph = std::max(miph / 2, 1);
if (textureType == TEXTURE_VOLUME)
mipslices = std::max(mipslices / 2, 1);
}
if (mipcount > 1)
return MIPMAPS_DATA;
else
return MIPMAPS_NONE;
}
} // graphics
} // love