mirror of
https://github.com/love2d/love.git
synced 2026-08-16 16:20:42 +02:00
Add love.graphics.copyTextureToBuffer and copyBufferToTexture.
This commit is contained in:
@@ -42,7 +42,8 @@ ByteData::ByteData(const void *d, size_t size)
|
||||
: size(size)
|
||||
{
|
||||
create();
|
||||
memcpy(data, d, size);
|
||||
if (d != nullptr)
|
||||
memcpy(data, d, size);
|
||||
}
|
||||
|
||||
ByteData::ByteData(void *d, size_t size, bool own)
|
||||
@@ -53,7 +54,8 @@ ByteData::ByteData(void *d, size_t size, bool own)
|
||||
else
|
||||
{
|
||||
create();
|
||||
memcpy(data, d, size);
|
||||
if (d != nullptr)
|
||||
memcpy(data, d, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1076,6 +1076,169 @@ void Graphics::copyBuffer(Buffer *source, Buffer *dest, size_t sourceoffset, siz
|
||||
source->copyTo(dest, sourceoffset, destoffset, size);
|
||||
}
|
||||
|
||||
void Graphics::copyTextureToBuffer(Texture *source, Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth)
|
||||
{
|
||||
if (!capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER])
|
||||
{
|
||||
if (!source->isRenderTarget())
|
||||
throw love::Exception("Copying a non-render target Texture to a Buffer is not supported on this system.");
|
||||
|
||||
if (!capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER])
|
||||
throw love::Exception("Copying a render target Texture to a Buffer is not supported on this system.");
|
||||
}
|
||||
|
||||
PixelFormat format = source->getPixelFormat();
|
||||
|
||||
if (isPixelFormatDepthStencil(format))
|
||||
throw love::Exception("Copying a depth/stencil Texture to a Buffer is not supported.");
|
||||
|
||||
if (!source->isReadable())
|
||||
throw love::Exception("copyTextureToBuffer can only be called on readable Textures.");
|
||||
|
||||
if (dest->getDataUsage() == BUFFERDATAUSAGE_STREAM)
|
||||
throw love::Exception("Buffers created with 'stream' data usage cannot be used as a copy destination.");
|
||||
|
||||
if (isRenderTargetActive(source))
|
||||
throw love::Exception("copyTextureToBuffer cannot be called while the Texture is an active render target.");
|
||||
|
||||
if (mipmap < 0 || mipmap >= source->getMipmapCount())
|
||||
throw love::Exception("Invalid texture mipmap index %d.", mipmap + 1);
|
||||
|
||||
TextureType textype = source->getTextureType();
|
||||
if (slice < 0 || (textype == TEXTURE_CUBE && slice >= 6)
|
||||
|| (textype == TEXTURE_VOLUME && slice >= source->getDepth(mipmap))
|
||||
|| (textype == TEXTURE_2D_ARRAY && slice >= source->getLayerCount()))
|
||||
{
|
||||
throw love::Exception("Invalid texture slice index %d.", slice + 1);
|
||||
}
|
||||
|
||||
int mipw = source->getPixelWidth(mipmap);
|
||||
int miph = source->getPixelHeight(mipmap);
|
||||
|
||||
if (rect.x < 0 || rect.y < 0 || rect.w <= 0 || rect.h <= 0
|
||||
|| (rect.x + rect.w) > mipw || (rect.y + rect.h) > miph)
|
||||
{
|
||||
throw love::Exception("Invalid rectangle dimensions (x=%d, y=%d, w=%d, h=%d) for %dx%d texture.", rect.x, rect.y, rect.w, rect.h, mipw, miph);
|
||||
}
|
||||
|
||||
if (destwidth <= 0)
|
||||
destwidth = rect.w;
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
if (isPixelFormatCompressed(format))
|
||||
{
|
||||
if (destwidth != rect.w) // OpenGL limitation...
|
||||
throw love::Exception("Copying a compressed texture to a buffer cannot use a custom destination width.");
|
||||
|
||||
const PixelFormatInfo &info = getPixelFormatInfo(format);
|
||||
int bw = (int) info.blockWidth;
|
||||
int bh = (int) info.blockHeight;
|
||||
if (rect.x % bw != 0 || rect.y % bh != 0 ||
|
||||
((rect.w % bw != 0 || rect.h % bh != 0) && rect.x + rect.w != source->getPixelWidth(mipmap)))
|
||||
{
|
||||
const char *name = nullptr;
|
||||
love::getConstant(format, name);
|
||||
throw love::Exception("Compressed texture format %s only supports copying a sub-rectangle with offset and dimensions that are a multiple of %d x %d.", name, bw, bh);
|
||||
}
|
||||
|
||||
// Note: this will need to change if destwidth == rect.w restriction
|
||||
// is removed.
|
||||
size = getPixelFormatSliceSize(format, destwidth, rect.h);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not the cleanest, but should work since uncompressed formats always
|
||||
// have 1x1 blocks.
|
||||
int pixels = (rect.h - 1) * destwidth + rect.w;
|
||||
size = getPixelFormatUncompressedRowSize(format, pixels);
|
||||
}
|
||||
|
||||
Range destrange(destoffset, size);
|
||||
|
||||
if (destrange.getMax() >= dest->getSize())
|
||||
throw love::Exception("Buffer copy destination offset and width/height doesn't fit within the destination Buffer.");
|
||||
|
||||
source->copyToBuffer(dest, slice, mipmap, rect, destoffset, destwidth, size);
|
||||
}
|
||||
|
||||
void Graphics::copyBufferToTexture(Buffer *source, Texture *dest, size_t sourceoffset, int sourcewidth, int slice, int mipmap, const Rect &rect)
|
||||
{
|
||||
if (!capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE])
|
||||
throw love::Exception("Copying a Buffer to a Texture is not supported on this system.");
|
||||
|
||||
PixelFormat format = dest->getPixelFormat();
|
||||
|
||||
if (isPixelFormatDepthStencil(format))
|
||||
throw love::Exception("Copying a Buffer to a depth/stencil Texture is not supported.");
|
||||
|
||||
if (!dest->isReadable())
|
||||
throw love::Exception("copyBufferToTexture can only be called on readable Textures.");
|
||||
|
||||
if (isRenderTargetActive(dest))
|
||||
throw love::Exception("copyBufferToTexture cannot be called while the Texture is an active render target.");
|
||||
|
||||
if (mipmap < 0 || mipmap >= dest->getMipmapCount())
|
||||
throw love::Exception("Invalid texture mipmap index %d.", mipmap + 1);
|
||||
|
||||
TextureType textype = dest->getTextureType();
|
||||
if (slice < 0 || (textype == TEXTURE_CUBE && slice >= 6)
|
||||
|| (textype == TEXTURE_VOLUME && slice >= dest->getDepth(mipmap))
|
||||
|| (textype == TEXTURE_2D_ARRAY && slice >= dest->getLayerCount()))
|
||||
{
|
||||
throw love::Exception("Invalid texture slice index %d.", slice + 1);
|
||||
}
|
||||
|
||||
int mipw = dest->getPixelWidth(mipmap);
|
||||
int miph = dest->getPixelHeight(mipmap);
|
||||
|
||||
if (rect.x < 0 || rect.y < 0 || rect.w <= 0 || rect.h <= 0
|
||||
|| (rect.x + rect.w) > mipw || (rect.y + rect.h) > miph)
|
||||
{
|
||||
throw love::Exception("Invalid rectangle dimensions (x=%d, y=%d, w=%d, h=%d) for %dx%d texture.", rect.x, rect.y, rect.w, rect.h, mipw, miph);
|
||||
}
|
||||
|
||||
if (sourcewidth <= 0)
|
||||
sourcewidth = rect.w;
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
if (isPixelFormatCompressed(format))
|
||||
{
|
||||
if (sourcewidth != rect.w) // OpenGL limitation...
|
||||
throw love::Exception("Copying a buffer to a compressed texture cannot use a custom source width.");
|
||||
|
||||
const PixelFormatInfo &info = getPixelFormatInfo(format);
|
||||
int bw = (int) info.blockWidth;
|
||||
int bh = (int) info.blockHeight;
|
||||
if (rect.x % bw != 0 || rect.y % bh != 0 ||
|
||||
((rect.w % bw != 0 || rect.h % bh != 0) && rect.x + rect.w != dest->getPixelWidth(mipmap)))
|
||||
{
|
||||
const char *name = nullptr;
|
||||
love::getConstant(format, name);
|
||||
throw love::Exception("Compressed texture format %s only supports copying a sub-rectangle with offset and dimensions that are a multiple of %d x %d.", name, bw, bh);
|
||||
}
|
||||
|
||||
// Note: this will need to change if sourcewidth == rect.w restriction
|
||||
// is removed.
|
||||
size = getPixelFormatSliceSize(format, sourcewidth, rect.h);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not the cleanest, but should work since uncompressed formats always
|
||||
// have 1x1 blocks.
|
||||
int pixels = (rect.h - 1) * sourcewidth + rect.w;
|
||||
size = getPixelFormatUncompressedRowSize(format, pixels);
|
||||
}
|
||||
|
||||
Range sourcerange(sourceoffset, size);
|
||||
|
||||
if (sourcerange.getMax() >= source->getSize())
|
||||
throw love::Exception("Buffer copy source offset and width/height doesn't fit within the source Buffer.");
|
||||
|
||||
dest->copyFromBuffer(source, sourceoffset, sourcewidth, size, slice, mipmap, rect);
|
||||
}
|
||||
|
||||
void Graphics::dispatchThreadgroups(Shader* shader, int x, int y, int z)
|
||||
{
|
||||
if (!shader->hasStage(SHADERSTAGE_COMPUTE))
|
||||
@@ -1907,6 +2070,9 @@ STRINGMAP_CLASS_BEGIN(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, f
|
||||
{ "instancing", Graphics::FEATURE_INSTANCING },
|
||||
{ "texelbuffer", Graphics::FEATURE_TEXEL_BUFFER },
|
||||
{ "copybuffer", Graphics::FEATURE_COPY_BUFFER },
|
||||
{ "copybuffertotexture", Graphics::FEATURE_COPY_BUFFER_TO_TEXTURE },
|
||||
{ "copytexturetobuffer", Graphics::FEATURE_COPY_TEXTURE_TO_BUFFER },
|
||||
{ "copyrendertargettobuffer", Graphics::FEATURE_COPY_RENDER_TARGET_TO_BUFFER },
|
||||
}
|
||||
STRINGMAP_CLASS_END(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, feature)
|
||||
|
||||
|
||||
@@ -145,6 +145,9 @@ public:
|
||||
FEATURE_INSTANCING,
|
||||
FEATURE_TEXEL_BUFFER,
|
||||
FEATURE_COPY_BUFFER,
|
||||
FEATURE_COPY_BUFFER_TO_TEXTURE,
|
||||
FEATURE_COPY_TEXTURE_TO_BUFFER,
|
||||
FEATURE_COPY_RENDER_TARGET_TO_BUFFER,
|
||||
FEATURE_MAX_ENUM
|
||||
};
|
||||
|
||||
@@ -674,6 +677,8 @@ public:
|
||||
void captureScreenshot(const ScreenshotInfo &info);
|
||||
|
||||
void copyBuffer(Buffer *source, Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size);
|
||||
void copyTextureToBuffer(Texture *source, Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth);
|
||||
void copyBufferToTexture(Buffer *source, Texture *dest, size_t sourceoffset, int sourcewidth, int slice, int mipmap, const Rect &rect);
|
||||
|
||||
void dispatchThreadgroups(Shader* shader, int x, int y, int z);
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace graphics
|
||||
{
|
||||
|
||||
class Graphics;
|
||||
class Buffer;
|
||||
|
||||
enum TextureType
|
||||
{
|
||||
@@ -246,6 +247,9 @@ public:
|
||||
|
||||
love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect);
|
||||
|
||||
virtual void copyFromBuffer(Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect) = 0;
|
||||
virtual void copyToBuffer(Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size) = 0;
|
||||
|
||||
virtual ptrdiff_t getRenderTargetHandle() const = 0;
|
||||
|
||||
TextureType getTextureType() const;
|
||||
|
||||
@@ -1640,7 +1640,10 @@ void Graphics::initCapabilities()
|
||||
capabilities.features[FEATURE_INSTANCING] = gl.isInstancingSupported();
|
||||
capabilities.features[FEATURE_TEXEL_BUFFER] = gl.isBufferUsageSupported(BUFFERUSAGE_TEXEL);
|
||||
capabilities.features[FEATURE_COPY_BUFFER] = gl.isCopyBufferSupported();
|
||||
static_assert(FEATURE_MAX_ENUM == 12, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
|
||||
capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE] = gl.isCopyBufferToTextureSupported();
|
||||
capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = gl.isCopyTextureToBufferSupported();
|
||||
capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = gl.isCopyRenderTargetToBufferSupported();
|
||||
static_assert(FEATURE_MAX_ENUM == 15, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
|
||||
|
||||
capabilities.limits[LIMIT_POINT_SIZE] = gl.getMaxPointSize();
|
||||
capabilities.limits[LIMIT_TEXTURE_SIZE] = gl.getMax2DTextureSize();
|
||||
|
||||
@@ -1530,6 +1530,24 @@ bool OpenGL::isCopyBufferSupported() const
|
||||
return GLAD_VERSION_3_1 || GLAD_ES_VERSION_3_0;
|
||||
}
|
||||
|
||||
bool OpenGL::isCopyBufferToTextureSupported() const
|
||||
{
|
||||
// Requires pixel unpack buffer binding support.
|
||||
return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0;
|
||||
}
|
||||
|
||||
bool OpenGL::isCopyTextureToBufferSupported() const
|
||||
{
|
||||
// Requires glGetTextureSubImage support.
|
||||
return GLAD_VERSION_4_5;
|
||||
}
|
||||
|
||||
bool OpenGL::isCopyRenderTargetToBufferSupported() const
|
||||
{
|
||||
// Requires pixel pack buffer binding support.
|
||||
return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0;
|
||||
}
|
||||
|
||||
int OpenGL::getMax2DTextureSize() const
|
||||
{
|
||||
return std::max(max2DTextureSize, 1);
|
||||
|
||||
@@ -372,6 +372,9 @@ public:
|
||||
bool isBaseVertexSupported() const;
|
||||
bool isMultiFormatMRTSupported() const;
|
||||
bool isCopyBufferSupported() const;
|
||||
bool isCopyBufferToTextureSupported() const;
|
||||
bool isCopyTextureToBufferSupported() const;
|
||||
bool isCopyRenderTargetToBufferSupported() const;
|
||||
|
||||
/**
|
||||
* Returns the maximum supported width or height of a texture.
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "graphics/Graphics.h"
|
||||
#include "Graphics.h"
|
||||
#include "Buffer.h"
|
||||
#include "common/int.h"
|
||||
|
||||
// STD
|
||||
@@ -524,6 +525,75 @@ void Texture::readbackImageData(love::image::ImageData *data, int slice, int mip
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo);
|
||||
}
|
||||
|
||||
void Texture::copyFromBuffer(love::graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect)
|
||||
{
|
||||
// Higher level code does validation.
|
||||
|
||||
GLuint glbuffer = (GLuint) source->getHandle();
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, glbuffer);
|
||||
|
||||
if (!isCompressed()) // Not supported in GL with compressed textures...
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, sourcewidth);
|
||||
|
||||
// glTexSubImage and friends copy from the active pixel_unpack_buffer by
|
||||
// treating the pointer as a byte offset.
|
||||
const uint8 *byteoffset = (const uint8 *)(ptrdiff_t)sourceoffset;
|
||||
uploadByteData(format, byteoffset, size, mipmap, slice, rect);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
void Texture::copyToBuffer(love::graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size)
|
||||
{
|
||||
// Higher level code does validation.
|
||||
|
||||
GLuint glbuffer = (GLuint) dest->getHandle();
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, glbuffer);
|
||||
|
||||
if (!isCompressed()) // Not supported in GL with compressed textures...
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, destwidth);
|
||||
|
||||
gl.bindTextureToUnit(this, 0, false);
|
||||
|
||||
bool isSRGB = false;
|
||||
OpenGL::TextureFormat fmt = gl.convertPixelFormat(format, false, isSRGB);
|
||||
|
||||
// glTexSubImage and friends copy from the active pixel_unpack_buffer by
|
||||
// treating the pointer as a byte offset.
|
||||
uint8 *byteoffset = (uint8 *)(ptrdiff_t)destoffset;
|
||||
|
||||
if (GLAD_VERSION_4_5)
|
||||
{
|
||||
if (isCompressed())
|
||||
glGetCompressedTextureSubImage(texture, mipmap, rect.x, rect.y, slice, rect.w, rect.h, 1, size, byteoffset);
|
||||
else
|
||||
glGetTextureSubImage(texture, mipmap, rect.x, rect.y, slice, rect.w, rect.h, 1, fmt.externalformat, fmt.type, size, byteoffset);
|
||||
}
|
||||
else if (fbo)
|
||||
{
|
||||
GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getFBO());
|
||||
|
||||
if (slice > 0 || mipmap > 0)
|
||||
{
|
||||
int layer = texType == TEXTURE_CUBE ? 0 : slice;
|
||||
int face = texType == TEXTURE_CUBE ? slice : 0;
|
||||
gl.framebufferTexture(GL_COLOR_ATTACHMENT0, texType, texture, mipmap, layer, face);
|
||||
}
|
||||
|
||||
glReadPixels(rect.x, rect.y, rect.w, rect.h, fmt.externalformat, fmt.type, byteoffset);
|
||||
|
||||
if (slice > 0 || mipmap > 0)
|
||||
gl.framebufferTexture(GL_COLOR_ATTACHMENT0, texType, texture, 0, 0, 0);
|
||||
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo);
|
||||
}
|
||||
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
void Texture::setSamplerState(const SamplerState &s)
|
||||
{
|
||||
if (s.depthSampleMode.hasValue && !gl.isDepthCompareSampleSupported())
|
||||
|
||||
@@ -46,6 +46,9 @@ public:
|
||||
bool loadVolatile() override;
|
||||
void unloadVolatile() override;
|
||||
|
||||
void copyFromBuffer(love::graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect) override;
|
||||
void copyToBuffer(love::graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size) override;
|
||||
|
||||
void setSamplerState(const SamplerState &s) override;
|
||||
|
||||
ptrdiff_t getHandle() const override;
|
||||
|
||||
@@ -3353,6 +3353,70 @@ int w_copyBuffer(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_copyBufferToTexture(lua_State *L)
|
||||
{
|
||||
Buffer *source = luax_checkbuffer(L, 1);
|
||||
Texture *dest = luax_checktexture(L, 2);
|
||||
|
||||
ptrdiff_t sourceoffset = luaL_optinteger(L, 3, 0);
|
||||
if (sourceoffset < 0)
|
||||
return luaL_error(L, "copyBufferToTexture source offset cannot be negative.");
|
||||
|
||||
int sourcewidth = (int) luaL_optinteger(L, 4, 0);
|
||||
|
||||
int slice = 0;
|
||||
int mipmap = 0;
|
||||
|
||||
if (dest->getTextureType() != TEXTURE_2D)
|
||||
slice = (int) luaL_checkinteger(L, 5) - 1;
|
||||
|
||||
mipmap = (int) luaL_optinteger(L, 6, 1) - 1;
|
||||
|
||||
Rect rect = {0, 0, dest->getPixelWidth(mipmap), dest->getPixelHeight(mipmap)};
|
||||
if (!lua_isnoneornil(L, 7))
|
||||
{
|
||||
rect.x = (int) luaL_checkinteger(L, 7);
|
||||
rect.y = (int) luaL_checkinteger(L, 8);
|
||||
rect.w = (int) luaL_checkinteger(L, 9);
|
||||
rect.h = (int) luaL_checkinteger(L, 10);
|
||||
}
|
||||
|
||||
luax_catchexcept(L, [&](){ instance()->copyBufferToTexture(source, dest, sourceoffset, sourcewidth, slice, mipmap, rect); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_copyTextureToBuffer(lua_State *L)
|
||||
{
|
||||
Texture *source = luax_checktexture(L, 1);
|
||||
Buffer *dest = luax_checkbuffer(L, 2);
|
||||
|
||||
int slice = 0;
|
||||
int mipmap = 0;
|
||||
|
||||
if (source->getTextureType() != TEXTURE_2D)
|
||||
slice = (int) luaL_checkinteger(L, 3) - 1;
|
||||
|
||||
mipmap = (int) luaL_optinteger(L, 4, 1) - 1;
|
||||
|
||||
Rect rect = {0, 0, source->getPixelWidth(mipmap), source->getPixelHeight(mipmap)};
|
||||
if (!lua_isnoneornil(L, 5))
|
||||
{
|
||||
rect.x = (int) luaL_checkinteger(L, 5);
|
||||
rect.y = (int) luaL_checkinteger(L, 6);
|
||||
rect.w = (int) luaL_checkinteger(L, 7);
|
||||
rect.h = (int) luaL_checkinteger(L, 8);
|
||||
}
|
||||
|
||||
ptrdiff_t destoffset = luaL_optinteger(L, 9, 0);
|
||||
if (destoffset < 0)
|
||||
return luaL_error(L, "copyTextureToBuffer dest offset cannot be negative.");
|
||||
|
||||
int destwidth = (int) luaL_optinteger(L, 10, 0);
|
||||
|
||||
luax_catchexcept(L, [&](){ instance()->copyTextureToBuffer(source, dest, slice, mipmap, rect, destoffset, destwidth); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_flushBatch(lua_State *)
|
||||
{
|
||||
instance()->flushBatchedDraws();
|
||||
@@ -3553,6 +3617,8 @@ static const luaL_Reg functions[] =
|
||||
{ "dispatchThreadgroups", w_dispatchThreadgroups },
|
||||
|
||||
{ "copyBuffer", w_copyBuffer },
|
||||
{ "copyBufferToTexture", w_copyBufferToTexture },
|
||||
{ "copyTextureToBuffer", w_copyTextureToBuffer },
|
||||
|
||||
{ "isCreated", w_isCreated },
|
||||
{ "isActive", w_isActive },
|
||||
|
||||
@@ -390,13 +390,13 @@ int w_Texture_newImageData(lua_State *L)
|
||||
|
||||
int slice = 0;
|
||||
int mipmap = 0;
|
||||
Rect rect = {0, 0, t->getPixelWidth(), t->getPixelHeight()};
|
||||
|
||||
if (t->getTextureType() != TEXTURE_2D)
|
||||
slice = (int) luaL_checkinteger(L, 2) - 1;
|
||||
|
||||
mipmap = (int) luaL_optinteger(L, 3, 1) - 1;
|
||||
|
||||
Rect rect = {0, 0, t->getPixelWidth(mipmap), t->getPixelHeight(mipmap)};
|
||||
if (!lua_isnoneornil(L, 4))
|
||||
{
|
||||
rect.x = (int) luaL_checkinteger(L, 4);
|
||||
|
||||
Reference in New Issue
Block a user