mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
Merge branch '12.0-development' into metal
This commit is contained in:
@@ -118,6 +118,10 @@ Filesystem::Filesystem()
|
||||
|
||||
Filesystem::~Filesystem()
|
||||
{
|
||||
#ifdef LOVE_ANDROID
|
||||
love::android::deinitializeVirtualArchive();
|
||||
#endif
|
||||
|
||||
if (PHYSFS_isInit())
|
||||
PHYSFS_deinit();
|
||||
}
|
||||
@@ -232,30 +236,56 @@ bool Filesystem::setSource(const char *source)
|
||||
if (!love::android::createStorageDirectories())
|
||||
SDL_Log("Error creating storage directories!");
|
||||
|
||||
new_search_path = love::android::getSelectedGameFile();
|
||||
new_search_path = "";
|
||||
|
||||
// try mounting first, if that fails, load to memory and mount
|
||||
if (!PHYSFS_mount(new_search_path.c_str(), nullptr, 1))
|
||||
PHYSFS_Io *gameLoveIO;
|
||||
bool hasFusedGame = love::android::checkFusedGame((void **) &gameLoveIO);
|
||||
|
||||
if (hasFusedGame)
|
||||
{
|
||||
// PHYSFS cannot yet mount a zip file inside an .apk
|
||||
SDL_Log("Mounting %s did not work. Loading to memory.",
|
||||
new_search_path.c_str());
|
||||
char* game_archive_ptr = NULL;
|
||||
size_t game_archive_size = 0;
|
||||
if (!love::android::loadGameArchiveToMemory(
|
||||
new_search_path.c_str(), &game_archive_ptr,
|
||||
&game_archive_size))
|
||||
if (gameLoveIO)
|
||||
{
|
||||
SDL_Log("Failure memory loading archive %s", new_search_path.c_str());
|
||||
return false;
|
||||
// Actually we should just be able to mount gameLoveIO, but that's experimental.
|
||||
gameLoveIO->destroy(gameLoveIO);
|
||||
goto oldschool;
|
||||
}
|
||||
if (!PHYSFS_mountMemory(
|
||||
game_archive_ptr, game_archive_size,
|
||||
love::android::freeGameArchiveMemory, "archive.zip", "/", 0))
|
||||
else
|
||||
{
|
||||
SDL_Log("Failure mounting in-memory archive.");
|
||||
love::android::freeGameArchiveMemory(game_archive_ptr);
|
||||
return false;
|
||||
if (!love::android::initializeVirtualArchive())
|
||||
{
|
||||
SDL_Log("Unable to mount AAsset: %s", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
oldschool:
|
||||
new_search_path = love::android::getSelectedGameFile();
|
||||
|
||||
// try mounting first, if that fails, load to memory and mount
|
||||
if (!PHYSFS_mount(new_search_path.c_str(), nullptr, 1))
|
||||
{
|
||||
// PHYSFS cannot yet mount a zip file inside an .apk
|
||||
SDL_Log("Mounting %s did not work. Loading to memory.",
|
||||
new_search_path.c_str());
|
||||
char* game_archive_ptr = NULL;
|
||||
size_t game_archive_size = 0;
|
||||
if (!love::android::loadGameArchiveToMemory(
|
||||
new_search_path.c_str(), &game_archive_ptr,
|
||||
&game_archive_size))
|
||||
{
|
||||
SDL_Log("Failure memory loading archive %s", new_search_path.c_str());
|
||||
return false;
|
||||
}
|
||||
if (!PHYSFS_mountMemory(
|
||||
game_archive_ptr, game_archive_size,
|
||||
love::android::freeGameArchiveMemory, "archive.zip", "/", 0))
|
||||
{
|
||||
SDL_Log("Failure mounting in-memory archive.");
|
||||
love::android::freeGameArchiveMemory(game_archive_ptr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -33,8 +33,8 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
|
||||
: arrayLength(0)
|
||||
, arrayStride(0)
|
||||
, size(size)
|
||||
, typeFlags(settings.typeFlags)
|
||||
, usage(settings.usage)
|
||||
, usageFlags(settings.usageFlags)
|
||||
, dataUsage(settings.dataUsage)
|
||||
, mapped(false)
|
||||
{
|
||||
if (size == 0 && arraylength == 0)
|
||||
@@ -46,10 +46,11 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
|
||||
const auto &caps = gfx->getCapabilities();
|
||||
bool supportsGLSL3 = caps.features[Graphics::FEATURE_GLSL3];
|
||||
|
||||
bool indexbuffer = settings.typeFlags & TYPEFLAG_INDEX;
|
||||
bool vertexbuffer = settings.typeFlags & TYPEFLAG_VERTEX;
|
||||
bool texelbuffer = settings.typeFlags & TYPEFLAG_TEXEL;
|
||||
bool storagebuffer = settings.typeFlags & TYPEFLAG_SHADER_STORAGE;
|
||||
bool indexbuffer = settings.usageFlags & BUFFERUSAGEFLAG_INDEX;
|
||||
bool vertexbuffer = settings.usageFlags & BUFFERUSAGEFLAG_VERTEX;
|
||||
bool texelbuffer = settings.usageFlags & BUFFERUSAGEFLAG_TEXEL;
|
||||
bool storagebuffer = settings.usageFlags & BUFFERUSAGEFLAG_SHADER_STORAGE;
|
||||
bool copydest = settings.usageFlags & BUFFERUSAGEFLAG_COPY_DEST;
|
||||
|
||||
if (!indexbuffer && !vertexbuffer && !texelbuffer && !storagebuffer)
|
||||
throw love::Exception("Buffer must be created with at least one buffer type (index, vertex, texel, or shaderstorage).");
|
||||
@@ -60,6 +61,9 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
|
||||
if (storagebuffer && !caps.features[Graphics::FEATURE_GLSL4])
|
||||
throw love::Exception("Shader Storage buffers are not supported on this system (GLSL 4 support is necessary.)");
|
||||
|
||||
if (copydest && dataUsage == BUFFERDATAUSAGE_STREAM)
|
||||
throw love::Exception("Buffers created with 'stream' data usage cannot be used as a copy destination.");
|
||||
|
||||
size_t offset = 0;
|
||||
size_t stride = 0;
|
||||
size_t structurealignment = 1;
|
||||
|
||||
@@ -55,16 +55,6 @@ public:
|
||||
MAP_WRITE_INVALIDATE,
|
||||
};
|
||||
|
||||
enum TypeFlags
|
||||
{
|
||||
TYPEFLAG_NONE = 0,
|
||||
TYPEFLAG_VERTEX = 1 << BUFFERTYPE_VERTEX,
|
||||
TYPEFLAG_INDEX = 1 << BUFFERTYPE_INDEX,
|
||||
TYPEFLAG_UNIFORM = 1 << BUFFERTYPE_UNIFORM,
|
||||
TYPEFLAG_TEXEL = 1 << BUFFERTYPE_TEXEL,
|
||||
TYPEFLAG_SHADER_STORAGE = 1 << BUFFERTYPE_SHADER_STORAGE,
|
||||
};
|
||||
|
||||
struct DataDeclaration
|
||||
{
|
||||
std::string name;
|
||||
@@ -95,13 +85,13 @@ public:
|
||||
|
||||
struct Settings
|
||||
{
|
||||
TypeFlags typeFlags;
|
||||
BufferUsage usage;
|
||||
BufferUsageFlags usageFlags;
|
||||
BufferDataUsage dataUsage;
|
||||
bool zeroInitialize;
|
||||
|
||||
Settings(uint32 typeflags, BufferUsage usage)
|
||||
: typeFlags((TypeFlags)typeflags)
|
||||
, usage(usage)
|
||||
Settings(uint32 usageflags, BufferDataUsage dataUsage)
|
||||
: usageFlags((BufferUsageFlags)usageflags)
|
||||
, dataUsage(dataUsage)
|
||||
, zeroInitialize(false)
|
||||
{}
|
||||
};
|
||||
@@ -110,8 +100,8 @@ public:
|
||||
virtual ~Buffer();
|
||||
|
||||
size_t getSize() const { return size; }
|
||||
TypeFlags getTypeFlags() const { return typeFlags; }
|
||||
BufferUsage getUsage() const { return usage; }
|
||||
BufferUsageFlags getUsageFlags() const { return usageFlags; }
|
||||
BufferDataUsage getDataUsage() const { return dataUsage; }
|
||||
bool isMapped() const { return mapped; }
|
||||
|
||||
size_t getArrayLength() const { return arrayLength; }
|
||||
@@ -137,6 +127,11 @@ public:
|
||||
*/
|
||||
virtual void fill(size_t offset, size_t size, const void *data) = 0;
|
||||
|
||||
/**
|
||||
* Copy a portion of this Buffer's data to another buffer, using the GPU.
|
||||
**/
|
||||
virtual void copyTo(Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Texel buffers may use an additional texture handle as well as a buffer
|
||||
* handle.
|
||||
@@ -174,11 +169,11 @@ protected:
|
||||
// The size of the buffer, in bytes.
|
||||
size_t size;
|
||||
|
||||
// The type of the buffer object.
|
||||
TypeFlags typeFlags;
|
||||
// Bit flags describing how the buffer can be used.
|
||||
BufferUsageFlags usageFlags;
|
||||
|
||||
// Usage hint. GL_[DYNAMIC, STATIC, STREAM]_DRAW.
|
||||
BufferUsage usage;
|
||||
BufferDataUsage dataUsage;
|
||||
|
||||
bool mapped;
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ void Graphics::createQuadIndexBuffer()
|
||||
|
||||
size_t size = sizeof(uint16) * (LOVE_UINT16_MAX / 4) * 6;
|
||||
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_INDEX, BUFFERUSAGE_STATIC);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, BUFFERDATAUSAGE_STATIC);
|
||||
quadIndexBuffer = newBuffer(settings, DATAFORMAT_UINT16, nullptr, size, 0);
|
||||
|
||||
Buffer::Mapper map(*quadIndexBuffer);
|
||||
@@ -239,7 +239,7 @@ Video *Graphics::newVideo(love::video::VideoStream *stream, float dpiscale)
|
||||
return new Video(this, stream, dpiscale);
|
||||
}
|
||||
|
||||
love::graphics::SpriteBatch *Graphics::newSpriteBatch(Texture *texture, int size, BufferUsage usage)
|
||||
love::graphics::SpriteBatch *Graphics::newSpriteBatch(Texture *texture, int size, BufferDataUsage usage)
|
||||
{
|
||||
return new SpriteBatch(this, texture, size, usage);
|
||||
}
|
||||
@@ -330,12 +330,12 @@ Buffer *Graphics::newBuffer(const Buffer::Settings &settings, DataFormat format,
|
||||
return newBuffer(settings, dataformat, data, size, arraylength);
|
||||
}
|
||||
|
||||
Mesh *Graphics::newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferUsage usage)
|
||||
Mesh *Graphics::newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferDataUsage usage)
|
||||
{
|
||||
return new Mesh(this, vertexformat, vertexcount, drawmode, usage);
|
||||
}
|
||||
|
||||
Mesh *Graphics::newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferUsage usage)
|
||||
Mesh *Graphics::newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferDataUsage usage)
|
||||
{
|
||||
return new Mesh(this, vertexformat, data, datasize, drawmode, usage);
|
||||
}
|
||||
@@ -1082,6 +1082,32 @@ void Graphics::captureScreenshot(const ScreenshotInfo &info)
|
||||
pendingScreenshotCallbacks.push_back(info);
|
||||
}
|
||||
|
||||
void Graphics::copyBuffer(Buffer *source, Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)
|
||||
{
|
||||
if (!capabilities.features[FEATURE_COPY_BUFFER])
|
||||
throw love::Exception("Buffer copying is not supported on this system.");
|
||||
|
||||
if (!(source->getUsageFlags() & BUFFERUSAGEFLAG_COPY_SOURCE))
|
||||
throw love::Exception("Copy source buffer must be created with the copysource flag.");
|
||||
|
||||
if (!(dest->getUsageFlags() & BUFFERUSAGEFLAG_COPY_DEST))
|
||||
throw love::Exception("Copy destination buffer must be created with the copydest flag.");
|
||||
|
||||
Range sourcerange(sourceoffset, size);
|
||||
Range destrange(destoffset, size);
|
||||
|
||||
if (sourcerange.getMax() >= source->getSize())
|
||||
throw love::Exception("Buffer copy source offset and size doesn't fit within the source Buffer's size.");
|
||||
|
||||
if (destrange.getMax() >= dest->getSize())
|
||||
throw love::Exception("Buffer copy destination offset and size doesn't fit within the destination buffer's size.");
|
||||
|
||||
if (source == dest && sourcerange.intersects(destrange))
|
||||
throw love::Exception("Copying a portion of a buffer to the same buffer requires non-overlapping source and destination offsets.");
|
||||
|
||||
source->copyTo(dest, sourceoffset, destoffset, size);
|
||||
}
|
||||
|
||||
Graphics::BatchedVertexData Graphics::requestBatchedDraw(const BatchedDrawCommand &cmd)
|
||||
{
|
||||
BatchedDrawState &state = batchedDrawState;
|
||||
@@ -1155,11 +1181,14 @@ Graphics::BatchedVertexData Graphics::requestBatchedDraw(const BatchedDrawComman
|
||||
state.standardShaderType = cmd.standardShaderType;
|
||||
}
|
||||
|
||||
if (state.vertexCount == 0 && Shader::isDefaultActive())
|
||||
Shader::attachDefault(state.standardShaderType);
|
||||
if (state.vertexCount == 0)
|
||||
{
|
||||
if (Shader::isDefaultActive())
|
||||
Shader::attachDefault(state.standardShaderType);
|
||||
|
||||
if (state.vertexCount == 0 && Shader::current != nullptr && cmd.texture != nullptr)
|
||||
Shader::current->checkMainTexture(cmd.texture);
|
||||
if (Shader::current != nullptr)
|
||||
Shader::current->validateDrawState(cmd.primitiveMode, cmd.texture);
|
||||
}
|
||||
|
||||
if (shouldresize)
|
||||
{
|
||||
@@ -1168,14 +1197,14 @@ Graphics::BatchedVertexData Graphics::requestBatchedDraw(const BatchedDrawComman
|
||||
if (state.vb[i]->getSize() < buffersizes[i])
|
||||
{
|
||||
delete state.vb[i];
|
||||
state.vb[i] = newStreamBuffer(BUFFERTYPE_VERTEX, buffersizes[i]);
|
||||
state.vb[i] = newStreamBuffer(BUFFERUSAGE_VERTEX, buffersizes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.indexBuffer->getSize() < buffersizes[2])
|
||||
{
|
||||
delete state.indexBuffer;
|
||||
state.indexBuffer = newStreamBuffer(BUFFERTYPE_INDEX, buffersizes[2]);
|
||||
state.indexBuffer = newStreamBuffer(BUFFERUSAGE_INDEX, buffersizes[2]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1367,6 +1396,7 @@ void Graphics::points(const Vector2 *positions, const Colorf *colors, size_t num
|
||||
cmd.formats[0] = getSinglePositionFormat(is2D);
|
||||
cmd.formats[1] = CommonFormat::RGBAub;
|
||||
cmd.vertexCount = (int) numpoints;
|
||||
cmd.standardShaderType = Shader::STANDARD_POINTS;
|
||||
|
||||
BatchedVertexData data = requestBatchedDraw(cmd);
|
||||
|
||||
@@ -1835,179 +1865,74 @@ Vector2 Graphics::inverseTransformPoint(Vector2 point)
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constants.
|
||||
**/
|
||||
|
||||
bool Graphics::getConstant(const char *in, DrawMode &out)
|
||||
STRINGMAP_CLASS_BEGIN(Graphics, Graphics::DrawMode, Graphics::DRAW_MAX_ENUM, drawMode)
|
||||
{
|
||||
return drawModes.find(in, out);
|
||||
{ "line", Graphics::DRAW_LINE },
|
||||
{ "fill", Graphics::DRAW_FILL },
|
||||
}
|
||||
STRINGMAP_CLASS_END(Graphics, Graphics::DrawMode, Graphics::DRAW_MAX_ENUM, drawMode)
|
||||
|
||||
bool Graphics::getConstant(DrawMode in, const char *&out)
|
||||
STRINGMAP_CLASS_BEGIN(Graphics, Graphics::ArcMode, Graphics::ARC_MAX_ENUM, arcMode)
|
||||
{
|
||||
return drawModes.find(in, out);
|
||||
{ "open", Graphics::ARC_OPEN },
|
||||
{ "closed", Graphics::ARC_CLOSED },
|
||||
{ "pie", Graphics::ARC_PIE },
|
||||
}
|
||||
STRINGMAP_CLASS_END(Graphics, Graphics::ArcMode, Graphics::ARC_MAX_ENUM, arcMode)
|
||||
|
||||
std::vector<std::string> Graphics::getConstants(DrawMode)
|
||||
STRINGMAP_CLASS_BEGIN(Graphics, Graphics::LineStyle, Graphics::LINE_MAX_ENUM, lineStyle)
|
||||
{
|
||||
return drawModes.getNames();
|
||||
{ "smooth", Graphics::LINE_SMOOTH },
|
||||
{ "rough", Graphics::LINE_ROUGH }
|
||||
}
|
||||
STRINGMAP_CLASS_END(Graphics, Graphics::LineStyle, Graphics::LINE_MAX_ENUM, lineStyle)
|
||||
|
||||
bool Graphics::getConstant(const char *in, ArcMode &out)
|
||||
STRINGMAP_CLASS_BEGIN(Graphics, Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM, lineJoin)
|
||||
{
|
||||
return arcModes.find(in, out);
|
||||
{ "none", Graphics::LINE_JOIN_NONE },
|
||||
{ "miter", Graphics::LINE_JOIN_MITER },
|
||||
{ "bevel", Graphics::LINE_JOIN_BEVEL }
|
||||
}
|
||||
STRINGMAP_CLASS_END(Graphics, Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM, lineJoin)
|
||||
|
||||
bool Graphics::getConstant(ArcMode in, const char *&out)
|
||||
STRINGMAP_CLASS_BEGIN(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, feature)
|
||||
{
|
||||
return arcModes.find(in, out);
|
||||
{ "multirendertargetformats", Graphics::FEATURE_MULTI_RENDER_TARGET_FORMATS },
|
||||
{ "clampzero", Graphics::FEATURE_CLAMP_ZERO },
|
||||
{ "blendminmax", Graphics::FEATURE_BLEND_MINMAX },
|
||||
{ "lighten", Graphics::FEATURE_LIGHTEN },
|
||||
{ "fullnpot", Graphics::FEATURE_FULL_NPOT },
|
||||
{ "pixelshaderhighp", Graphics::FEATURE_PIXEL_SHADER_HIGHP },
|
||||
{ "shaderderivatives", Graphics::FEATURE_SHADER_DERIVATIVES },
|
||||
{ "glsl3", Graphics::FEATURE_GLSL3 },
|
||||
{ "glsl4", Graphics::FEATURE_GLSL4 },
|
||||
{ "instancing", Graphics::FEATURE_INSTANCING },
|
||||
{ "texelbuffer", Graphics::FEATURE_TEXEL_BUFFER },
|
||||
{ "copybuffer", Graphics::FEATURE_COPY_BUFFER },
|
||||
}
|
||||
STRINGMAP_CLASS_END(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, feature)
|
||||
|
||||
std::vector<std::string> Graphics::getConstants(ArcMode)
|
||||
STRINGMAP_CLASS_BEGIN(Graphics, Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM, systemLimit)
|
||||
{
|
||||
return arcModes.getNames();
|
||||
{ "pointsize", Graphics::LIMIT_POINT_SIZE },
|
||||
{ "texturesize", Graphics::LIMIT_TEXTURE_SIZE },
|
||||
{ "texturelayers", Graphics::LIMIT_TEXTURE_LAYERS },
|
||||
{ "volumetexturesize", Graphics::LIMIT_VOLUME_TEXTURE_SIZE },
|
||||
{ "cubetexturesize", Graphics::LIMIT_CUBE_TEXTURE_SIZE },
|
||||
{ "texelbuffersize", Graphics::LIMIT_TEXEL_BUFFER_SIZE },
|
||||
{ "shaderstoragebuffersize", Graphics::LIMIT_SHADER_STORAGE_BUFFER_SIZE },
|
||||
{ "rendertargets", Graphics::LIMIT_RENDER_TARGETS },
|
||||
{ "texturemsaa", Graphics::LIMIT_TEXTURE_MSAA },
|
||||
{ "anisotropy", Graphics::LIMIT_ANISOTROPY },
|
||||
}
|
||||
STRINGMAP_CLASS_END(Graphics, Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM, systemLimit)
|
||||
|
||||
bool Graphics::getConstant(const char *in, LineStyle &out)
|
||||
STRINGMAP_CLASS_BEGIN(Graphics, Graphics::StackType, Graphics::STACK_MAX_ENUM, stackType)
|
||||
{
|
||||
return lineStyles.find(in, out);
|
||||
{ "all", Graphics::STACK_ALL },
|
||||
{ "transform", Graphics::STACK_TRANSFORM },
|
||||
}
|
||||
|
||||
bool Graphics::getConstant(LineStyle in, const char *&out)
|
||||
{
|
||||
return lineStyles.find(in, out);
|
||||
}
|
||||
|
||||
std::vector<std::string> Graphics::getConstants(LineStyle)
|
||||
{
|
||||
return lineStyles.getNames();
|
||||
}
|
||||
|
||||
bool Graphics::getConstant(const char *in, LineJoin &out)
|
||||
{
|
||||
return lineJoins.find(in, out);
|
||||
}
|
||||
|
||||
bool Graphics::getConstant(LineJoin in, const char *&out)
|
||||
{
|
||||
return lineJoins.find(in, out);
|
||||
}
|
||||
|
||||
std::vector<std::string> Graphics::getConstants(LineJoin)
|
||||
{
|
||||
return lineJoins.getNames();
|
||||
}
|
||||
|
||||
bool Graphics::getConstant(const char *in, Feature &out)
|
||||
{
|
||||
return features.find(in, out);
|
||||
}
|
||||
|
||||
bool Graphics::getConstant(Feature in, const char *&out)
|
||||
{
|
||||
return features.find(in, out);
|
||||
}
|
||||
|
||||
bool Graphics::getConstant(const char *in, SystemLimit &out)
|
||||
{
|
||||
return systemLimits.find(in, out);
|
||||
}
|
||||
|
||||
bool Graphics::getConstant(SystemLimit in, const char *&out)
|
||||
{
|
||||
return systemLimits.find(in, out);
|
||||
}
|
||||
|
||||
bool Graphics::getConstant(const char *in, StackType &out)
|
||||
{
|
||||
return stackTypes.find(in, out);
|
||||
}
|
||||
|
||||
bool Graphics::getConstant(StackType in, const char *&out)
|
||||
{
|
||||
return stackTypes.find(in, out);
|
||||
}
|
||||
|
||||
std::vector<std::string> Graphics::getConstants(StackType)
|
||||
{
|
||||
return stackTypes.getNames();
|
||||
}
|
||||
|
||||
StringMap<Graphics::DrawMode, Graphics::DRAW_MAX_ENUM>::Entry Graphics::drawModeEntries[] =
|
||||
{
|
||||
{ "line", DRAW_LINE },
|
||||
{ "fill", DRAW_FILL },
|
||||
};
|
||||
|
||||
StringMap<Graphics::DrawMode, Graphics::DRAW_MAX_ENUM> Graphics::drawModes(Graphics::drawModeEntries, sizeof(Graphics::drawModeEntries));
|
||||
|
||||
StringMap<Graphics::ArcMode, Graphics::ARC_MAX_ENUM>::Entry Graphics::arcModeEntries[] =
|
||||
{
|
||||
{ "open", ARC_OPEN },
|
||||
{ "closed", ARC_CLOSED },
|
||||
{ "pie", ARC_PIE },
|
||||
};
|
||||
|
||||
StringMap<Graphics::ArcMode, Graphics::ARC_MAX_ENUM> Graphics::arcModes(Graphics::arcModeEntries, sizeof(Graphics::arcModeEntries));
|
||||
|
||||
StringMap<Graphics::LineStyle, Graphics::LINE_MAX_ENUM>::Entry Graphics::lineStyleEntries[] =
|
||||
{
|
||||
{ "smooth", LINE_SMOOTH },
|
||||
{ "rough", LINE_ROUGH }
|
||||
};
|
||||
|
||||
StringMap<Graphics::LineStyle, Graphics::LINE_MAX_ENUM> Graphics::lineStyles(Graphics::lineStyleEntries, sizeof(Graphics::lineStyleEntries));
|
||||
|
||||
StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM>::Entry Graphics::lineJoinEntries[] =
|
||||
{
|
||||
{ "none", LINE_JOIN_NONE },
|
||||
{ "miter", LINE_JOIN_MITER },
|
||||
{ "bevel", LINE_JOIN_BEVEL }
|
||||
};
|
||||
|
||||
StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM> Graphics::lineJoins(Graphics::lineJoinEntries, sizeof(Graphics::lineJoinEntries));
|
||||
|
||||
StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM>::Entry Graphics::featureEntries[] =
|
||||
{
|
||||
{ "multirendertargetformats", FEATURE_MULTI_RENDER_TARGET_FORMATS },
|
||||
{ "clampzero", FEATURE_CLAMP_ZERO },
|
||||
{ "blendminmax", FEATURE_BLEND_MINMAX },
|
||||
{ "lighten", FEATURE_LIGHTEN },
|
||||
{ "fullnpot", FEATURE_FULL_NPOT },
|
||||
{ "pixelshaderhighp", FEATURE_PIXEL_SHADER_HIGHP },
|
||||
{ "shaderderivatives", FEATURE_SHADER_DERIVATIVES },
|
||||
{ "glsl3", FEATURE_GLSL3 },
|
||||
{ "glsl4", FEATURE_GLSL4 },
|
||||
{ "instancing", FEATURE_INSTANCING },
|
||||
{ "texelbuffer", FEATURE_TEXEL_BUFFER },
|
||||
};
|
||||
|
||||
StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM> Graphics::features(Graphics::featureEntries, sizeof(Graphics::featureEntries));
|
||||
|
||||
StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM>::Entry Graphics::systemLimitEntries[] =
|
||||
{
|
||||
{ "pointsize", LIMIT_POINT_SIZE },
|
||||
{ "texturesize", LIMIT_TEXTURE_SIZE },
|
||||
{ "texturelayers", LIMIT_TEXTURE_LAYERS },
|
||||
{ "volumetexturesize", LIMIT_VOLUME_TEXTURE_SIZE },
|
||||
{ "cubetexturesize", LIMIT_CUBE_TEXTURE_SIZE },
|
||||
{ "texelbuffersize", LIMIT_TEXEL_BUFFER_SIZE },
|
||||
{ "shaderstoragebuffersize", LIMIT_SHADER_STORAGE_BUFFER_SIZE },
|
||||
{ "rendertargets", LIMIT_RENDER_TARGETS },
|
||||
{ "texturemsaa", LIMIT_TEXTURE_MSAA },
|
||||
{ "anisotropy", LIMIT_ANISOTROPY },
|
||||
};
|
||||
|
||||
StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM> Graphics::systemLimits(Graphics::systemLimitEntries, sizeof(Graphics::systemLimitEntries));
|
||||
|
||||
StringMap<Graphics::StackType, Graphics::STACK_MAX_ENUM>::Entry Graphics::stackTypeEntries[] =
|
||||
{
|
||||
{ "all", STACK_ALL },
|
||||
{ "transform", STACK_TRANSFORM },
|
||||
};
|
||||
|
||||
StringMap<Graphics::StackType, Graphics::STACK_MAX_ENUM> Graphics::stackTypes(Graphics::stackTypeEntries, sizeof(Graphics::stackTypeEntries));
|
||||
STRINGMAP_CLASS_END(Graphics, Graphics::StackType, Graphics::STACK_MAX_ENUM, stackType)
|
||||
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -144,6 +144,7 @@ public:
|
||||
FEATURE_GLSL4,
|
||||
FEATURE_INSTANCING,
|
||||
FEATURE_TEXEL_BUFFER,
|
||||
FEATURE_COPY_BUFFER,
|
||||
FEATURE_MAX_ENUM
|
||||
};
|
||||
|
||||
@@ -432,7 +433,7 @@ public:
|
||||
Font *newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting);
|
||||
Video *newVideo(love::video::VideoStream *stream, float dpiscale);
|
||||
|
||||
SpriteBatch *newSpriteBatch(Texture *texture, int size, BufferUsage usage);
|
||||
SpriteBatch *newSpriteBatch(Texture *texture, int size, BufferDataUsage usage);
|
||||
ParticleSystem *newParticleSystem(Texture *texture, int size);
|
||||
|
||||
Shader *newShader(const std::vector<std::string> &stagessource);
|
||||
@@ -440,8 +441,8 @@ public:
|
||||
virtual Buffer *newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength) = 0;
|
||||
virtual Buffer *newBuffer(const Buffer::Settings &settings, DataFormat format, const void *data, size_t size, size_t arraylength);
|
||||
|
||||
Mesh *newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferUsage usage);
|
||||
Mesh *newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferUsage usage);
|
||||
Mesh *newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferDataUsage usage);
|
||||
Mesh *newMesh(const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferDataUsage usage);
|
||||
Mesh *newMesh(const std::vector<Mesh::BufferAttribute> &attributes, PrimitiveType drawmode);
|
||||
|
||||
Text *newText(Font *font, const std::vector<Font::ColoredString> &text = {});
|
||||
@@ -669,6 +670,8 @@ public:
|
||||
|
||||
void captureScreenshot(const ScreenshotInfo &info);
|
||||
|
||||
void copyBuffer(Buffer *source, Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size);
|
||||
|
||||
void draw(Drawable *drawable, const Matrix4 &m);
|
||||
void draw(Texture *texture, Quad *quad, const Matrix4 &m);
|
||||
void drawLayer(Texture *texture, int layer, const Matrix4 &m);
|
||||
@@ -776,7 +779,7 @@ public:
|
||||
/**
|
||||
* Converts PIXELFORMAT_NORMAL and PIXELFORMAT_HDR into a real format.
|
||||
**/
|
||||
virtual PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const = 0;
|
||||
virtual PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const = 0;
|
||||
|
||||
/**
|
||||
* Gets whether the specified pixel format is supported.
|
||||
@@ -848,31 +851,13 @@ public:
|
||||
|
||||
static Graphics *createInstance(const std::vector<Renderer> &renderers);
|
||||
|
||||
static bool getConstant(const char *in, DrawMode &out);
|
||||
static bool getConstant(DrawMode in, const char *&out);
|
||||
static std::vector<std::string> getConstants(DrawMode);
|
||||
|
||||
static bool getConstant(const char *in, ArcMode &out);
|
||||
static bool getConstant(ArcMode in, const char *&out);
|
||||
static std::vector<std::string> getConstants(ArcMode);
|
||||
|
||||
static bool getConstant(const char *in, LineStyle &out);
|
||||
static bool getConstant(LineStyle in, const char *&out);
|
||||
static std::vector<std::string> getConstants(LineStyle);
|
||||
|
||||
static bool getConstant(const char *in, LineJoin &out);
|
||||
static bool getConstant(LineJoin in, const char *&out);
|
||||
static std::vector<std::string> getConstants(LineJoin);
|
||||
|
||||
static bool getConstant(const char *in, Feature &out);
|
||||
static bool getConstant(Feature in, const char *&out);
|
||||
|
||||
static bool getConstant(const char *in, SystemLimit &out);
|
||||
static bool getConstant(SystemLimit in, const char *&out);
|
||||
|
||||
static bool getConstant(const char *in, StackType &out);
|
||||
static bool getConstant(StackType in, const char *&out);
|
||||
static std::vector<std::string> getConstants(StackType);
|
||||
STRINGMAP_CLASS_DECLARE(DrawMode);
|
||||
STRINGMAP_CLASS_DECLARE(ArcMode);
|
||||
STRINGMAP_CLASS_DECLARE(LineStyle);
|
||||
STRINGMAP_CLASS_DECLARE(LineJoin);
|
||||
STRINGMAP_CLASS_DECLARE(Feature);
|
||||
STRINGMAP_CLASS_DECLARE(SystemLimit);
|
||||
STRINGMAP_CLASS_DECLARE(StackType);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -952,7 +937,7 @@ protected:
|
||||
ShaderStage *newShaderStage(ShaderStage::StageType stage, const std::string &source, const Shader::SourceInfo &info);
|
||||
virtual ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) = 0;
|
||||
virtual Shader *newShaderInternal(ShaderStage *vertex, ShaderStage *pixel) = 0;
|
||||
virtual StreamBuffer *newStreamBuffer(BufferType type, size_t size) = 0;
|
||||
virtual StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) = 0;
|
||||
|
||||
virtual void setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBtexture) = 0;
|
||||
|
||||
@@ -1016,27 +1001,6 @@ private:
|
||||
|
||||
std::unordered_map<std::string, ShaderStage *> cachedShaderStages[ShaderStage::STAGE_MAX_ENUM];
|
||||
|
||||
static StringMap<DrawMode, DRAW_MAX_ENUM>::Entry drawModeEntries[];
|
||||
static StringMap<DrawMode, DRAW_MAX_ENUM> drawModes;
|
||||
|
||||
static StringMap<ArcMode, ARC_MAX_ENUM>::Entry arcModeEntries[];
|
||||
static StringMap<ArcMode, ARC_MAX_ENUM> arcModes;
|
||||
|
||||
static StringMap<LineStyle, LINE_MAX_ENUM>::Entry lineStyleEntries[];
|
||||
static StringMap<LineStyle, LINE_MAX_ENUM> lineStyles;
|
||||
|
||||
static StringMap<LineJoin, LINE_JOIN_MAX_ENUM>::Entry lineJoinEntries[];
|
||||
static StringMap<LineJoin, LINE_JOIN_MAX_ENUM> lineJoins;
|
||||
|
||||
static StringMap<Feature, FEATURE_MAX_ENUM>::Entry featureEntries[];
|
||||
static StringMap<Feature, FEATURE_MAX_ENUM> features;
|
||||
|
||||
static StringMap<SystemLimit, LIMIT_MAX_ENUM>::Entry systemLimitEntries[];
|
||||
static StringMap<SystemLimit, LIMIT_MAX_ENUM> systemLimits;
|
||||
|
||||
static StringMap<StackType, STACK_MAX_ENUM>::Entry stackTypeEntries[];
|
||||
static StringMap<StackType, STACK_MAX_ENUM> stackTypes;
|
||||
|
||||
}; // Graphics
|
||||
|
||||
} // graphics
|
||||
|
||||
@@ -45,7 +45,7 @@ std::vector<Buffer::DataDeclaration> Mesh::getDefaultVertexFormat()
|
||||
|
||||
love::Type Mesh::type("Mesh", &Drawable::type);
|
||||
|
||||
Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferUsage usage)
|
||||
Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferDataUsage usage)
|
||||
: primitiveType(drawmode)
|
||||
{
|
||||
try
|
||||
@@ -59,7 +59,7 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &
|
||||
|
||||
memcpy(vertexData, data, datasize);
|
||||
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_VERTEX, usage);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, usage);
|
||||
vertexBuffer.set(gfx->newBuffer(settings, vertexformat, vertexData, datasize, 0), Acquire::NORETAIN);
|
||||
|
||||
vertexCount = vertexBuffer->getArrayLength();
|
||||
@@ -71,7 +71,7 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &
|
||||
indexDataType = getIndexDataTypeFromMax(vertexCount);
|
||||
}
|
||||
|
||||
Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferUsage usage)
|
||||
Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferDataUsage usage)
|
||||
: vertexCount((size_t) vertexcount)
|
||||
, indexDataType(getIndexDataTypeFromMax(vertexcount))
|
||||
, primitiveType(drawmode)
|
||||
@@ -79,7 +79,7 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Buffer::DataDeclaration> &
|
||||
if (vertexcount <= 0)
|
||||
throw love::Exception("Invalid number of vertices (%d).", vertexcount);
|
||||
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_VERTEX, usage);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, usage);
|
||||
vertexBuffer.set(gfx->newBuffer(settings, vertexformat, nullptr, 0, vertexcount), Acquire::NORETAIN);
|
||||
|
||||
vertexStride = vertexBuffer->getArrayStride();
|
||||
@@ -112,7 +112,7 @@ Mesh::Mesh(const std::vector<Mesh::BufferAttribute> &attributes, PrimitiveType d
|
||||
|
||||
for (const auto &attrib : attachedAttributes)
|
||||
{
|
||||
if ((attrib.buffer->getTypeFlags() & Buffer::TYPEFLAG_VERTEX) == 0)
|
||||
if ((attrib.buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0)
|
||||
throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute.");
|
||||
|
||||
if (getAttachedAttributeIndex(attrib.name) != -1)
|
||||
@@ -210,7 +210,7 @@ bool Mesh::isAttributeEnabled(const std::string &name) const
|
||||
|
||||
void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, const std::string &attachname, AttributeStep step)
|
||||
{
|
||||
if ((buffer->getTypeFlags() & Buffer::TYPEFLAG_VERTEX) == 0)
|
||||
if ((buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0)
|
||||
throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute.");
|
||||
|
||||
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
|
||||
@@ -276,7 +276,7 @@ void Mesh::flush()
|
||||
{
|
||||
if (vertexBuffer.get() && vertexData != nullptr && modifiedVertexData.isValid())
|
||||
{
|
||||
if (vertexBuffer->getUsage() == BUFFERUSAGE_STREAM)
|
||||
if (vertexBuffer->getDataUsage() == BUFFERDATAUSAGE_STREAM)
|
||||
{
|
||||
vertexBuffer->fill(0, vertexBuffer->getSize(), vertexData);
|
||||
}
|
||||
@@ -327,8 +327,8 @@ void Mesh::setVertexMap(const std::vector<uint32> &map)
|
||||
if (indexBuffer.get() == nullptr || size > indexBuffer->getSize() || indexBuffer->getDataMember(0).decl.format != dataformat)
|
||||
{
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
auto usage = vertexBuffer.get() ? vertexBuffer->getUsage() : BUFFERUSAGE_DYNAMIC;
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_INDEX, usage);
|
||||
auto usage = vertexBuffer.get() ? vertexBuffer->getDataUsage() : BUFFERDATAUSAGE_DYNAMIC;
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, usage);
|
||||
indexBuffer.set(gfx->newBuffer(settings, dataformat, nullptr, size, 0), Acquire::NORETAIN);
|
||||
}
|
||||
|
||||
@@ -360,8 +360,8 @@ void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasiz
|
||||
if (indexBuffer.get() == nullptr || datasize > indexBuffer->getSize() || indexBuffer->getDataMember(0).decl.format != dataformat)
|
||||
{
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
auto usage = vertexBuffer.get() ? vertexBuffer->getUsage() : BUFFERUSAGE_DYNAMIC;
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_INDEX, usage);
|
||||
auto usage = vertexBuffer.get() ? vertexBuffer->getDataUsage() : BUFFERDATAUSAGE_DYNAMIC;
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, usage);
|
||||
indexBuffer.set(gfx->newBuffer(settings, dataformat, nullptr, datasize, 0), Acquire::NORETAIN);
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ void Mesh::setIndexBuffer(Buffer *buffer)
|
||||
{
|
||||
// Buffer constructor does the rest of the validation for index buffers
|
||||
// (data member formats, etc.)
|
||||
if (buffer != nullptr && (buffer->getTypeFlags() & Buffer::TYPEFLAG_INDEX) == 0)
|
||||
if (buffer != nullptr && (buffer->getUsageFlags() & BUFFERUSAGEFLAG_INDEX) == 0)
|
||||
throw love::Exception("setIndexBuffer requires a Buffer created as an index buffer.");
|
||||
|
||||
indexBuffer.set(buffer);
|
||||
@@ -519,8 +519,8 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
|
||||
if (Shader::isDefaultActive())
|
||||
Shader::attachDefault(Shader::STANDARD_DEFAULT);
|
||||
|
||||
if (Shader::current && texture.get())
|
||||
Shader::current->checkMainTexture(texture);
|
||||
if (Shader::current)
|
||||
Shader::current->validateDrawState(primitiveType, texture);
|
||||
|
||||
VertexAttributes attributes;
|
||||
BufferBindings buffers;
|
||||
|
||||
@@ -63,8 +63,8 @@ public:
|
||||
|
||||
static love::Type type;
|
||||
|
||||
Mesh(Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferUsage usage);
|
||||
Mesh(Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferUsage usage);
|
||||
Mesh(Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, BufferDataUsage usage);
|
||||
Mesh(Graphics *gfx, const std::vector<Buffer::DataDeclaration> &vertexformat, int vertexcount, PrimitiveType drawmode, BufferDataUsage usage);
|
||||
Mesh(const std::vector<BufferAttribute> &attributes, PrimitiveType drawmode);
|
||||
|
||||
virtual ~Mesh();
|
||||
|
||||
@@ -191,7 +191,7 @@ void ParticleSystem::createBuffers(size_t size)
|
||||
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
|
||||
|
||||
size_t bytes = sizeof(Vertex) * size * 4;
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_VERTEX, BUFFERUSAGE_STREAM);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STREAM);
|
||||
auto decl = Buffer::getCommonFormatDeclaration(CommonFormat::XYf_STf_RGBAub);
|
||||
buffer = gfx->newBuffer(settings, decl, nullptr, bytes, 0);
|
||||
}
|
||||
@@ -1037,8 +1037,8 @@ void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m)
|
||||
if (Shader::isDefaultActive())
|
||||
Shader::attachDefault(Shader::STANDARD_DEFAULT);
|
||||
|
||||
if (Shader::current && texture.get())
|
||||
Shader::current->checkMainTexture(texture);
|
||||
if (Shader::current)
|
||||
Shader::current->validateDrawState(PRIMITIVE_TRIANGLES, texture);
|
||||
|
||||
const Vector2 *positions = texture->getQuad()->getVertexPositions();
|
||||
const Vector2 *texcoords = texture->getQuad()->getVertexTexCoords();
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
// Needed for reflection information.
|
||||
#include "libraries/glslang/glslang/Include/Types.h"
|
||||
#include "libraries/glslang/glslang/MachineIndependent/localintermediate.h"
|
||||
|
||||
// C++
|
||||
#include <string>
|
||||
@@ -99,6 +100,10 @@ LOVE_HIGHP_OR_MEDIUMP mat3 NormalMatrix;
|
||||
LOVE_HIGHP_OR_MEDIUMP vec4 love_ScreenSize;
|
||||
LOVE_HIGHP_OR_MEDIUMP vec4 ConstantColor;
|
||||
|
||||
LOVE_HIGHP_OR_MEDIUMP float CurrentDPIScale;
|
||||
|
||||
LOVE_HIGHP_OR_MEDIUMP float ConstantPointSize;
|
||||
|
||||
#define TransformProjectionMatrix (ProjectionMatrix * TransformMatrix)
|
||||
|
||||
// Alternate names
|
||||
@@ -128,6 +133,8 @@ void love_initializeBuiltinUniforms() {
|
||||
love_UniformsPerDraw[10].xyz
|
||||
);
|
||||
|
||||
CurrentDPIScale = love_UniformsPerDraw[8].w;
|
||||
ConstantPointSize = love_UniformsPerDraw[9].w;
|
||||
love_ScreenSize = love_UniformsPerDraw[11];
|
||||
ConstantColor = love_UniformsPerDraw[12];
|
||||
}
|
||||
@@ -242,6 +249,7 @@ mediump vec4 linearToGammaFast(mediump vec4 c) { return vec4(linearToGammaFast(c
|
||||
|
||||
static const char vertex_header[] = R"(
|
||||
#define love_Position gl_Position
|
||||
#define love_PointSize gl_PointSize
|
||||
|
||||
#if __VERSION__ >= 130
|
||||
#define attribute in
|
||||
@@ -251,19 +259,9 @@ static const char vertex_header[] = R"(
|
||||
#define love_InstanceID gl_InstanceID
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef GL_ES
|
||||
uniform mediump float love_PointSize;
|
||||
#endif
|
||||
)";
|
||||
|
||||
static const char vertex_functions[] = R"(
|
||||
void setPointSize() {
|
||||
#ifdef GL_ES
|
||||
gl_PointSize = love_PointSize;
|
||||
#endif
|
||||
}
|
||||
)";
|
||||
static const char vertex_functions[] = R"()";
|
||||
|
||||
static const char vertex_main[] = R"(
|
||||
attribute vec4 VertexPosition;
|
||||
@@ -279,7 +277,6 @@ void main() {
|
||||
love_initializeBuiltinUniforms();
|
||||
VaryingTexCoord = VertexTexCoord;
|
||||
VaryingColor = gammaCorrectColor(VertexColor) * ConstantColor;
|
||||
setPointSize();
|
||||
love_Position = position(ClipSpaceFromLocal, VertexPosition);
|
||||
}
|
||||
)";
|
||||
@@ -289,7 +286,6 @@ void vertexmain();
|
||||
|
||||
void main() {
|
||||
love_initializeBuiltinUniforms();
|
||||
setPointSize();
|
||||
vertexmain();
|
||||
}
|
||||
)";
|
||||
@@ -604,13 +600,29 @@ TextureType Shader::getMainTextureType() const
|
||||
return info != nullptr ? info->textureType : TEXTURE_MAX_ENUM;
|
||||
}
|
||||
|
||||
void Shader::checkMainTextureType(TextureType textype, bool isDepthSampler) const
|
||||
void Shader::validateDrawState(PrimitiveType primtype, Texture *maintex) const
|
||||
{
|
||||
if ((primtype == PRIMITIVE_POINTS) != validationReflection.usesPointSize)
|
||||
{
|
||||
if (validationReflection.usesPointSize)
|
||||
throw love::Exception("The active shader can only be used to draw points.");
|
||||
else
|
||||
throw love::Exception("The gl_PointSize variable must be set in a vertex shader when drawing points.");
|
||||
}
|
||||
|
||||
if (maintex == nullptr)
|
||||
return;
|
||||
|
||||
const UniformInfo *info = getUniformInfo(BUILTIN_TEXTURE_MAIN);
|
||||
|
||||
if (info == nullptr)
|
||||
return;
|
||||
|
||||
if (!maintex->isReadable())
|
||||
throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader.");
|
||||
|
||||
auto textype = maintex->getTextureType();
|
||||
|
||||
if (info->textureType != TEXTURE_MAX_ENUM && info->textureType != textype)
|
||||
{
|
||||
const char *textypestr = "unknown";
|
||||
@@ -620,7 +632,7 @@ void Shader::checkMainTextureType(TextureType textype, bool isDepthSampler) cons
|
||||
throw love::Exception("Texture's type (%s) must match the type of the shader's main texture type (%s).", textypestr, shadertextypestr);
|
||||
}
|
||||
|
||||
if (info->isDepthSampler != isDepthSampler)
|
||||
if (info->isDepthSampler != maintex->getSamplerState().depthSampleMode.hasValue)
|
||||
{
|
||||
if (info->isDepthSampler)
|
||||
throw love::Exception("Depth comparison samplers in shaders can only be used with depth textures which have depth comparison set.");
|
||||
@@ -629,14 +641,6 @@ void Shader::checkMainTextureType(TextureType textype, bool isDepthSampler) cons
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::checkMainTexture(Texture *tex) const
|
||||
{
|
||||
if (!tex->isReadable())
|
||||
throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader.");
|
||||
|
||||
checkMainTextureType(tex->getTextureType(), tex->getSamplerState().depthSampleMode.hasValue);
|
||||
}
|
||||
|
||||
bool Shader::validate(ShaderStage* vertex, ShaderStage* pixel, std::string& err)
|
||||
{
|
||||
ValidationReflection reflection;
|
||||
@@ -665,6 +669,13 @@ bool Shader::validateInternal(ShaderStage *vertex, ShaderStage *pixel, std::stri
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto *vertintermediate = program.getIntermediate(EShLangVertex);
|
||||
if (vertintermediate != nullptr)
|
||||
{
|
||||
// NOTE: this doesn't check whether the use affects final output...
|
||||
reflection.usesPointSize = vertintermediate->inIoAccessed("gl_PointSize");
|
||||
}
|
||||
|
||||
for (int i = 0; i < program.getNumBufferBlocks(); i++)
|
||||
{
|
||||
const glslang::TObjectReflection &info = program.getBufferBlock(i);
|
||||
@@ -732,6 +743,14 @@ vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition)
|
||||
}
|
||||
)";
|
||||
|
||||
static const std::string defaultPointsVertex = R"(
|
||||
vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition)
|
||||
{
|
||||
love_PointSize = ConstantPointSize * CurrentDPIScale;
|
||||
return clipSpaceFromLocal * localPosition;
|
||||
}
|
||||
)";
|
||||
|
||||
static const std::string defaultStandardPixel = R"(
|
||||
vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord)
|
||||
{
|
||||
@@ -757,7 +776,12 @@ void effect()
|
||||
const std::string &Shader::getDefaultCode(StandardShader shader, ShaderStage::StageType stage)
|
||||
{
|
||||
if (stage == ShaderStage::STAGE_VERTEX)
|
||||
return defaultVertex;
|
||||
{
|
||||
if (shader == STANDARD_POINTS)
|
||||
return defaultPointsVertex;
|
||||
else
|
||||
return defaultVertex;
|
||||
}
|
||||
|
||||
static std::string nocode = "";
|
||||
|
||||
@@ -766,6 +790,7 @@ const std::string &Shader::getDefaultCode(StandardShader shader, ShaderStage::St
|
||||
case STANDARD_DEFAULT: return defaultStandardPixel;
|
||||
case STANDARD_VIDEO: return defaultVideoPixel;
|
||||
case STANDARD_ARRAY: return defaultArrayPixel;
|
||||
case STANDARD_POINTS: return defaultStandardPixel;
|
||||
case STANDARD_MAX_ENUM: return nocode;
|
||||
}
|
||||
|
||||
@@ -788,7 +813,6 @@ static StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry builti
|
||||
{ "love_VideoCbChannel", Shader::BUILTIN_TEXTURE_VIDEO_CB },
|
||||
{ "love_VideoCrChannel", Shader::BUILTIN_TEXTURE_VIDEO_CR },
|
||||
{ "love_UniformsPerDraw", Shader::BUILTIN_UNIFORMS_PER_DRAW },
|
||||
{ "love_PointSize", Shader::BUILTIN_POINT_SIZE },
|
||||
};
|
||||
|
||||
static StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> builtinNames(builtinNameEntries, sizeof(builtinNameEntries));
|
||||
|
||||
@@ -64,7 +64,6 @@ public:
|
||||
BUILTIN_TEXTURE_VIDEO_CB,
|
||||
BUILTIN_TEXTURE_VIDEO_CR,
|
||||
BUILTIN_UNIFORMS_PER_DRAW,
|
||||
BUILTIN_POINT_SIZE,
|
||||
BUILTIN_MAX_ENUM
|
||||
};
|
||||
|
||||
@@ -88,6 +87,7 @@ public:
|
||||
STANDARD_DEFAULT,
|
||||
STANDARD_VIDEO,
|
||||
STANDARD_ARRAY,
|
||||
STANDARD_POINTS,
|
||||
STANDARD_MAX_ENUM
|
||||
};
|
||||
|
||||
@@ -209,8 +209,7 @@ public:
|
||||
virtual void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) = 0;
|
||||
|
||||
TextureType getMainTextureType() const;
|
||||
void checkMainTextureType(TextureType textype, bool isDepthSampler) const;
|
||||
void checkMainTexture(Texture *texture) const;
|
||||
void validateDrawState(PrimitiveType primtype, Texture *maintexture) const;
|
||||
|
||||
static SourceInfo getSourceInfo(const std::string &src);
|
||||
static std::string createShaderStageCode(Graphics *gfx, ShaderStage::StageType stage, const std::string &code, const SourceInfo &info);
|
||||
@@ -239,6 +238,7 @@ protected:
|
||||
struct ValidationReflection
|
||||
{
|
||||
std::map<std::string, BufferReflection> storageBuffers;
|
||||
bool usesPointSize;
|
||||
};
|
||||
|
||||
static bool validateInternal(ShaderStage* vertex, ShaderStage* pixel, std::string& err, ValidationReflection &reflection);
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace graphics
|
||||
|
||||
love::Type SpriteBatch::type("SpriteBatch", &Drawable::type);
|
||||
|
||||
SpriteBatch::SpriteBatch(Graphics *gfx, Texture *texture, int size, BufferUsage usage)
|
||||
SpriteBatch::SpriteBatch(Graphics *gfx, Texture *texture, int size, BufferDataUsage usage)
|
||||
: texture(texture)
|
||||
, size(size)
|
||||
, next(0)
|
||||
@@ -73,7 +73,7 @@ SpriteBatch::SpriteBatch(Graphics *gfx, Texture *texture, int size, BufferUsage
|
||||
|
||||
memset(vertex_data, 0, vertex_size);
|
||||
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_VERTEX, usage);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, usage);
|
||||
auto decl = Buffer::getCommonFormatDeclaration(vertex_format);
|
||||
|
||||
array_buf.set(gfx->newBuffer(settings, decl, nullptr, vertex_size, 0), Acquire::NORETAIN);
|
||||
@@ -185,7 +185,7 @@ void SpriteBatch::flush()
|
||||
size_t offset = modified_sprites.getOffset() * vertex_stride * 4;
|
||||
size_t size = modified_sprites.getSize() * vertex_stride * 4;
|
||||
|
||||
if (array_buf->getUsage() == BUFFERUSAGE_STREAM)
|
||||
if (array_buf->getDataUsage() == BUFFERDATAUSAGE_STREAM)
|
||||
array_buf->fill(0, array_buf->getSize(), vertex_data);
|
||||
else
|
||||
array_buf->fill(offset, size, vertex_data + offset);
|
||||
@@ -244,7 +244,7 @@ void SpriteBatch::setBufferSize(int newsize)
|
||||
throw love::Exception("Out of memory.");
|
||||
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
Buffer::Settings settings(array_buf->getTypeFlags(), array_buf->getUsage());
|
||||
Buffer::Settings settings(array_buf->getUsageFlags(), array_buf->getDataUsage());
|
||||
auto decl = Buffer::getCommonFormatDeclaration(vertex_format);
|
||||
|
||||
array_buf.set(gfx->newBuffer(settings, decl, nullptr, vertex_size, 0), Acquire::NORETAIN);
|
||||
@@ -264,7 +264,7 @@ int SpriteBatch::getBufferSize() const
|
||||
|
||||
void SpriteBatch::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh)
|
||||
{
|
||||
if ((buffer->getTypeFlags() & Buffer::TYPEFLAG_VERTEX) == 0)
|
||||
if ((buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0)
|
||||
throw love::Exception("GraphicsBuffer must be created with vertex buffer support to be used as a SpriteBatch vertex attribute.");
|
||||
|
||||
AttachedAttribute oldattrib = {};
|
||||
@@ -329,11 +329,11 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
|
||||
Shader::attachDefault(defaultshader);
|
||||
}
|
||||
|
||||
if (Shader::current)
|
||||
Shader::current->checkMainTexture(texture);
|
||||
}
|
||||
|
||||
if (Shader::current)
|
||||
Shader::current->validateDrawState(PRIMITIVE_TRIANGLES, texture);
|
||||
|
||||
flush(); // Upload any modified sprite data to the GPU.
|
||||
|
||||
VertexAttributes attributes;
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
|
||||
static love::Type type;
|
||||
|
||||
SpriteBatch(Graphics *gfx, Texture *texture, int size, BufferUsage usage);
|
||||
SpriteBatch(Graphics *gfx, Texture *texture, int size, BufferDataUsage usage);
|
||||
virtual ~SpriteBatch();
|
||||
|
||||
int add(const Matrix4 &m, int index = -1);
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace love
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
StreamBuffer::StreamBuffer(BufferType mode, size_t size)
|
||||
StreamBuffer::StreamBuffer(BufferUsage mode, size_t size)
|
||||
: bufferSize(size)
|
||||
, frameGPUReadOffset(0)
|
||||
, mode(mode)
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
virtual ~StreamBuffer() {}
|
||||
|
||||
size_t getSize() const { return bufferSize; }
|
||||
BufferType getMode() const { return mode; }
|
||||
BufferUsage getMode() const { return mode; }
|
||||
size_t getUsableSize() const { return bufferSize - frameGPUReadOffset; }
|
||||
|
||||
virtual MapInfo map(size_t minsize) = 0;
|
||||
@@ -64,11 +64,11 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
StreamBuffer(BufferType mode, size_t size);
|
||||
StreamBuffer(BufferUsage mode, size_t size);
|
||||
|
||||
size_t bufferSize;
|
||||
size_t frameGPUReadOffset;
|
||||
BufferType mode;
|
||||
BufferUsage mode;
|
||||
|
||||
}; // StreamBuffer
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ void Text::uploadVertices(const std::vector<Font::GlyphVertex> &vertices, size_t
|
||||
|
||||
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
|
||||
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_VERTEX, BUFFERUSAGE_DYNAMIC);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_DYNAMIC);
|
||||
auto decl = Buffer::getCommonFormatDeclaration(Font::vertexFormat);
|
||||
Buffer *newbuffer = gfx->newBuffer(settings, decl, nullptr, newsize, 0);
|
||||
|
||||
@@ -262,8 +262,12 @@ void Text::draw(Graphics *gfx, const Matrix4 &m)
|
||||
if (Shader::isDefaultActive())
|
||||
Shader::attachDefault(Shader::STANDARD_DEFAULT);
|
||||
|
||||
Texture *firsttex = nullptr;
|
||||
if (!drawCommands.empty())
|
||||
firsttex = drawCommands[0].texture;
|
||||
|
||||
if (Shader::current)
|
||||
Shader::current->checkMainTextureType(TEXTURE_2D, false);
|
||||
Shader::current->validateDrawState(PRIMITIVE_TRIANGLES, firsttex);
|
||||
|
||||
// Re-generate the text if the Font's texture cache was invalidated.
|
||||
if (font->getTextureCacheID() != textureCacheID)
|
||||
@@ -279,7 +283,7 @@ void Text::draw(Graphics *gfx, const Matrix4 &m)
|
||||
size_t offset = modifiedVertices.getOffset();
|
||||
size_t size = modifiedVertices.getSize();
|
||||
|
||||
if (vertexBuffer->getUsage() == BUFFERUSAGE_STREAM)
|
||||
if (vertexBuffer->getDataUsage() == BUFFERDATAUSAGE_STREAM)
|
||||
vertexBuffer->fill(0, vertexBuffer->getSize(), vertexData);
|
||||
else
|
||||
vertexBuffer->fill(offset, size, vertexData + offset);
|
||||
|
||||
@@ -223,7 +223,7 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices)
|
||||
else
|
||||
readable = !renderTarget || !isPixelFormatDepthStencil(format);
|
||||
|
||||
format = gfx->getSizedFormat(format, renderTarget, readable, sRGB);
|
||||
format = gfx->getSizedFormat(format, renderTarget, readable);
|
||||
|
||||
if (mipmapsMode == MIPMAPS_AUTO && isCompressed())
|
||||
mipmapsMode = MIPMAPS_MANUAL;
|
||||
@@ -419,7 +419,7 @@ void Texture::uploadImageData(love::image::ImageDataBase *d, int level, int slic
|
||||
lock.setLock(id->getMutex());
|
||||
|
||||
Rect rect = {x, y, d->getWidth(), d->getHeight()};
|
||||
uploadByteData(d->getFormat(), d->getData(), d->getSize(), level, slice, rect, d);
|
||||
uploadByteData(d->getFormat(), d->getData(), d->getSize(), level, slice, rect);
|
||||
}
|
||||
|
||||
void Texture::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps)
|
||||
@@ -485,7 +485,7 @@ void Texture::replacePixels(const void *data, size_t size, int slice, int mipmap
|
||||
|
||||
Graphics::flushBatchedDrawsGlobal();
|
||||
|
||||
uploadByteData(format, data, size, mipmap, slice, rect, nullptr);
|
||||
uploadByteData(format, data, size, mipmap, slice, rect);
|
||||
|
||||
if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1)
|
||||
generateMipmaps();
|
||||
|
||||
@@ -56,6 +56,26 @@ enum TextureType
|
||||
TEXTURE_MAX_ENUM
|
||||
};
|
||||
|
||||
enum PixelFormatUsage
|
||||
{
|
||||
PIXELFORMATUSAGE_SAMPLE,
|
||||
PIXELFORMATUSAGE_LINEAR,
|
||||
PIXELFORMATUSAGE_RENDERTARGET,
|
||||
PIXELFORMATUSAGE_BLEND,
|
||||
PIXELFORMATUSAGE_MSAA,
|
||||
PIXELFORMATUSAGE_MAX_ENUM
|
||||
};
|
||||
|
||||
enum PixelFormatUsageFlags
|
||||
{
|
||||
PIXELFORMATUSAGEFLAGS_NONE = 0,
|
||||
PIXELFORMATUSAGEFLAGS_SAMPLE = (1 << PIXELFORMATUSAGE_SAMPLE),
|
||||
PIXELFORMATUSAGEFLAGS_LINEAR = (1 << PIXELFORMATUSAGE_LINEAR),
|
||||
PIXELFORMATUSAGEFLAGS_RENDERTARGET = (1 << PIXELFORMATUSAGE_RENDERTARGET),
|
||||
PIXELFORMATUSAGEFLAGS_BLEND = (1 << PIXELFORMATUSAGE_BLEND),
|
||||
PIXELFORMATUSAGEFLAGS_MSAA = (1 << PIXELFORMATUSAGE_MSAA),
|
||||
};
|
||||
|
||||
struct SamplerState
|
||||
{
|
||||
enum WrapMode
|
||||
@@ -276,7 +296,7 @@ protected:
|
||||
void setGraphicsMemorySize(int64 size);
|
||||
|
||||
void uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y);
|
||||
virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) = 0;
|
||||
virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) = 0;
|
||||
|
||||
virtual void generateMipmapsInternal() = 0;
|
||||
virtual void readbackImageData(love::image::ImageData *imagedata, int slice, int mipmap, const Rect &rect) = 0;
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
void *map(MapType map, size_t offset, size_t size) override;
|
||||
void unmap(size_t usedoffset, size_t usedsize) override;
|
||||
void fill(size_t offset, size_t size, const void *data) override;
|
||||
void copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) override;
|
||||
|
||||
ptrdiff_t getHandle() const override { return (ptrdiff_t) buffer; }
|
||||
ptrdiff_t getTexelBufferHandle() const override { return (ptrdiff_t) texture; }
|
||||
|
||||
@@ -71,7 +71,7 @@ Buffer::Buffer(love::graphics::Graphics *gfx, id<MTLDevice> device, const Settin
|
||||
if (buffer == nil)
|
||||
throw love::Exception("Could not create buffer (out of VRAM?)");
|
||||
|
||||
if (typeFlags & TYPEFLAG_TEXEL)
|
||||
if (usageFlags & BUFFERUSAGEFLAG_TEXEL)
|
||||
{
|
||||
if (@available(iOS 12, macOS 10.14, *))
|
||||
{
|
||||
@@ -169,6 +169,18 @@ void Buffer::fill(size_t offset, size_t size, const void *data)
|
||||
size:size];
|
||||
}}
|
||||
|
||||
void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)
|
||||
{ @autoreleasepool {
|
||||
auto gfx = Graphics::getInstance();
|
||||
auto encoder = gfx->useBlitEncoder();
|
||||
|
||||
[encoder copyFromBuffer:buffer
|
||||
sourceOffset:sourceoffset
|
||||
toBuffer:((Buffer *) dest)->buffer
|
||||
destinationOffset:destoffset
|
||||
size:size];
|
||||
}}
|
||||
|
||||
} // metal
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -90,7 +90,7 @@ public:
|
||||
|
||||
void setWireframe(bool enable) override;
|
||||
|
||||
PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const override;
|
||||
PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override;
|
||||
bool isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB = false) override;
|
||||
Renderer getRenderer() const override;
|
||||
bool usesGLSLES() const override;
|
||||
@@ -163,7 +163,7 @@ private:
|
||||
|
||||
love::graphics::ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) override;
|
||||
love::graphics::Shader *newShaderInternal(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel) override;
|
||||
love::graphics::StreamBuffer *newStreamBuffer(BufferType type, size_t size) override;
|
||||
love::graphics::StreamBuffer *newStreamBuffer(BufferUsage usage, size_t size) override;
|
||||
void setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) override;
|
||||
void initCapabilities() override;
|
||||
void getAPIStats(int &shaderswitches) const override;
|
||||
|
||||
@@ -189,7 +189,7 @@ Graphics::Graphics()
|
||||
|
||||
initCapabilities();
|
||||
|
||||
uniformBuffer = CreateStreamBuffer(device, BUFFERTYPE_UNIFORM, 1024 * 1024 * 1);
|
||||
uniformBuffer = CreateStreamBuffer(device, BUFFERUSAGE_UNIFORM, 1024 * 1024 * 1);
|
||||
|
||||
{
|
||||
std::vector<Buffer::DataDeclaration> dataformat = {
|
||||
@@ -202,7 +202,7 @@ Graphics::Graphics()
|
||||
{0, 0, 0, 1},
|
||||
};
|
||||
|
||||
Buffer::Settings attribsettings(Buffer::TYPEFLAG_VERTEX, BUFFERUSAGE_STATIC);
|
||||
Buffer::Settings attribsettings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC);
|
||||
|
||||
defaultAttributesBuffer = newBuffer(attribsettings, dataformat, &defaults, sizeof(DefaultVertexAttributes), 0);
|
||||
}
|
||||
@@ -261,9 +261,9 @@ Graphics::~Graphics()
|
||||
graphicsInstance = nullptr;
|
||||
}}
|
||||
|
||||
love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t size)
|
||||
love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage usage, size_t size)
|
||||
{
|
||||
return CreateStreamBuffer(device, type, size);
|
||||
return CreateStreamBuffer(device, usage, size);
|
||||
}
|
||||
|
||||
love::graphics::Texture *Graphics::newTexture(const Texture::Settings &settings, const Texture::Slices *data)
|
||||
@@ -324,9 +324,9 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
||||
{
|
||||
// Initial sizes that should be good enough for most cases. It will
|
||||
// resize to fit if needed, later.
|
||||
batchedDrawState.vb[0] = CreateStreamBuffer(device, BUFFERTYPE_VERTEX, 1024 * 1024 * 1);
|
||||
batchedDrawState.vb[1] = CreateStreamBuffer(device, BUFFERTYPE_VERTEX, 256 * 1024 * 1);
|
||||
batchedDrawState.indexBuffer = CreateStreamBuffer(device, BUFFERTYPE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||
batchedDrawState.vb[0] = CreateStreamBuffer(device, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1);
|
||||
batchedDrawState.vb[1] = CreateStreamBuffer(device, BUFFERUSAGE_VERTEX, 256 * 1024 * 1);
|
||||
batchedDrawState.indexBuffer = CreateStreamBuffer(device, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||
}
|
||||
|
||||
createQuadIndexBuffer();
|
||||
@@ -717,7 +717,7 @@ void Graphics::applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, lo
|
||||
{
|
||||
size_t newsize = uniformBuffer->getSize() * 2;
|
||||
delete uniformBuffer;
|
||||
uniformBuffer = CreateStreamBuffer(device, BUFFERTYPE_UNIFORM, newsize);
|
||||
uniformBuffer = CreateStreamBuffer(device, BUFFERUSAGE_UNIFORM, newsize);
|
||||
uniformBufferData = {};
|
||||
uniformBufferOffset = 0;
|
||||
}
|
||||
@@ -1293,7 +1293,7 @@ void Graphics::setWireframe(bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
PixelFormat Graphics::getSizedFormat(PixelFormat format, bool /*rendertarget*/, bool /*readable*/, bool /*sRGB*/) const
|
||||
PixelFormat Graphics::getSizedFormat(PixelFormat format, bool /*rendertarget*/, bool /*readable*/) const
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
@@ -1362,7 +1362,8 @@ void Graphics::initCapabilities()
|
||||
capabilities.features[FEATURE_GLSL4] = true;
|
||||
capabilities.features[FEATURE_INSTANCING] = true;
|
||||
capabilities.features[FEATURE_TEXEL_BUFFER] = true;
|
||||
static_assert(FEATURE_MAX_ENUM == 11, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
|
||||
capabilities.features[FEATURE_COPY_BUFFER] = true;
|
||||
static_assert(FEATURE_MAX_ENUM == 12, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
|
||||
|
||||
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
|
||||
capabilities.limits[LIMIT_POINT_SIZE] = 511;
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace graphics
|
||||
namespace metal
|
||||
{
|
||||
|
||||
love::graphics::StreamBuffer *CreateStreamBuffer(id<MTLDevice> device, BufferType mode, size_t size);
|
||||
love::graphics::StreamBuffer *CreateStreamBuffer(id<MTLDevice> device, BufferUsage usage, size_t size);
|
||||
|
||||
} // metal
|
||||
} // graphics
|
||||
|
||||
@@ -38,8 +38,8 @@ class StreamBuffer final : public love::graphics::StreamBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
StreamBuffer(id<MTLDevice> device, BufferType mode, size_t size)
|
||||
: love::graphics::StreamBuffer(mode, size)
|
||||
StreamBuffer(id<MTLDevice> device, BufferUsage usage, size_t size)
|
||||
: love::graphics::StreamBuffer(usage, size)
|
||||
, frameIndex(0)
|
||||
, mappedFrames()
|
||||
{ @autoreleasepool {
|
||||
@@ -122,9 +122,9 @@ private:
|
||||
|
||||
}; // StreamBuffer
|
||||
|
||||
love::graphics::StreamBuffer *CreateStreamBuffer(id<MTLDevice> device, BufferType mode, size_t size)
|
||||
love::graphics::StreamBuffer *CreateStreamBuffer(id<MTLDevice> device, BufferUsage usage, size_t size)
|
||||
{
|
||||
return new StreamBuffer(device, mode, size);
|
||||
return new StreamBuffer(device, usage, size);
|
||||
}
|
||||
|
||||
} // metal
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override;
|
||||
void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) override;
|
||||
void generateMipmapsInternal() override;
|
||||
void readbackImageData(love::image::ImageData *imagedata, int slice, int mipmap, const Rect &rect) override;
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ Texture::~Texture()
|
||||
sampler = nil;
|
||||
}}
|
||||
|
||||
void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *)
|
||||
void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r)
|
||||
{ @autoreleasepool {
|
||||
auto gfx = Graphics::getInstance();
|
||||
id<MTLBuffer> buffer = [gfx->device newBufferWithBytes:data
|
||||
|
||||
@@ -72,18 +72,22 @@ Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const st
|
||||
size = getSize();
|
||||
arraylength = getArrayLength();
|
||||
|
||||
if (typeFlags & TYPEFLAG_TEXEL)
|
||||
mapType = BUFFERTYPE_TEXEL;
|
||||
else if (typeFlags & TYPEFLAG_VERTEX)
|
||||
mapType = BUFFERTYPE_VERTEX;
|
||||
else if (typeFlags & TYPEFLAG_INDEX)
|
||||
mapType = BUFFERTYPE_INDEX;
|
||||
else if (typeFlags & TYPEFLAG_SHADER_STORAGE)
|
||||
mapType = BUFFERTYPE_SHADER_STORAGE;
|
||||
if (usageFlags & BUFFERUSAGEFLAG_TEXEL)
|
||||
mapUsage = BUFFERUSAGE_TEXEL;
|
||||
else if (usageFlags & BUFFERUSAGEFLAG_VERTEX)
|
||||
mapUsage = BUFFERUSAGE_VERTEX;
|
||||
else if (usageFlags & BUFFERUSAGEFLAG_INDEX)
|
||||
mapUsage = BUFFERUSAGE_INDEX;
|
||||
else if (usageFlags & BUFFERUSAGEFLAG_SHADER_STORAGE)
|
||||
mapUsage = BUFFERUSAGE_SHADER_STORAGE;
|
||||
else if (usageFlags & BUFFERUSAGEFLAG_COPY_SOURCE)
|
||||
mapUsage = BUFFERUSAGE_COPY_SOURCE;
|
||||
else if (usageFlags & BUFFERUSAGEFLAG_COPY_DEST)
|
||||
mapUsage = BUFFERUSAGE_COPY_DEST;
|
||||
|
||||
target = OpenGL::getGLBufferType(mapType);
|
||||
target = OpenGL::getGLBufferType(mapUsage);
|
||||
|
||||
if (usage == BUFFERUSAGE_STREAM)
|
||||
if (dataUsage == BUFFERDATAUSAGE_STREAM)
|
||||
ownsMemoryMap = true;
|
||||
|
||||
std::vector<uint8> emptydata;
|
||||
@@ -139,12 +143,14 @@ bool Buffer::load(const void *initialdata)
|
||||
/* Clear the error buffer. */;
|
||||
|
||||
glGenBuffers(1, &buffer);
|
||||
gl.bindBuffer(mapType, buffer);
|
||||
gl.bindBuffer(mapUsage, buffer);
|
||||
|
||||
GLenum gldatausage = OpenGL::getGLBufferDataUsage(getDataUsage());
|
||||
|
||||
// initialdata can be null.
|
||||
glBufferData(target, (GLsizeiptr) getSize(), initialdata, OpenGL::getGLBufferUsage(getUsage()));
|
||||
glBufferData(target, (GLsizeiptr) getSize(), initialdata, gldatausage);
|
||||
|
||||
if (getTypeFlags() & TYPEFLAG_TEXEL)
|
||||
if (getUsageFlags() & BUFFERUSAGEFLAG_TEXEL)
|
||||
{
|
||||
glGenTextures(1, &texture);
|
||||
gl.bindBufferTextureToUnit(texture, 0, false, true);
|
||||
@@ -200,7 +206,7 @@ void Buffer::unmap(size_t usedoffset, size_t usedsize)
|
||||
mapped = false;
|
||||
|
||||
// Orphan optimization - see fill().
|
||||
if (usage != BUFFERUSAGE_STATIC && mappedRange.first == 0 && mappedRange.getSize() == getSize())
|
||||
if (dataUsage != BUFFERDATAUSAGE_STATIC && mappedRange.first == 0 && mappedRange.getSize() == getSize())
|
||||
{
|
||||
usedoffset = 0;
|
||||
usedsize = getSize();
|
||||
@@ -228,21 +234,21 @@ void Buffer::fill(size_t offset, size_t size, const void *data)
|
||||
if (!Range(0, buffersize).contains(Range(offset, size)))
|
||||
return;
|
||||
|
||||
GLenum glusage = OpenGL::getGLBufferUsage(usage);
|
||||
GLenum gldatausage = OpenGL::getGLBufferDataUsage(dataUsage);
|
||||
|
||||
gl.bindBuffer(mapType, buffer);
|
||||
gl.bindBuffer(mapUsage, buffer);
|
||||
|
||||
if (usage != BUFFERUSAGE_STATIC && size == buffersize)
|
||||
if (dataUsage != BUFFERDATAUSAGE_STATIC && size == buffersize)
|
||||
{
|
||||
// "orphan" current buffer to avoid implicit synchronisation on the GPU:
|
||||
// http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf
|
||||
gl.bindBuffer(mapType, buffer);
|
||||
glBufferData(target, (GLsizeiptr) buffersize, nullptr, glusage);
|
||||
gl.bindBuffer(mapUsage, buffer);
|
||||
glBufferData(target, (GLsizeiptr) buffersize, nullptr, gldatausage);
|
||||
|
||||
#if LOVE_WINDOWS
|
||||
// TODO: Verify that this codepath is a useful optimization.
|
||||
if (gl.getVendor() == OpenGL::VENDOR_INTEL)
|
||||
glBufferData(target, (GLsizeiptr) buffersize, data, glusage);
|
||||
glBufferData(target, (GLsizeiptr) buffersize, data, gldatausage);
|
||||
else
|
||||
#endif
|
||||
glBufferSubData(target, 0, (GLsizeiptr) buffersize, data);
|
||||
@@ -253,6 +259,14 @@ void Buffer::fill(size_t offset, size_t size, const void *data)
|
||||
}
|
||||
}
|
||||
|
||||
void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size)
|
||||
{
|
||||
gl.bindBuffer(BUFFERUSAGE_COPY_SOURCE, buffer);
|
||||
gl.bindBuffer(BUFFERUSAGE_COPY_DEST, ((Buffer *) dest)->buffer);
|
||||
|
||||
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, sourceoffset, destoffset, size);
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
void *map(MapType map, size_t offset, size_t size) override;
|
||||
void unmap(size_t usedoffset, size_t usedsize) override;
|
||||
void fill(size_t offset, size_t size, const void *data) override;
|
||||
void copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) override;
|
||||
|
||||
ptrdiff_t getHandle() const override { return buffer; };
|
||||
ptrdiff_t getTexelBufferHandle() const override { return texture; };
|
||||
@@ -64,7 +65,7 @@ private:
|
||||
void unmapStatic(size_t offset, size_t size);
|
||||
void unmapStream();
|
||||
|
||||
BufferType mapType = BUFFERTYPE_VERTEX;
|
||||
BufferUsage mapUsage = BUFFERUSAGE_VERTEX;
|
||||
GLenum target = 0;
|
||||
|
||||
// The buffer object identifier. Assigned by OpenGL.
|
||||
|
||||
@@ -157,7 +157,7 @@ const char *Graphics::getName() const
|
||||
return "love.graphics.opengl";
|
||||
}
|
||||
|
||||
love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t size)
|
||||
love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size)
|
||||
{
|
||||
return CreateStreamBuffer(type, size);
|
||||
}
|
||||
@@ -321,6 +321,9 @@ bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth,
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
if (!GLAD_ES_VERSION_2_0)
|
||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
|
||||
gl.setTextureUnit(0);
|
||||
|
||||
// Set pixel row alignment - code that calls glTexSubImage and glReadPixels
|
||||
@@ -350,46 +353,46 @@ bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth,
|
||||
{
|
||||
// Initial sizes that should be good enough for most cases. It will
|
||||
// resize to fit if needed, later.
|
||||
batchedDrawState.vb[0] = CreateStreamBuffer(BUFFERTYPE_VERTEX, 1024 * 1024 * 1);
|
||||
batchedDrawState.vb[1] = CreateStreamBuffer(BUFFERTYPE_VERTEX, 256 * 1024 * 1);
|
||||
batchedDrawState.indexBuffer = CreateStreamBuffer(BUFFERTYPE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||
batchedDrawState.vb[0] = CreateStreamBuffer(BUFFERUSAGE_VERTEX, 1024 * 1024 * 1);
|
||||
batchedDrawState.vb[1] = CreateStreamBuffer(BUFFERUSAGE_VERTEX, 256 * 1024 * 1);
|
||||
batchedDrawState.indexBuffer = CreateStreamBuffer(BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||
}
|
||||
|
||||
if (capabilities.features[FEATURE_TEXEL_BUFFER] && defaultBuffers[BUFFERTYPE_TEXEL].get() == nullptr)
|
||||
if (capabilities.features[FEATURE_TEXEL_BUFFER] && defaultBuffers[BUFFERUSAGE_TEXEL].get() == nullptr)
|
||||
{
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_TEXEL, BUFFERUSAGE_STATIC);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_TEXEL, BUFFERDATAUSAGE_STATIC);
|
||||
std::vector<Buffer::DataDeclaration> format = {{"", DATAFORMAT_FLOAT_VEC4, 0}};
|
||||
|
||||
const float texel[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
||||
auto buffer = newBuffer(settings, format, texel, sizeof(texel), 1);
|
||||
defaultBuffers[BUFFERTYPE_TEXEL].set(buffer, Acquire::NORETAIN);
|
||||
defaultBuffers[BUFFERUSAGE_TEXEL].set(buffer, Acquire::NORETAIN);
|
||||
}
|
||||
|
||||
if (capabilities.features[FEATURE_GLSL4] && defaultBuffers[BUFFERTYPE_SHADER_STORAGE].get() == nullptr)
|
||||
if (capabilities.features[FEATURE_GLSL4] && defaultBuffers[BUFFERUSAGE_SHADER_STORAGE].get() == nullptr)
|
||||
{
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_SHADER_STORAGE, BUFFERUSAGE_STATIC);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_SHADER_STORAGE, BUFFERDATAUSAGE_STATIC);
|
||||
std::vector<Buffer::DataDeclaration> format = {{"", DATAFORMAT_FLOAT, 0}};
|
||||
|
||||
std::vector<float> data;
|
||||
data.resize(Buffer::SHADER_STORAGE_BUFFER_MAX_STRIDE / 4);
|
||||
|
||||
auto buffer = newBuffer(settings, format, data.data(), data.size() * sizeof(float), data.size());
|
||||
defaultBuffers[BUFFERTYPE_TEXEL].set(buffer, Acquire::NORETAIN);
|
||||
defaultBuffers[BUFFERUSAGE_TEXEL].set(buffer, Acquire::NORETAIN);
|
||||
}
|
||||
|
||||
// Load default resources before other Volatile.
|
||||
for (int i = 0; i < BUFFERTYPE_MAX_ENUM; i++)
|
||||
for (int i = 0; i < BUFFERUSAGE_MAX_ENUM; i++)
|
||||
{
|
||||
if (defaultBuffers[i].get())
|
||||
((Buffer *) defaultBuffers[i].get())->loadVolatile();
|
||||
}
|
||||
|
||||
if (defaultBuffers[BUFFERTYPE_TEXEL].get())
|
||||
gl.setDefaultTexelBuffer((GLuint) defaultBuffers[BUFFERTYPE_TEXEL]->getTexelBufferHandle());
|
||||
if (defaultBuffers[BUFFERUSAGE_TEXEL].get())
|
||||
gl.setDefaultTexelBuffer((GLuint) defaultBuffers[BUFFERUSAGE_TEXEL]->getTexelBufferHandle());
|
||||
|
||||
if (defaultBuffers[BUFFERTYPE_SHADER_STORAGE].get())
|
||||
gl.setDefaultStorageBuffer((GLuint) defaultBuffers[BUFFERTYPE_SHADER_STORAGE]->getHandle());
|
||||
if (defaultBuffers[BUFFERUSAGE_SHADER_STORAGE].get())
|
||||
gl.setDefaultStorageBuffer((GLuint) defaultBuffers[BUFFERUSAGE_SHADER_STORAGE]->getHandle());
|
||||
|
||||
// Reload all volatile objects.
|
||||
if (!Volatile::loadAll())
|
||||
@@ -511,7 +514,7 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||
GLenum glprimitivetype = OpenGL::getGLPrimitiveType(cmd.primitiveType);
|
||||
GLenum gldatatype = OpenGL::getGLIndexDataType(cmd.indexType);
|
||||
|
||||
gl.bindBuffer(BUFFERTYPE_INDEX, cmd.indexBuffer->getHandle());
|
||||
gl.bindBuffer(BUFFERUSAGE_INDEX, cmd.indexBuffer->getHandle());
|
||||
|
||||
if (cmd.instanceCount > 1)
|
||||
glDrawElementsInstanced(glprimitivetype, cmd.indexCount, gldatatype, gloffset, cmd.instanceCount);
|
||||
@@ -553,7 +556,7 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes &attribute
|
||||
gl.bindTextureToUnit(texture, 0, false);
|
||||
gl.setCullMode(CULL_NONE);
|
||||
|
||||
gl.bindBuffer(BUFFERTYPE_INDEX, quadIndexBuffer->getHandle());
|
||||
gl.bindBuffer(BUFFERUSAGE_INDEX, quadIndexBuffer->getHandle());
|
||||
|
||||
if (gl.isBaseVertexSupported())
|
||||
{
|
||||
@@ -1462,10 +1465,9 @@ void Graphics::setBlendState(const BlendState &blend)
|
||||
|
||||
void Graphics::setPointSize(float size)
|
||||
{
|
||||
if (batchedDrawState.primitiveMode == PRIMITIVE_POINTS)
|
||||
if (size != states.back().pointSize)
|
||||
flushBatchedDraws();
|
||||
|
||||
gl.setPointSize(size * getCurrentDPIScale());
|
||||
states.back().pointSize = size;
|
||||
}
|
||||
|
||||
@@ -1553,8 +1555,9 @@ void Graphics::initCapabilities()
|
||||
capabilities.features[FEATURE_GLSL3] = GLAD_ES_VERSION_3_0 || gl.isCoreProfile();
|
||||
capabilities.features[FEATURE_GLSL4] = GLAD_ES_VERSION_3_1 || (gl.isCoreProfile() && GLAD_VERSION_4_3);
|
||||
capabilities.features[FEATURE_INSTANCING] = gl.isInstancingSupported();
|
||||
capabilities.features[FEATURE_TEXEL_BUFFER] = gl.isBufferTypeSupported(BUFFERTYPE_TEXEL);
|
||||
static_assert(FEATURE_MAX_ENUM == 11, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
|
||||
capabilities.features[FEATURE_TEXEL_BUFFER] = gl.isBufferUsageSupported(BUFFERUSAGE_TEXEL);
|
||||
capabilities.features[FEATURE_COPY_BUFFER] = gl.isBufferUsageSupported(BUFFERUSAGE_COPY_SOURCE);
|
||||
static_assert(FEATURE_MAX_ENUM == 12, "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();
|
||||
@@ -1572,14 +1575,20 @@ void Graphics::initCapabilities()
|
||||
capabilities.textureTypes[i] = gl.isTextureTypeSupported((TextureType) i);
|
||||
}
|
||||
|
||||
PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const
|
||||
PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const
|
||||
{
|
||||
uint32 requiredflags = 0;
|
||||
if (rendertarget)
|
||||
requiredflags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET;
|
||||
if (readable)
|
||||
requiredflags |= PIXELFORMATUSAGEFLAGS_SAMPLE;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case PIXELFORMAT_NORMAL:
|
||||
if (isGammaCorrect())
|
||||
return PIXELFORMAT_RGBA8_UNORM_sRGB;
|
||||
else if (!OpenGL::isPixelFormatSupported(PIXELFORMAT_RGBA8_UNORM, rendertarget, readable, sRGB))
|
||||
else if ((OpenGL::getPixelFormatUsageFlags(PIXELFORMAT_RGBA8_UNORM) & requiredflags) != requiredflags)
|
||||
// 32-bit render targets don't have guaranteed support on GLES2.
|
||||
return PIXELFORMAT_RGBA4_UNORM;
|
||||
else
|
||||
@@ -1595,18 +1604,26 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, boo
|
||||
{
|
||||
if (sRGB && format == PIXELFORMAT_RGBA8_UNORM)
|
||||
{
|
||||
format = PIXELFORMAT_RGBA8_UNORM_sRGB;
|
||||
format = getSRGBPixelFormat(format);
|
||||
sRGB = false;
|
||||
}
|
||||
|
||||
format = getSizedFormat(format, rendertarget, readable, sRGB);
|
||||
uint32 requiredflags = 0;
|
||||
if (rendertarget)
|
||||
requiredflags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET;
|
||||
if (readable)
|
||||
requiredflags |= PIXELFORMATUSAGEFLAGS_SAMPLE;
|
||||
|
||||
format = getSizedFormat(format, rendertarget, readable);
|
||||
|
||||
OptionalBool &supported = supportedFormats[format][rendertarget ? 1 : 0][readable ? 1 : 0][sRGB ? 1 : 0];
|
||||
|
||||
if (supported.hasValue)
|
||||
return supported.value;
|
||||
|
||||
if (!OpenGL::isPixelFormatSupported(format, rendertarget, readable, sRGB))
|
||||
auto supportedflags = OpenGL::getPixelFormatUsageFlags(format);
|
||||
|
||||
if ((requiredflags & supportedflags) != requiredflags)
|
||||
{
|
||||
supported.set(false);
|
||||
return supported.value;
|
||||
@@ -1636,7 +1653,7 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, boo
|
||||
return true;
|
||||
}
|
||||
|
||||
OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, readable, sRGB);
|
||||
OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, !readable, sRGB);
|
||||
|
||||
GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
|
||||
void setWireframe(bool enable) override;
|
||||
|
||||
PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const override;
|
||||
PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override;
|
||||
bool isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB = false) override;
|
||||
Renderer getRenderer() const override;
|
||||
bool usesGLSLES() const override;
|
||||
@@ -139,7 +139,7 @@ private:
|
||||
|
||||
love::graphics::ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) override;
|
||||
love::graphics::Shader *newShaderInternal(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel) override;
|
||||
love::graphics::StreamBuffer *newStreamBuffer(BufferType type, size_t size) override;
|
||||
love::graphics::StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) override;
|
||||
void setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBtexture) override;
|
||||
void initCapabilities() override;
|
||||
void getAPIStats(int &shaderswitches) const override;
|
||||
@@ -167,7 +167,7 @@ private:
|
||||
size_t bufferMapMemorySize;
|
||||
|
||||
// Only needed for buffer types that can be bound to shaders.
|
||||
StrongRef<love::graphics::Buffer> defaultBuffers[BUFFERTYPE_MAX_ENUM];
|
||||
StrongRef<love::graphics::Buffer> defaultBuffers[BUFFERUSAGE_MAX_ENUM];
|
||||
|
||||
// [rendertarget][readable][srgb]
|
||||
OptionalBool supportedFormats[PIXELFORMAT_MAX_ENUM][2][2][2];
|
||||
|
||||
@@ -235,15 +235,15 @@ void OpenGL::setupContext()
|
||||
glGetIntegerv(GL_CULL_FACE_MODE, &faceCull);
|
||||
state.faceCullMode = faceCull;
|
||||
|
||||
for (int i = 0; i < (int) BUFFERTYPE_MAX_ENUM; i++)
|
||||
for (int i = 0; i < (int) BUFFERUSAGE_MAX_ENUM; i++)
|
||||
{
|
||||
state.boundBuffers[i] = 0;
|
||||
if (isBufferTypeSupported((BufferType) i))
|
||||
glBindBuffer(getGLBufferType((BufferType) i), 0);
|
||||
if (isBufferUsageSupported((BufferUsage) i))
|
||||
glBindBuffer(getGLBufferType((BufferUsage) i), 0);
|
||||
}
|
||||
|
||||
if (isBufferTypeSupported(BUFFERTYPE_SHADER_STORAGE))
|
||||
state.boundIndexedBuffers[BUFFERTYPE_SHADER_STORAGE].resize(maxShaderStorageBufferBindings, 0);
|
||||
if (isBufferUsageSupported(BUFFERUSAGE_SHADER_STORAGE))
|
||||
state.boundIndexedBuffers[BUFFERUSAGE_SHADER_STORAGE].resize(maxShaderStorageBufferBindings, 0);
|
||||
|
||||
// Initialize multiple texture unit support for shaders.
|
||||
for (int i = 0; i < TEXTURE_MAX_ENUM + 1; i++)
|
||||
@@ -484,12 +484,12 @@ void OpenGL::initMaxValues()
|
||||
else
|
||||
maxTextureArrayLayers = 0;
|
||||
|
||||
if (isBufferTypeSupported(BUFFERTYPE_TEXEL))
|
||||
if (isBufferUsageSupported(BUFFERUSAGE_TEXEL))
|
||||
glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTexelBufferSize);
|
||||
else
|
||||
maxTexelBufferSize = 0;
|
||||
|
||||
if (isBufferTypeSupported(BUFFERTYPE_SHADER_STORAGE))
|
||||
if (isBufferUsageSupported(BUFFERUSAGE_SHADER_STORAGE))
|
||||
{
|
||||
glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxShaderStorageBufferSize);
|
||||
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxShaderStorageBufferBindings);
|
||||
@@ -613,16 +613,18 @@ GLenum OpenGL::getGLPrimitiveType(PrimitiveType type)
|
||||
return GL_ZERO;
|
||||
}
|
||||
|
||||
GLenum OpenGL::getGLBufferType(BufferType type)
|
||||
GLenum OpenGL::getGLBufferType(BufferUsage usage)
|
||||
{
|
||||
switch (type)
|
||||
switch (usage)
|
||||
{
|
||||
case BUFFERTYPE_VERTEX: return GL_ARRAY_BUFFER;
|
||||
case BUFFERTYPE_INDEX: return GL_ELEMENT_ARRAY_BUFFER;
|
||||
case BUFFERTYPE_TEXEL: return GL_TEXTURE_BUFFER;
|
||||
case BUFFERTYPE_UNIFORM: return GL_UNIFORM_BUFFER;
|
||||
case BUFFERTYPE_SHADER_STORAGE: return GL_SHADER_STORAGE_BUFFER;
|
||||
case BUFFERTYPE_MAX_ENUM: return GL_ZERO;
|
||||
case BUFFERUSAGE_VERTEX: return GL_ARRAY_BUFFER;
|
||||
case BUFFERUSAGE_INDEX: return GL_ELEMENT_ARRAY_BUFFER;
|
||||
case BUFFERUSAGE_UNIFORM: return GL_UNIFORM_BUFFER;
|
||||
case BUFFERUSAGE_TEXEL: return GL_TEXTURE_BUFFER;
|
||||
case BUFFERUSAGE_SHADER_STORAGE: return GL_SHADER_STORAGE_BUFFER;
|
||||
case BUFFERUSAGE_COPY_SOURCE: return GL_COPY_READ_BUFFER;
|
||||
case BUFFERUSAGE_COPY_DEST: return GL_COPY_WRITE_BUFFER;
|
||||
case BUFFERUSAGE_MAX_ENUM: return GL_ZERO;
|
||||
}
|
||||
|
||||
return GL_ZERO;
|
||||
@@ -791,18 +793,18 @@ GLenum OpenGL::getGLVertexDataType(DataFormat format, int &components, GLboolean
|
||||
return GL_ZERO;
|
||||
}
|
||||
|
||||
GLenum OpenGL::getGLBufferUsage(BufferUsage usage)
|
||||
GLenum OpenGL::getGLBufferDataUsage(BufferDataUsage usage)
|
||||
{
|
||||
switch (usage)
|
||||
{
|
||||
case BUFFERUSAGE_STREAM: return GL_STREAM_DRAW;
|
||||
case BUFFERUSAGE_DYNAMIC: return GL_DYNAMIC_DRAW;
|
||||
case BUFFERUSAGE_STATIC: return GL_STATIC_DRAW;
|
||||
case BUFFERDATAUSAGE_STREAM: return GL_STREAM_DRAW;
|
||||
case BUFFERDATAUSAGE_DYNAMIC: return GL_DYNAMIC_DRAW;
|
||||
case BUFFERDATAUSAGE_STATIC: return GL_STATIC_DRAW;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGL::bindBuffer(BufferType type, GLuint buffer)
|
||||
void OpenGL::bindBuffer(BufferUsage type, GLuint buffer)
|
||||
{
|
||||
if (state.boundBuffers[type] != buffer)
|
||||
{
|
||||
@@ -815,7 +817,7 @@ void OpenGL::deleteBuffer(GLuint buffer)
|
||||
{
|
||||
glDeleteBuffers(1, &buffer);
|
||||
|
||||
for (int i = 0; i < (int) BUFFERTYPE_MAX_ENUM; i++)
|
||||
for (int i = 0; i < (int) BUFFERUSAGE_MAX_ENUM; i++)
|
||||
{
|
||||
if (state.boundBuffers[i] == buffer)
|
||||
state.boundBuffers[i] = 0;
|
||||
@@ -868,7 +870,7 @@ void OpenGL::setVertexAttributes(const VertexAttributes &attributes, const Buffe
|
||||
|
||||
const void *offsetpointer = reinterpret_cast<void*>(bufferinfo.offset + attrib.offsetFromVertex);
|
||||
|
||||
bindBuffer(BUFFERTYPE_VERTEX, (GLuint) bufferinfo.buffer->getHandle());
|
||||
bindBuffer(BUFFERUSAGE_VERTEX, (GLuint) bufferinfo.buffer->getHandle());
|
||||
|
||||
if (intformat)
|
||||
glVertexAttribIPointer(i, components, gltype, layout.stride, offsetpointer);
|
||||
@@ -942,19 +944,6 @@ void OpenGL::setScissor(const Rect &v, bool rtActive)
|
||||
state.scissor = v;
|
||||
}
|
||||
|
||||
void OpenGL::setPointSize(float size)
|
||||
{
|
||||
if (GLAD_VERSION_1_0)
|
||||
glPointSize(size);
|
||||
|
||||
state.pointSize = size;
|
||||
}
|
||||
|
||||
float OpenGL::getPointSize() const
|
||||
{
|
||||
return state.pointSize;
|
||||
}
|
||||
|
||||
void OpenGL::setEnableState(EnableState enablestate, bool enable)
|
||||
{
|
||||
GLenum glstate = GL_NONE;
|
||||
@@ -1164,7 +1153,7 @@ void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restorepr
|
||||
bindTextureToUnit(textype, handle, textureunit, restoreprev, bindforedit);
|
||||
}
|
||||
|
||||
void OpenGL::bindIndexedBuffer(GLuint buffer, BufferType type, int index)
|
||||
void OpenGL::bindIndexedBuffer(GLuint buffer, BufferUsage type, int index)
|
||||
{
|
||||
auto &bindings = state.boundIndexedBuffers[type];
|
||||
if (bindings.size() > (size_t) index && buffer != bindings[index])
|
||||
@@ -1433,19 +1422,22 @@ bool OpenGL::isTextureTypeSupported(TextureType type) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpenGL::isBufferTypeSupported(BufferType type) const
|
||||
bool OpenGL::isBufferUsageSupported(BufferUsage usage) const
|
||||
{
|
||||
switch (type)
|
||||
switch (usage)
|
||||
{
|
||||
case BUFFERTYPE_VERTEX:
|
||||
case BUFFERTYPE_INDEX:
|
||||
case BUFFERUSAGE_VERTEX:
|
||||
case BUFFERUSAGE_INDEX:
|
||||
return true;
|
||||
case BUFFERTYPE_TEXEL:
|
||||
case BUFFERUSAGE_TEXEL:
|
||||
// Not supported in ES until 3.2, which we don't support shaders for...
|
||||
return GLAD_VERSION_3_1;
|
||||
case BUFFERTYPE_SHADER_STORAGE:
|
||||
case BUFFERUSAGE_SHADER_STORAGE:
|
||||
return (GLAD_VERSION_4_3 && isCoreProfile()) || GLAD_ES_VERSION_3_1;
|
||||
case BUFFERTYPE_MAX_ENUM:
|
||||
case BUFFERUSAGE_COPY_SOURCE:
|
||||
case BUFFERUSAGE_COPY_DEST:
|
||||
return GLAD_VERSION_3_1 || GLAD_ES_VERSION_3_0;
|
||||
case BUFFERUSAGE_MAX_ENUM:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
@@ -1933,152 +1925,178 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r
|
||||
return f;
|
||||
}
|
||||
|
||||
bool OpenGL::isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget, bool readable, bool isSRGB)
|
||||
uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat)
|
||||
{
|
||||
if (rendertarget && isPixelFormatCompressed(pixelformat))
|
||||
return false;
|
||||
const uint32 commonsample = PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_LINEAR;
|
||||
const uint32 commonrender = PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_BLEND | PIXELFORMATUSAGEFLAGS_MSAA;
|
||||
|
||||
if (isSRGB)
|
||||
pixelformat = getSRGBPixelFormat(pixelformat);
|
||||
uint32 flags = PIXELFORMATUSAGEFLAGS_NONE;
|
||||
|
||||
switch (pixelformat)
|
||||
{
|
||||
case PIXELFORMAT_R8_UNORM:
|
||||
case PIXELFORMAT_RG8_UNORM:
|
||||
if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_ARB_texture_rg || GLAD_EXT_texture_rg)
|
||||
return true;
|
||||
else if (pixelformat == PIXELFORMAT_R8_UNORM && !rendertarget && (GLAD_ES_VERSION_2_0 || GLAD_VERSION_1_1))
|
||||
return true; // We'll use OpenGL's luminance format internally.
|
||||
else
|
||||
return false;
|
||||
flags |= commonsample | commonrender;
|
||||
else if (pixelformat == PIXELFORMAT_R8_UNORM && (GLAD_ES_VERSION_2_0 || GLAD_VERSION_1_1))
|
||||
flags |= commonsample; // We'll use OpenGL's luminance format internally.
|
||||
break;
|
||||
case PIXELFORMAT_RGBA8_UNORM:
|
||||
if (rendertarget)
|
||||
return GLAD_VERSION_1_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8;
|
||||
else
|
||||
return true;
|
||||
flags |= commonsample;
|
||||
if (GLAD_VERSION_1_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8)
|
||||
flags |= commonrender;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA8_UNORM_sRGB:
|
||||
if (gl.bugs.brokenSRGB)
|
||||
return false;
|
||||
if (rendertarget)
|
||||
{
|
||||
if (GLAD_VERSION_1_0)
|
||||
{
|
||||
return GLAD_VERSION_3_0 || ((GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
|
||||
&& (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB));
|
||||
}
|
||||
else
|
||||
return GLAD_ES_VERSION_3_0;
|
||||
}
|
||||
else
|
||||
return GLAD_ES_VERSION_3_0 || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB;
|
||||
break;
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB)
|
||||
flags |= commonsample;
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0
|
||||
|| ((GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB) && (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB)))
|
||||
flags |= commonrender;
|
||||
break;
|
||||
case PIXELFORMAT_R16_UNORM:
|
||||
case PIXELFORMAT_RG16_UNORM:
|
||||
return GLAD_VERSION_3_0
|
||||
if (GLAD_VERSION_3_0
|
||||
|| (GLAD_VERSION_1_1 && GLAD_ARB_texture_rg)
|
||||
|| (GLAD_EXT_texture_norm16 && (GLAD_ES_VERSION_3_0 || GLAD_EXT_texture_rg));
|
||||
|| (GLAD_EXT_texture_norm16 && (GLAD_ES_VERSION_3_0 || GLAD_EXT_texture_rg)))
|
||||
flags |= commonsample | commonrender;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA16_UNORM:
|
||||
return GLAD_VERSION_1_1 || GLAD_EXT_texture_norm16;
|
||||
if (GLAD_VERSION_1_1 || GLAD_EXT_texture_norm16)
|
||||
flags |= commonsample | commonrender;
|
||||
break;
|
||||
case PIXELFORMAT_R16_FLOAT:
|
||||
case PIXELFORMAT_RG16_FLOAT:
|
||||
if (GLAD_VERSION_1_0)
|
||||
return GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel && GLAD_ARB_texture_rg);
|
||||
else if (rendertarget && !GLAD_EXT_color_buffer_half_float)
|
||||
return false;
|
||||
else
|
||||
return GLAD_ES_VERSION_3_0 || (GLAD_OES_texture_half_float && GLAD_EXT_texture_rg);
|
||||
if (GLAD_VERSION_1_0 && (GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel && GLAD_ARB_texture_rg)))
|
||||
flags |= commonsample | commonrender;
|
||||
if (GLAD_ES_VERSION_3_0 || (GLAD_OES_texture_half_float && GLAD_EXT_texture_rg))
|
||||
flags |= commonsample;
|
||||
if (GLAD_EXT_color_buffer_half_float && (GLAD_ES_VERSION_3_0 || GLAD_EXT_texture_rg))
|
||||
flags |= commonrender;
|
||||
if (!(GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear))
|
||||
flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA16_FLOAT:
|
||||
if (GLAD_VERSION_1_0)
|
||||
return GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel);
|
||||
else if (rendertarget && !GLAD_EXT_color_buffer_half_float)
|
||||
return false;
|
||||
else
|
||||
return GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float;
|
||||
if (GLAD_VERSION_3_0 || (GLAD_VERSION_1_0 && GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel))
|
||||
flags |= commonsample | commonrender;
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float)
|
||||
flags |= commonsample;
|
||||
if (GLAD_EXT_color_buffer_half_float)
|
||||
flags |= commonrender;
|
||||
if (!(GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear))
|
||||
flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR;
|
||||
break;
|
||||
case PIXELFORMAT_R32_FLOAT:
|
||||
case PIXELFORMAT_RG32_FLOAT:
|
||||
if (GLAD_VERSION_1_0)
|
||||
return GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_texture_rg);
|
||||
else if (!rendertarget)
|
||||
return GLAD_ES_VERSION_3_0 || (GLAD_OES_texture_float && GLAD_EXT_texture_rg);
|
||||
else
|
||||
return false;
|
||||
if (GLAD_VERSION_3_0 || (GLAD_VERSION_1_0 && GLAD_ARB_texture_float && GLAD_ARB_texture_rg))
|
||||
flags |= commonsample | commonrender;
|
||||
if (GLAD_ES_VERSION_3_0 || (GLAD_OES_texture_float && GLAD_EXT_texture_rg))
|
||||
flags |= commonsample;
|
||||
if (!(GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear))
|
||||
flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA32_FLOAT:
|
||||
if (GLAD_VERSION_1_0)
|
||||
return GLAD_VERSION_3_0 || GLAD_ARB_texture_float;
|
||||
else if (!rendertarget)
|
||||
return GLAD_ES_VERSION_3_0 || GLAD_OES_texture_float;
|
||||
else
|
||||
return false;
|
||||
if (GLAD_VERSION_3_0 || (GLAD_VERSION_1_0 && GLAD_ARB_texture_float))
|
||||
flags |= commonsample | commonrender;
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_OES_texture_float)
|
||||
flags |= commonsample;
|
||||
if (!(GLAD_VERSION_1_1 || GLAD_OES_texture_float_linear))
|
||||
flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_LA8_UNORM:
|
||||
return !rendertarget;
|
||||
flags |= commonsample;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_RGBA4_UNORM:
|
||||
case PIXELFORMAT_RGB5A1_UNORM:
|
||||
return true;
|
||||
flags |= commonsample | commonrender;
|
||||
break;
|
||||
case PIXELFORMAT_RGB565_UNORM:
|
||||
return GLAD_ES_VERSION_2_0 || GLAD_VERSION_4_2 || GLAD_ARB_ES2_compatibility;
|
||||
if (GLAD_ES_VERSION_2_0 || GLAD_VERSION_4_2 || GLAD_ARB_ES2_compatibility)
|
||||
flags |= commonsample | commonrender;
|
||||
break;
|
||||
case PIXELFORMAT_RGB10A2_UNORM:
|
||||
return GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0;
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0)
|
||||
flags |= commonsample | commonrender;
|
||||
break;
|
||||
case PIXELFORMAT_RG11B10_FLOAT:
|
||||
if (rendertarget)
|
||||
return GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_color_buffer_packed_float;
|
||||
else
|
||||
return GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_texture_packed_float;
|
||||
if (GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_texture_packed_float)
|
||||
flags |= commonsample;
|
||||
if (GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_color_buffer_packed_float)
|
||||
flags |= commonrender;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_STENCIL8:
|
||||
return rendertarget && !readable;
|
||||
flags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_DEPTH16_UNORM:
|
||||
if (!rendertarget)
|
||||
return false;
|
||||
else if (readable)
|
||||
return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_depth_texture;
|
||||
else
|
||||
return true;
|
||||
flags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA;
|
||||
if (GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_depth_texture)
|
||||
flags |= commonsample;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_DEPTH24_UNORM:
|
||||
if (!rendertarget)
|
||||
return false;
|
||||
else if (readable)
|
||||
return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || (GLAD_OES_depth_texture && (GLAD_OES_depth24 || GLAD_OES_depth_texture));
|
||||
else
|
||||
return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_depth24 || GLAD_OES_depth_texture;
|
||||
if (GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_depth24 || GLAD_OES_depth_texture)
|
||||
flags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA;
|
||||
|
||||
if (GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || (GLAD_OES_depth_texture && (GLAD_OES_depth24 || GLAD_OES_depth_texture)))
|
||||
flags |= commonsample;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_DEPTH24_UNORM_STENCIL8:
|
||||
if (!rendertarget)
|
||||
return false;
|
||||
else if (readable)
|
||||
return GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_packed_depth_stencil || (GLAD_OES_depth_texture && GLAD_OES_packed_depth_stencil);
|
||||
else
|
||||
return GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_packed_depth_stencil || GLAD_OES_packed_depth_stencil;
|
||||
if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_packed_depth_stencil || GLAD_OES_packed_depth_stencil)
|
||||
flags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA;
|
||||
|
||||
if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_packed_depth_stencil || (GLAD_OES_depth_texture && GLAD_OES_packed_depth_stencil))
|
||||
flags |= commonsample;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_DEPTH32_FLOAT:
|
||||
case PIXELFORMAT_DEPTH32_FLOAT_STENCIL8:
|
||||
return rendertarget && (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_ARB_depth_buffer_float);
|
||||
if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_ARB_depth_buffer_float)
|
||||
flags |= commonsample | PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_DXT1_UNORM:
|
||||
return GLAD_EXT_texture_compression_s3tc || GLAD_EXT_texture_compression_dxt1;
|
||||
if (GLAD_EXT_texture_compression_s3tc || GLAD_EXT_texture_compression_dxt1)
|
||||
flags |= commonsample;
|
||||
break;
|
||||
case PIXELFORMAT_DXT3_UNORM:
|
||||
return GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt3;
|
||||
if (GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt3)
|
||||
flags |= commonsample;
|
||||
break;
|
||||
case PIXELFORMAT_DXT5_UNORM:
|
||||
return GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt5;
|
||||
if (GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt5)
|
||||
flags |= commonsample;
|
||||
break;
|
||||
case PIXELFORMAT_BC4_UNORM:
|
||||
case PIXELFORMAT_BC4_SNORM:
|
||||
case PIXELFORMAT_BC5_UNORM:
|
||||
case PIXELFORMAT_BC5_SNORM:
|
||||
return (GLAD_VERSION_3_0 || GLAD_ARB_texture_compression_rgtc || GLAD_EXT_texture_compression_rgtc);
|
||||
if (GLAD_VERSION_3_0 || GLAD_ARB_texture_compression_rgtc || GLAD_EXT_texture_compression_rgtc)
|
||||
flags |= commonsample;
|
||||
break;
|
||||
case PIXELFORMAT_BC6H_UFLOAT:
|
||||
case PIXELFORMAT_BC6H_FLOAT:
|
||||
case PIXELFORMAT_BC7_UNORM:
|
||||
return GLAD_VERSION_4_2 || GLAD_ARB_texture_compression_bptc;
|
||||
if (GLAD_VERSION_4_2 || GLAD_ARB_texture_compression_bptc)
|
||||
flags |= commonsample;
|
||||
break;
|
||||
case PIXELFORMAT_PVR1_RGB2_UNORM:
|
||||
case PIXELFORMAT_PVR1_RGB4_UNORM:
|
||||
case PIXELFORMAT_PVR1_RGBA2_UNORM:
|
||||
case PIXELFORMAT_PVR1_RGBA4_UNORM:
|
||||
return isSRGB ? GLAD_EXT_pvrtc_sRGB : GLAD_IMG_texture_compression_pvrtc;
|
||||
if (GLAD_IMG_texture_compression_pvrtc)
|
||||
flags |= commonsample;
|
||||
break;
|
||||
case PIXELFORMAT_ETC1_UNORM:
|
||||
// ETC2 support guarantees ETC1 support as well.
|
||||
return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility || GLAD_OES_compressed_ETC1_RGB8_texture;
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility || GLAD_OES_compressed_ETC1_RGB8_texture)
|
||||
flags |= commonsample;
|
||||
break;
|
||||
case PIXELFORMAT_ETC2_RGB_UNORM:
|
||||
case PIXELFORMAT_ETC2_RGBA_UNORM:
|
||||
case PIXELFORMAT_ETC2_RGBA1_UNORM:
|
||||
@@ -2086,7 +2104,9 @@ bool OpenGL::isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget,
|
||||
case PIXELFORMAT_EAC_R_SNORM:
|
||||
case PIXELFORMAT_EAC_RG_UNORM:
|
||||
case PIXELFORMAT_EAC_RG_SNORM:
|
||||
return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility;
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility)
|
||||
flags |= commonsample;
|
||||
break;
|
||||
case PIXELFORMAT_ASTC_4x4:
|
||||
case PIXELFORMAT_ASTC_5x4:
|
||||
case PIXELFORMAT_ASTC_5x5:
|
||||
@@ -2101,28 +2121,18 @@ bool OpenGL::isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget,
|
||||
case PIXELFORMAT_ASTC_10x10:
|
||||
case PIXELFORMAT_ASTC_12x10:
|
||||
case PIXELFORMAT_ASTC_12x12:
|
||||
return GLAD_ES_VERSION_3_2 || GLAD_KHR_texture_compression_astc_ldr;
|
||||
if (GLAD_ES_VERSION_3_2 || GLAD_KHR_texture_compression_astc_ldr)
|
||||
flags |= commonsample;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
case PIXELFORMAT_UNKNOWN:
|
||||
case PIXELFORMAT_NORMAL:
|
||||
case PIXELFORMAT_HDR:
|
||||
case PIXELFORMAT_MAX_ENUM:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenGL::hasTextureFilteringSupport(PixelFormat pixelformat)
|
||||
{
|
||||
switch (pixelformat)
|
||||
{
|
||||
case PIXELFORMAT_R16_FLOAT:
|
||||
case PIXELFORMAT_RG16_FLOAT:
|
||||
case PIXELFORMAT_RGBA16_FLOAT:
|
||||
return GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear;
|
||||
case PIXELFORMAT_R32_FLOAT:
|
||||
case PIXELFORMAT_RG32_FLOAT:
|
||||
case PIXELFORMAT_RGBA32_FLOAT:
|
||||
return GLAD_VERSION_1_1 || GLAD_OES_texture_float_linear;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
const char *OpenGL::errorString(GLenum errorcode)
|
||||
|
||||
@@ -235,7 +235,7 @@ public:
|
||||
* NOTE: This does not account for multiple VAOs being used! Index buffer
|
||||
* bindings are per-VAO in OpenGL, but this doesn't know about that.
|
||||
**/
|
||||
void bindBuffer(BufferType type, GLuint buffer);
|
||||
void bindBuffer(BufferUsage type, GLuint buffer);
|
||||
|
||||
/**
|
||||
* glDeleteBuffers which updates our shadowed state.
|
||||
@@ -270,12 +270,6 @@ public:
|
||||
**/
|
||||
void setScissor(const Rect &v, bool rtActive);
|
||||
|
||||
/**
|
||||
* Sets the global point size.
|
||||
**/
|
||||
void setPointSize(float size);
|
||||
float getPointSize() const;
|
||||
|
||||
/**
|
||||
* State-tracked version of glEnable.
|
||||
**/
|
||||
@@ -341,7 +335,7 @@ public:
|
||||
|
||||
void bindBufferTextureToUnit(GLuint texture, int textureunit, bool restoreprev, bool bindforedit);
|
||||
|
||||
void bindIndexedBuffer(GLuint buffer, BufferType type, int index);
|
||||
void bindIndexedBuffer(GLuint buffer, BufferUsage type, int index);
|
||||
|
||||
/**
|
||||
* Helper for deleting an OpenGL texture.
|
||||
@@ -362,7 +356,7 @@ public:
|
||||
bool rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, bool &isSRGB, int width, int height, int depth = 1);
|
||||
|
||||
bool isTextureTypeSupported(TextureType type) const;
|
||||
bool isBufferTypeSupported(BufferType type) const;
|
||||
bool isBufferUsageSupported(BufferUsage usage) const;
|
||||
bool isClampZeroOneTextureWrapSupported() const;
|
||||
bool isPixelShaderHighpSupported() const;
|
||||
bool isInstancingSupported() const;
|
||||
@@ -433,18 +427,17 @@ public:
|
||||
Vendor getVendor() const;
|
||||
|
||||
static GLenum getGLPrimitiveType(PrimitiveType type);
|
||||
static GLenum getGLBufferType(BufferType type);
|
||||
static GLenum getGLBufferType(BufferUsage usage);
|
||||
static GLenum getGLIndexDataType(IndexDataType type);
|
||||
static GLenum getGLVertexDataType(DataFormat format, int &components, GLboolean &normalized, bool &intformat);
|
||||
static GLenum getGLBufferUsage(BufferUsage usage);
|
||||
static GLenum getGLBufferDataUsage(BufferDataUsage usage);
|
||||
static GLenum getGLTextureType(TextureType type);
|
||||
static GLint getGLWrapMode(SamplerState::WrapMode wmode);
|
||||
static GLint getGLCompareMode(CompareMode mode);
|
||||
|
||||
static TextureFormat convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB);
|
||||
static bool isTexStorageSupported();
|
||||
static bool isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget, bool readable, bool isSRGB);
|
||||
static bool hasTextureFilteringSupport(PixelFormat pixelformat);
|
||||
static uint32 getPixelFormatUsageFlags(PixelFormat pixelformat);
|
||||
|
||||
static const char *errorString(GLenum errorcode);
|
||||
static const char *framebufferStatusString(GLenum status);
|
||||
@@ -487,12 +480,12 @@ private:
|
||||
// Tracked OpenGL state.
|
||||
struct
|
||||
{
|
||||
GLuint boundBuffers[BUFFERTYPE_MAX_ENUM];
|
||||
GLuint boundBuffers[BUFFERUSAGE_MAX_ENUM];
|
||||
|
||||
// Texture unit state (currently bound texture for each texture unit.)
|
||||
std::vector<GLuint> boundTextures[TEXTURE_MAX_ENUM + 1];
|
||||
|
||||
std::vector<GLuint> boundIndexedBuffers[BUFFERTYPE_MAX_ENUM];
|
||||
std::vector<GLuint> boundIndexedBuffers[BUFFERUSAGE_MAX_ENUM];
|
||||
|
||||
bool enableState[ENABLE_MAX_ENUM];
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage
|
||||
, program(0)
|
||||
, builtinUniforms()
|
||||
, builtinUniformInfo()
|
||||
, lastPointSize(0.0f)
|
||||
{
|
||||
// load shader source and create program object
|
||||
loadVolatile();
|
||||
@@ -315,7 +314,7 @@ void Shader::mapActiveUniforms()
|
||||
}
|
||||
}
|
||||
|
||||
if (gl.isBufferTypeSupported(BUFFERTYPE_SHADER_STORAGE))
|
||||
if (gl.isBufferUsageSupported(BUFFERUSAGE_SHADER_STORAGE))
|
||||
{
|
||||
GLint numstoragebuffers = 0;
|
||||
glGetProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &numstoragebuffers);
|
||||
@@ -430,8 +429,6 @@ bool Shader::loadVolatile()
|
||||
{
|
||||
OpenGL::TempDebugGroup debuggroup("Shader load");
|
||||
|
||||
lastPointSize = -1.0f;
|
||||
|
||||
// zero out active texture list
|
||||
textureUnits.clear();
|
||||
textureUnits.push_back(TextureUnit());
|
||||
@@ -577,7 +574,7 @@ void Shader::attach()
|
||||
}
|
||||
|
||||
for (auto bufferbinding : activeStorageBufferBindings)
|
||||
gl.bindIndexedBuffer(bufferbinding.buffer, BUFFERTYPE_SHADER_STORAGE, bufferbinding.bindingindex);
|
||||
gl.bindIndexedBuffer(bufferbinding.buffer, BUFFERUSAGE_SHADER_STORAGE, bufferbinding.bindingindex);
|
||||
|
||||
// send any pending uniforms to the shader program.
|
||||
for (const auto &p : pendingUniformUpdates)
|
||||
@@ -807,9 +804,9 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
|
||||
bool storagebinding = info->baseType == UNIFORM_STORAGEBUFFER;
|
||||
|
||||
if (texelbinding)
|
||||
requiredtypeflags = Buffer::TYPEFLAG_TEXEL;
|
||||
requiredtypeflags = BUFFERUSAGEFLAG_TEXEL;
|
||||
else if (storagebinding)
|
||||
requiredtypeflags = Buffer::TYPEFLAG_SHADER_STORAGE;
|
||||
requiredtypeflags = BUFFERUSAGEFLAG_SHADER_STORAGE;
|
||||
|
||||
if (requiredtypeflags == 0)
|
||||
return;
|
||||
@@ -828,7 +825,7 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
|
||||
|
||||
if (buffer != nullptr)
|
||||
{
|
||||
if ((buffer->getTypeFlags() & requiredtypeflags) == 0)
|
||||
if ((buffer->getUsageFlags() & requiredtypeflags) == 0)
|
||||
{
|
||||
if (internalUpdate)
|
||||
continue;
|
||||
@@ -906,7 +903,7 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
|
||||
glbuffer = gl.getDefaultStorageBuffer();
|
||||
|
||||
if (shaderactive)
|
||||
gl.bindIndexedBuffer(glbuffer, BUFFERTYPE_SHADER_STORAGE, bindingindex);
|
||||
gl.bindIndexedBuffer(glbuffer, BUFFERUSAGE_SHADER_STORAGE, bindingindex);
|
||||
|
||||
int activeindex = storageBufferBindingIndexToActiveBinding[bindingindex];
|
||||
if (activeindex >= 0)
|
||||
@@ -962,26 +959,11 @@ void Shader::setVideoTextures(love::graphics::Texture *ytexture, love::graphics:
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::updatePointSize(float size)
|
||||
{
|
||||
if (size == lastPointSize || current != this)
|
||||
return;
|
||||
|
||||
GLint location = builtinUniforms[BUILTIN_POINT_SIZE];
|
||||
if (location >= 0)
|
||||
glUniform1f(location, size);
|
||||
|
||||
lastPointSize = size;
|
||||
}
|
||||
|
||||
void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, int viewportH)
|
||||
{
|
||||
if (current != this)
|
||||
return;
|
||||
|
||||
if (GLAD_ES_VERSION_2_0)
|
||||
updatePointSize(gl.getPointSize());
|
||||
|
||||
BuiltinUniformData data;
|
||||
|
||||
data.transformMatrix = gfx->getTransform();
|
||||
@@ -1001,6 +983,12 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW,
|
||||
}
|
||||
}
|
||||
|
||||
// Store DPI scale in an unused component of another vector.
|
||||
data.normalMatrix[0].w = (float) gfx->getCurrentDPIScale();
|
||||
|
||||
// Same with point size.
|
||||
data.normalMatrix[1].w = gfx->getPointSize();
|
||||
|
||||
data.screenSizeParams.x = viewportW;
|
||||
data.screenSizeParams.y = viewportH;
|
||||
|
||||
|
||||
@@ -43,10 +43,6 @@ class Shader final : public love::graphics::Shader, public Volatile
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new Shader using a list of source codes.
|
||||
* Source must contain either vertex or pixel shader code, or both.
|
||||
**/
|
||||
Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel);
|
||||
virtual ~Shader();
|
||||
|
||||
@@ -67,7 +63,6 @@ public:
|
||||
ptrdiff_t getHandle() const override;
|
||||
void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override;
|
||||
|
||||
void updatePointSize(float size);
|
||||
void updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, int viewportH);
|
||||
|
||||
private:
|
||||
@@ -125,8 +120,6 @@ private:
|
||||
|
||||
std::vector<std::pair<const UniformInfo *, int>> pendingUniformUpdates;
|
||||
|
||||
float lastPointSize;
|
||||
|
||||
}; // Shader
|
||||
|
||||
} // opengl
|
||||
|
||||
@@ -44,7 +44,7 @@ class StreamBufferClientMemory final : public love::graphics::StreamBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
StreamBufferClientMemory(BufferType mode, size_t size)
|
||||
StreamBufferClientMemory(BufferUsage mode, size_t size)
|
||||
: love::graphics::StreamBuffer(mode, size)
|
||||
, data(nullptr)
|
||||
{
|
||||
@@ -86,7 +86,7 @@ class StreamBufferSubDataOrphan final : public love::graphics::StreamBuffer, pub
|
||||
{
|
||||
public:
|
||||
|
||||
StreamBufferSubDataOrphan(BufferType mode, size_t size)
|
||||
StreamBufferSubDataOrphan(BufferUsage mode, size_t size)
|
||||
: love::graphics::StreamBuffer(mode, size)
|
||||
, vbo(0)
|
||||
, glMode(OpenGL::getGLBufferType(mode))
|
||||
@@ -184,7 +184,7 @@ class StreamBufferSync : public love::graphics::StreamBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
StreamBufferSync(BufferType type, size_t size)
|
||||
StreamBufferSync(BufferUsage type, size_t size)
|
||||
: love::graphics::StreamBuffer(type, size)
|
||||
, frameIndex(0)
|
||||
, syncs()
|
||||
@@ -220,7 +220,7 @@ class StreamBufferMapSync final : public StreamBufferSync, public Volatile
|
||||
{
|
||||
public:
|
||||
|
||||
StreamBufferMapSync(BufferType type, size_t size)
|
||||
StreamBufferMapSync(BufferUsage type, size_t size)
|
||||
: StreamBufferSync(type, size)
|
||||
, vbo(0)
|
||||
, glMode(OpenGL::getGLBufferType(mode))
|
||||
@@ -302,7 +302,7 @@ public:
|
||||
|
||||
// Coherent mapping is supposedly faster on intel/nvidia aside from a couple
|
||||
// old nvidia GPUs.
|
||||
StreamBufferPersistentMapSync(BufferType type, size_t size, bool coherent = true)
|
||||
StreamBufferPersistentMapSync(BufferUsage type, size_t size, bool coherent = true)
|
||||
: StreamBufferSync(type, size)
|
||||
, vbo(0)
|
||||
, glMode(OpenGL::getGLBufferType(mode))
|
||||
@@ -393,7 +393,7 @@ class StreamBufferPinnedMemory final : public StreamBufferSync, public Volatile
|
||||
{
|
||||
public:
|
||||
|
||||
StreamBufferPinnedMemory(BufferType type, size_t size)
|
||||
StreamBufferPinnedMemory(BufferUsage type, size_t size)
|
||||
: StreamBufferSync(type, size)
|
||||
, vbo(0)
|
||||
, glMode(OpenGL::getGLBufferType(mode))
|
||||
@@ -491,7 +491,7 @@ private:
|
||||
|
||||
}; // StreamBufferPinnedMemory
|
||||
|
||||
love::graphics::StreamBuffer *CreateStreamBuffer(BufferType mode, size_t size)
|
||||
love::graphics::StreamBuffer *CreateStreamBuffer(BufferUsage mode, size_t size)
|
||||
{
|
||||
if (gl.isCoreProfile())
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace graphics
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
love::graphics::StreamBuffer *CreateStreamBuffer(BufferType mode, size_t size);
|
||||
love::graphics::StreamBuffer *CreateStreamBuffer(BufferUsage mode, size_t size);
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
|
||||
@@ -251,7 +251,7 @@ void Texture::createTexture()
|
||||
int slices = texType == TEXTURE_CUBE ? 6 : 1;
|
||||
Rect rect = {0, 0, 2, 2};
|
||||
for (int slice = 0; slice < slices; slice++)
|
||||
uploadByteData(PIXELFORMAT_RGBA8_UNORM, px, sizeof(px), 0, slice, rect, nullptr);
|
||||
uploadByteData(PIXELFORMAT_RGBA8_UNORM, px, sizeof(px), 0, slice, rect);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -452,18 +452,8 @@ void Texture::unloadVolatile()
|
||||
setGraphicsMemorySize(0);
|
||||
}
|
||||
|
||||
void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd)
|
||||
void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r)
|
||||
{
|
||||
love::image::ImageDataBase *oldd = slices.get(slice, level);
|
||||
|
||||
// We can only replace the internal Data (used when reloading due to setMode)
|
||||
// if the dimensions match.
|
||||
if (imgd != nullptr && oldd != nullptr && oldd->getWidth() == imgd->getWidth()
|
||||
&& oldd->getHeight() == imgd->getHeight())
|
||||
{
|
||||
slices.set(slice, level, imgd);
|
||||
}
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Texture data upload");
|
||||
|
||||
gl.bindTextureToUnit(this, 0, false);
|
||||
@@ -539,7 +529,9 @@ void Texture::setSamplerState(const SamplerState &s)
|
||||
// Base class does common validation and assigns samplerState.
|
||||
love::graphics::Texture::setSamplerState(s);
|
||||
|
||||
if (!OpenGL::hasTextureFilteringSupport(getPixelFormat()))
|
||||
auto supportedflags = OpenGL::getPixelFormatUsageFlags(getPixelFormat());
|
||||
|
||||
if ((supportedflags & PIXELFORMATUSAGEFLAGS_LINEAR) == 0)
|
||||
{
|
||||
samplerState.magFilter = samplerState.minFilter = SamplerState::FILTER_NEAREST;
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ private:
|
||||
|
||||
void createTexture();
|
||||
|
||||
void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override;
|
||||
void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) override;
|
||||
|
||||
void generateMipmapsInternal() override;
|
||||
|
||||
|
||||
@@ -337,14 +337,16 @@ const char *getConstant(BuiltinVertexAttribute attrib)
|
||||
return name;
|
||||
}
|
||||
|
||||
STRINGMAP_BEGIN(BufferType, BUFFERTYPE_MAX_ENUM, bufferTypeName)
|
||||
STRINGMAP_BEGIN(BufferUsage, BUFFERUSAGE_MAX_ENUM, bufferUsageName)
|
||||
{
|
||||
{ "vertex", BUFFERTYPE_VERTEX },
|
||||
{ "index", BUFFERTYPE_INDEX },
|
||||
{ "texel", BUFFERTYPE_TEXEL },
|
||||
{ "shaderstorage", BUFFERTYPE_SHADER_STORAGE },
|
||||
{ "vertex", BUFFERUSAGE_VERTEX },
|
||||
{ "index", BUFFERUSAGE_INDEX },
|
||||
{ "texel", BUFFERUSAGE_TEXEL },
|
||||
{ "shaderstorage", BUFFERUSAGE_SHADER_STORAGE },
|
||||
{ "copysource", BUFFERUSAGE_COPY_SOURCE },
|
||||
{ "copydest", BUFFERUSAGE_COPY_DEST },
|
||||
}
|
||||
STRINGMAP_END(BufferType, BUFFERTYPE_MAX_ENUM, bufferTypeName)
|
||||
STRINGMAP_END(BufferUsage, BUFFERUSAGE_MAX_ENUM, bufferUsageName)
|
||||
|
||||
STRINGMAP_BEGIN(IndexDataType, INDEX_MAX_ENUM, indexType)
|
||||
{
|
||||
@@ -353,13 +355,13 @@ STRINGMAP_BEGIN(IndexDataType, INDEX_MAX_ENUM, indexType)
|
||||
}
|
||||
STRINGMAP_END(IndexDataType, INDEX_MAX_ENUM, indexType)
|
||||
|
||||
STRINGMAP_BEGIN(BufferUsage, BUFFERUSAGE_MAX_ENUM, bufferUsage)
|
||||
STRINGMAP_BEGIN(BufferDataUsage, BUFFERDATAUSAGE_MAX_ENUM, bufferDataUsage)
|
||||
{
|
||||
{ "stream", BUFFERUSAGE_STREAM },
|
||||
{ "dynamic", BUFFERUSAGE_DYNAMIC },
|
||||
{ "static", BUFFERUSAGE_STATIC },
|
||||
{ "stream", BUFFERDATAUSAGE_STREAM },
|
||||
{ "dynamic", BUFFERDATAUSAGE_DYNAMIC },
|
||||
{ "static", BUFFERDATAUSAGE_STATIC },
|
||||
}
|
||||
STRINGMAP_END(BufferUsage, BUFFERUSAGE_MAX_ENUM, bufferUsage)
|
||||
STRINGMAP_END(BufferDataUsage, BUFFERDATAUSAGE_MAX_ENUM, bufferDataUsage)
|
||||
|
||||
STRINGMAP_BEGIN(PrimitiveType, PRIMITIVE_MAX_ENUM, primitiveType)
|
||||
{
|
||||
|
||||
@@ -54,14 +54,28 @@ enum BuiltinVertexAttributeFlags
|
||||
ATTRIBFLAG_COLOR = 1 << ATTRIB_COLOR,
|
||||
};
|
||||
|
||||
enum BufferType
|
||||
enum BufferUsage
|
||||
{
|
||||
BUFFERTYPE_VERTEX = 0,
|
||||
BUFFERTYPE_INDEX,
|
||||
BUFFERTYPE_UNIFORM,
|
||||
BUFFERTYPE_TEXEL,
|
||||
BUFFERTYPE_SHADER_STORAGE,
|
||||
BUFFERTYPE_MAX_ENUM
|
||||
BUFFERUSAGE_VERTEX = 0,
|
||||
BUFFERUSAGE_INDEX,
|
||||
BUFFERUSAGE_UNIFORM,
|
||||
BUFFERUSAGE_TEXEL,
|
||||
BUFFERUSAGE_SHADER_STORAGE,
|
||||
BUFFERUSAGE_COPY_SOURCE,
|
||||
BUFFERUSAGE_COPY_DEST,
|
||||
BUFFERUSAGE_MAX_ENUM
|
||||
};
|
||||
|
||||
enum BufferUsageFlags
|
||||
{
|
||||
BUFFERUSAGEFLAG_NONE = 0,
|
||||
BUFFERUSAGEFLAG_VERTEX = 1 << BUFFERUSAGE_VERTEX,
|
||||
BUFFERUSAGEFLAG_INDEX = 1 << BUFFERUSAGE_INDEX,
|
||||
BUFFERUSAGEFLAG_UNIFORM = 1 << BUFFERUSAGE_UNIFORM,
|
||||
BUFFERUSAGEFLAG_TEXEL = 1 << BUFFERUSAGE_TEXEL,
|
||||
BUFFERUSAGEFLAG_SHADER_STORAGE = 1 << BUFFERUSAGE_SHADER_STORAGE,
|
||||
BUFFERUSAGEFLAG_COPY_SOURCE = 1 << BUFFERUSAGE_COPY_SOURCE,
|
||||
BUFFERUSAGEFLAG_COPY_DEST = 1 << BUFFERUSAGE_COPY_DEST,
|
||||
};
|
||||
|
||||
enum IndexDataType
|
||||
@@ -97,12 +111,12 @@ enum CullMode
|
||||
};
|
||||
|
||||
// The expected usage pattern of buffer data.
|
||||
enum BufferUsage
|
||||
enum BufferDataUsage
|
||||
{
|
||||
BUFFERUSAGE_STREAM,
|
||||
BUFFERUSAGE_DYNAMIC,
|
||||
BUFFERUSAGE_STATIC,
|
||||
BUFFERUSAGE_MAX_ENUM
|
||||
BUFFERDATAUSAGE_STREAM,
|
||||
BUFFERDATAUSAGE_DYNAMIC,
|
||||
BUFFERDATAUSAGE_STATIC,
|
||||
BUFFERDATAUSAGE_MAX_ENUM
|
||||
};
|
||||
|
||||
// Value types used when interfacing with the GPU (vertex and shader data).
|
||||
@@ -380,9 +394,9 @@ void fillIndices(TriangleIndexMode mode, uint16 vertexStart, uint16 vertexCount,
|
||||
void fillIndices(TriangleIndexMode mode, uint32 vertexStart, uint32 vertexCount, uint32 *indices);
|
||||
|
||||
STRINGMAP_DECLARE(BuiltinVertexAttribute);
|
||||
STRINGMAP_DECLARE(BufferType);
|
||||
STRINGMAP_DECLARE(IndexDataType);
|
||||
STRINGMAP_DECLARE(BufferUsage);
|
||||
STRINGMAP_DECLARE(IndexDataType);
|
||||
STRINGMAP_DECLARE(BufferDataUsage);
|
||||
STRINGMAP_DECLARE(PrimitiveType);
|
||||
STRINGMAP_DECLARE(AttributeStep);
|
||||
STRINGMAP_DECLARE(DataFormat);
|
||||
|
||||
@@ -190,34 +190,49 @@ static int w_Buffer_setArrayData(lua_State *L)
|
||||
{
|
||||
Buffer *t = luax_checkbuffer(L, 1);
|
||||
|
||||
int startindex = (int) luaL_optnumber(L, 3, 1) - 1;
|
||||
int sourceindex = (int) luaL_optnumber(L, 3, 1) - 1;
|
||||
int destindex = (int) luaL_optnumber(L, 4, 1) - 1;
|
||||
|
||||
if (sourceindex < 0)
|
||||
return luaL_error(L, "Source start index must be at least 1.");
|
||||
|
||||
int count = -1;
|
||||
if (!lua_isnoneornil(L, 4))
|
||||
if (!lua_isnoneornil(L, 5))
|
||||
{
|
||||
count = (int) luaL_checknumber(L, 4);
|
||||
count = (int) luaL_checknumber(L, 5);
|
||||
if (count <= 0)
|
||||
return luaL_error(L, "Element count must be greater than 0.");
|
||||
}
|
||||
|
||||
size_t stride = t->getArrayStride();
|
||||
size_t offset = startindex * stride;
|
||||
size_t bufferoffset = destindex * stride;
|
||||
int arraylength = (int) t->getArrayLength();
|
||||
|
||||
if (startindex >= arraylength || startindex < 0)
|
||||
return luaL_error(L, "Invalid vertex start index (must be between 1 and %d)", arraylength);
|
||||
if (destindex >= arraylength || destindex < 0)
|
||||
return luaL_error(L, "Invalid buffer start index (must be between 1 and %d)", arraylength);
|
||||
|
||||
if (luax_istype(L, 2, Data::type))
|
||||
{
|
||||
Data *d = luax_checktype<Data>(L, 2);
|
||||
|
||||
count = count >= 0 ? count : (arraylength - startindex);
|
||||
if (startindex + count > arraylength)
|
||||
return luaL_error(L, "Too many array elements (expected at most %d, got %d)", arraylength - startindex, count);
|
||||
int dataarraylength = d->getSize() / stride;
|
||||
|
||||
size_t datasize = std::min(d->getSize(), count * stride);
|
||||
if (sourceindex >= dataarraylength)
|
||||
return luaL_error(L, "Invalid data start index (must be between 1 and %d)", dataarraylength);
|
||||
|
||||
t->fill(offset, datasize, d->getData());
|
||||
int maxcount = std::min(dataarraylength - sourceindex, arraylength - destindex);
|
||||
|
||||
if (count < 0)
|
||||
count = maxcount;
|
||||
|
||||
if (count > maxcount)
|
||||
return luaL_error(L, "Too many array elements (expected at most %d, got %d)", maxcount, count);
|
||||
|
||||
size_t dataoffset = sourceindex * stride;
|
||||
size_t datasize = std::min(d->getSize() - dataoffset, count * stride);
|
||||
const void *sourcedata = (const uint8 *) d->getData() + dataoffset;
|
||||
|
||||
t->fill(bufferoffset, datasize, sourcedata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -241,15 +256,19 @@ static int w_Buffer_setArrayData(lua_State *L)
|
||||
tablelen /= ncomponents;
|
||||
}
|
||||
|
||||
count = count >= 0 ? std::min(count, tablelen) : tablelen;
|
||||
if (startindex + count > arraylength)
|
||||
return luaL_error(L, "Too many array elements (expected at most %d, got %d)", arraylength - startindex, count);
|
||||
if (sourceindex >= tablelen)
|
||||
return luaL_error(L, "Invalid data start index (must be between 1 and %d)", tablelen);
|
||||
|
||||
char *data = (char *) t->map(Buffer::MAP_WRITE_INVALIDATE, offset, count * stride);
|
||||
count = count >= 0 ? std::min(count, tablelen - sourceindex) : tablelen - sourceindex;
|
||||
|
||||
if (destindex + count > arraylength)
|
||||
return luaL_error(L, "Too many array elements (expected at most %d, got %d)", arraylength - destindex, count);
|
||||
|
||||
char *data = (char *) t->map(Buffer::MAP_WRITE_INVALIDATE, bufferoffset, count * stride);
|
||||
|
||||
if (tableoftables)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
for (int i = sourceindex; i < count; i++)
|
||||
{
|
||||
// get arraydata[index]
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
@@ -273,7 +292,7 @@ static int w_Buffer_setArrayData(lua_State *L)
|
||||
}
|
||||
else // Flat array
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
for (int i = sourceindex; i < count; i++)
|
||||
{
|
||||
// get arraydata[arrayindex * ncomponents + componentindex]
|
||||
for (int componentindex = 1; componentindex <= ncomponents; componentindex++)
|
||||
@@ -292,7 +311,7 @@ static int w_Buffer_setArrayData(lua_State *L)
|
||||
}
|
||||
}
|
||||
|
||||
t->unmap(offset, count * stride);
|
||||
t->unmap(bufferoffset, count * stride);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -354,11 +373,11 @@ static int w_Buffer_getFormat(lua_State *L)
|
||||
static int w_Buffer_isBufferType(lua_State *L)
|
||||
{
|
||||
Buffer *t = luax_checkbuffer(L, 1);
|
||||
BufferType buffertype = BUFFERTYPE_MAX_ENUM;
|
||||
BufferUsage bufferusage = BUFFERUSAGE_MAX_ENUM;
|
||||
const char *typestr = luaL_checkstring(L, 2);
|
||||
if (!getConstant(typestr, buffertype))
|
||||
return luax_enumerror(L, "buffer type", getConstants(buffertype), typestr);
|
||||
luax_pushboolean(L, (t->getTypeFlags() & (1 << buffertype)) != 0);
|
||||
if (!getConstant(typestr, bufferusage))
|
||||
return luax_enumerror(L, "buffer type", getConstants(bufferusage), typestr);
|
||||
luax_pushboolean(L, (t->getUsageFlags() & (1 << bufferusage)) != 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1325,7 +1325,7 @@ int w_newSpriteBatch(lua_State *L)
|
||||
|
||||
Texture *texture = luax_checktexture(L, 1);
|
||||
int size = (int) luaL_optinteger(L, 2, 1000);
|
||||
BufferUsage usage = BUFFERUSAGE_DYNAMIC;
|
||||
BufferDataUsage usage = BUFFERDATAUSAGE_DYNAMIC;
|
||||
if (lua_gettop(L) > 2)
|
||||
{
|
||||
const char *usagestr = luaL_checkstring(L, 3);
|
||||
@@ -1488,7 +1488,7 @@ int w_validateShader(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BufferUsage luax_optbufferusage(lua_State *L, int idx, BufferUsage def)
|
||||
static BufferDataUsage luax_optdatausage(lua_State *L, int idx, BufferDataUsage def)
|
||||
{
|
||||
const char *usagestr = lua_isnoneornil(L, idx) ? nullptr : luaL_checkstring(L, idx);
|
||||
|
||||
@@ -1506,7 +1506,7 @@ static void luax_optbuffersettings(lua_State *L, int idx, Buffer::Settings &sett
|
||||
luaL_checktype(L, idx, LUA_TTABLE);
|
||||
|
||||
lua_getfield(L, idx, "usage");
|
||||
settings.usage = luax_optbufferusage(L, -1, settings.usage);
|
||||
settings.dataUsage = luax_optdatausage(L, -1, settings.dataUsage);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
@@ -1664,18 +1664,18 @@ static Buffer *luax_newbuffer(lua_State *L, int idx, Buffer::Settings settings,
|
||||
|
||||
int w_newBuffer(lua_State *L)
|
||||
{
|
||||
Buffer::Settings settings(0, BUFFERUSAGE_DYNAMIC);
|
||||
Buffer::Settings settings(0, BUFFERDATAUSAGE_DYNAMIC);
|
||||
|
||||
luaL_checktype(L, 3, LUA_TTABLE);
|
||||
|
||||
for (int i = 0; i < BUFFERTYPE_MAX_ENUM; i++)
|
||||
for (int i = 0; i < BUFFERUSAGE_MAX_ENUM; i++)
|
||||
{
|
||||
BufferType buffertype = (BufferType) i;
|
||||
BufferUsage bufferusage = (BufferUsage) i;
|
||||
const char *tname = nullptr;
|
||||
if (!getConstant(buffertype, tname))
|
||||
if (!getConstant(bufferusage, tname))
|
||||
continue;
|
||||
if (luax_boolflag(L, 3, tname, false))
|
||||
settings.typeFlags = (Buffer::TypeFlags)(settings.typeFlags | (1u << i));
|
||||
settings.usageFlags = (BufferUsageFlags)(settings.usageFlags | (1u << i));
|
||||
}
|
||||
|
||||
luax_optbuffersettings(L, 3, settings);
|
||||
@@ -1692,7 +1692,7 @@ int w_newBuffer(lua_State *L)
|
||||
|
||||
int w_newVertexBuffer(lua_State *L)
|
||||
{
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_VERTEX, BUFFERUSAGE_DYNAMIC);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_DYNAMIC);
|
||||
luax_optbuffersettings(L, 3, settings);
|
||||
|
||||
std::vector<Buffer::DataDeclaration> format;
|
||||
@@ -1707,7 +1707,7 @@ int w_newVertexBuffer(lua_State *L)
|
||||
|
||||
int w_newIndexBuffer(lua_State *L)
|
||||
{
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_INDEX, BUFFERUSAGE_DYNAMIC);
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_INDEX, BUFFERDATAUSAGE_DYNAMIC);
|
||||
luax_optbuffersettings(L, 3, settings);
|
||||
|
||||
size_t arraylength = 0;
|
||||
@@ -1799,7 +1799,7 @@ static Mesh *newStandardMesh(lua_State *L)
|
||||
Mesh *t = nullptr;
|
||||
|
||||
PrimitiveType drawmode = luax_optmeshdrawmode(L, 2, PRIMITIVE_TRIANGLE_FAN);
|
||||
BufferUsage usage = luax_optbufferusage(L, 3, BUFFERUSAGE_DYNAMIC);
|
||||
BufferDataUsage usage = luax_optdatausage(L, 3, BUFFERDATAUSAGE_DYNAMIC);
|
||||
|
||||
std::vector<Buffer::DataDeclaration> format = Mesh::getDefaultVertexFormat();
|
||||
|
||||
@@ -1861,7 +1861,7 @@ static Mesh *newCustomMesh(lua_State *L)
|
||||
std::vector<Buffer::DataDeclaration> vertexformat;
|
||||
|
||||
PrimitiveType drawmode = luax_optmeshdrawmode(L, 3, PRIMITIVE_TRIANGLE_FAN);
|
||||
BufferUsage usage = luax_optbufferusage(L, 4, BUFFERUSAGE_DYNAMIC);
|
||||
BufferDataUsage usage = luax_optdatausage(L, 4, BUFFERDATAUSAGE_DYNAMIC);
|
||||
|
||||
lua_rawgeti(L, 1, 1);
|
||||
if (!lua_istable(L, -1))
|
||||
@@ -3103,7 +3103,7 @@ int w_rectangle(lua_State *L)
|
||||
|
||||
if (lua_isnoneornil(L, 6))
|
||||
{
|
||||
instance()->rectangle(mode, x, y, w, h);
|
||||
luax_catchexcept(L, [&](){ instance()->rectangle(mode, x, y, w, h); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3255,6 +3255,27 @@ int w_polygon(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_copyBuffer(lua_State *L)
|
||||
{
|
||||
Buffer *source = luax_checkbuffer(L, 1);
|
||||
Buffer *dest = luax_checkbuffer(L, 2);
|
||||
|
||||
ptrdiff_t sourceoffset = luaL_optinteger(L, 3, 0);
|
||||
ptrdiff_t destoffset = luaL_optinteger(L, 4, 0);
|
||||
|
||||
ptrdiff_t size = std::min(source->getSize() - sourceoffset, dest->getSize() - destoffset);
|
||||
if (!lua_isnoneornil(L, 5))
|
||||
size = luaL_checkinteger(L, 5);
|
||||
|
||||
if (sourceoffset < 0 || destoffset < 0)
|
||||
return luaL_error(L, "copyBuffer offsets cannot be negative.");
|
||||
if (size <= 0)
|
||||
return luaL_error(L, "copyBuffer size must be greater than 0.");
|
||||
|
||||
luax_catchexcept(L, [&](){ instance()->copyBuffer(source, dest, sourceoffset, destoffset, size); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_flushBatch(lua_State *)
|
||||
{
|
||||
instance()->flushBatchedDraws();
|
||||
@@ -3451,6 +3472,8 @@ static const luaL_Reg functions[] =
|
||||
{ "print", w_print },
|
||||
{ "printf", w_printf },
|
||||
|
||||
{ "copyBuffer", w_copyBuffer },
|
||||
|
||||
{ "isCreated", w_isCreated },
|
||||
{ "isActive", w_isActive },
|
||||
{ "isGammaCorrect", w_isGammaCorrect },
|
||||
|
||||
@@ -42,102 +42,77 @@ float Joystick::clampval(float x)
|
||||
return x;
|
||||
}
|
||||
|
||||
bool Joystick::getConstant(const char *in, Joystick::Hat &out)
|
||||
STRINGMAP_CLASS_BEGIN(Joystick, Joystick::Hat, Joystick::HAT_MAX_ENUM, hat)
|
||||
{
|
||||
return hats.find(in, out);
|
||||
{ "c", Joystick::HAT_CENTERED },
|
||||
{ "u", Joystick::HAT_UP },
|
||||
{ "r", Joystick::HAT_RIGHT },
|
||||
{ "d", Joystick::HAT_DOWN },
|
||||
{ "l", Joystick::HAT_LEFT },
|
||||
{ "ru", Joystick::HAT_RIGHTUP },
|
||||
{ "rd", Joystick::HAT_RIGHTDOWN },
|
||||
{ "lu", Joystick::HAT_LEFTUP },
|
||||
{ "ld", Joystick::HAT_LEFTDOWN },
|
||||
}
|
||||
STRINGMAP_CLASS_END(Joystick, Joystick::Hat, Joystick::HAT_MAX_ENUM, hat)
|
||||
|
||||
bool Joystick::getConstant(Joystick::Hat in, const char *&out)
|
||||
STRINGMAP_CLASS_BEGIN(Joystick, Joystick::GamepadType, Joystick::GAMEPAD_TYPE_MAX_ENUM, gamepadType)
|
||||
{
|
||||
return hats.find(in, out);
|
||||
{ "unknown", Joystick::GAMEPAD_TYPE_UNKNOWN },
|
||||
{ "xbox360", Joystick::GAMEPAD_TYPE_XBOX360 },
|
||||
{ "xboxone", Joystick::GAMEPAD_TYPE_XBOXONE },
|
||||
{ "ps3", Joystick::GAMEPAD_TYPE_PS3 },
|
||||
{ "ps4", Joystick::GAMEPAD_TYPE_PS4 },
|
||||
{ "ps5", Joystick::GAMEPAD_TYPE_PS5 },
|
||||
{ "switchpro", Joystick::GAMEPAD_TYPE_NINTENDO_SWITCH_PRO },
|
||||
{ "virtual", Joystick::GAMEPAD_TYPE_VIRTUAL },
|
||||
}
|
||||
STRINGMAP_CLASS_END(Joystick, Joystick::GamepadType, Joystick::GAMEPAD_TYPE_MAX_ENUM, gamepadType)
|
||||
|
||||
bool Joystick::getConstant(const char *in, Joystick::GamepadAxis &out)
|
||||
STRINGMAP_CLASS_BEGIN(Joystick, Joystick::GamepadAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM, gpAxis)
|
||||
{
|
||||
return gpAxes.find(in, out);
|
||||
{ "leftx", Joystick::GAMEPAD_AXIS_LEFTX },
|
||||
{ "lefty", Joystick::GAMEPAD_AXIS_LEFTY },
|
||||
{ "rightx", Joystick::GAMEPAD_AXIS_RIGHTX },
|
||||
{ "righty", Joystick::GAMEPAD_AXIS_RIGHTY },
|
||||
{ "triggerleft", Joystick::GAMEPAD_AXIS_TRIGGERLEFT },
|
||||
{ "triggerright", Joystick::GAMEPAD_AXIS_TRIGGERRIGHT },
|
||||
}
|
||||
STRINGMAP_CLASS_END(Joystick, Joystick::GamepadAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM, gpAxis)
|
||||
|
||||
bool Joystick::getConstant(Joystick::GamepadAxis in, const char *&out)
|
||||
STRINGMAP_CLASS_BEGIN(Joystick, Joystick::GamepadButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM, gpButton)
|
||||
{
|
||||
return gpAxes.find(in, out);
|
||||
{ "a", Joystick::GAMEPAD_BUTTON_A },
|
||||
{ "b", Joystick::GAMEPAD_BUTTON_B },
|
||||
{ "x", Joystick::GAMEPAD_BUTTON_X },
|
||||
{ "y", Joystick::GAMEPAD_BUTTON_Y },
|
||||
{ "back", Joystick::GAMEPAD_BUTTON_BACK },
|
||||
{ "guide", Joystick::GAMEPAD_BUTTON_GUIDE },
|
||||
{ "start", Joystick::GAMEPAD_BUTTON_START },
|
||||
{ "leftstick", Joystick::GAMEPAD_BUTTON_LEFTSTICK },
|
||||
{ "rightstick", Joystick::GAMEPAD_BUTTON_RIGHTSTICK },
|
||||
{ "leftshoulder", Joystick::GAMEPAD_BUTTON_LEFTSHOULDER },
|
||||
{ "rightshoulder", Joystick::GAMEPAD_BUTTON_RIGHTSHOULDER },
|
||||
{ "dpup", Joystick::GAMEPAD_BUTTON_DPAD_UP },
|
||||
{ "dpdown", Joystick::GAMEPAD_BUTTON_DPAD_DOWN },
|
||||
{ "dpleft", Joystick::GAMEPAD_BUTTON_DPAD_LEFT },
|
||||
{ "dpright", Joystick::GAMEPAD_BUTTON_DPAD_RIGHT },
|
||||
{ "misc1", Joystick::GAMEPAD_BUTTON_MISC1 },
|
||||
{ "paddle1", Joystick::GAMEPAD_BUTTON_PADDLE1 },
|
||||
{ "paddle2", Joystick::GAMEPAD_BUTTON_PADDLE2 },
|
||||
{ "paddle3", Joystick::GAMEPAD_BUTTON_PADDLE3 },
|
||||
{ "paddle4", Joystick::GAMEPAD_BUTTON_PADDLE4 },
|
||||
{ "touchpad", Joystick::GAMEPAD_BUTTON_TOUCHPAD },
|
||||
}
|
||||
STRINGMAP_CLASS_END(Joystick, Joystick::GamepadButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM, gpButton)
|
||||
|
||||
bool Joystick::getConstant(const char *in, Joystick::GamepadButton &out)
|
||||
STRINGMAP_CLASS_BEGIN(Joystick, Joystick::InputType, Joystick::INPUT_TYPE_MAX_ENUM, inputType)
|
||||
{
|
||||
return gpButtons.find(in, out);
|
||||
{ "axis", Joystick::INPUT_TYPE_AXIS },
|
||||
{ "button", Joystick::INPUT_TYPE_BUTTON },
|
||||
{ "hat", Joystick::INPUT_TYPE_HAT },
|
||||
}
|
||||
|
||||
bool Joystick::getConstant(Joystick::GamepadButton in, const char *&out)
|
||||
{
|
||||
return gpButtons.find(in, out);
|
||||
}
|
||||
|
||||
bool Joystick::getConstant(const char *in, Joystick::InputType &out)
|
||||
{
|
||||
return inputTypes.find(in, out);
|
||||
}
|
||||
|
||||
bool Joystick::getConstant(Joystick::InputType in, const char *&out)
|
||||
{
|
||||
return inputTypes.find(in, out);
|
||||
}
|
||||
|
||||
StringMap<Joystick::Hat, Joystick::HAT_MAX_ENUM>::Entry Joystick::hatEntries[] =
|
||||
{
|
||||
{"c", Joystick::HAT_CENTERED},
|
||||
{"u", Joystick::HAT_UP},
|
||||
{"r", Joystick::HAT_RIGHT},
|
||||
{"d", Joystick::HAT_DOWN},
|
||||
{"l", Joystick::HAT_LEFT},
|
||||
{"ru", Joystick::HAT_RIGHTUP},
|
||||
{"rd", Joystick::HAT_RIGHTDOWN},
|
||||
{"lu", Joystick::HAT_LEFTUP},
|
||||
{"ld", Joystick::HAT_LEFTDOWN},
|
||||
};
|
||||
|
||||
StringMap<Joystick::Hat, Joystick::HAT_MAX_ENUM> Joystick::hats(Joystick::hatEntries, sizeof(Joystick::hatEntries));
|
||||
|
||||
StringMap<Joystick::GamepadAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM>::Entry Joystick::gpAxisEntries[] =
|
||||
{
|
||||
{"leftx", GAMEPAD_AXIS_LEFTX},
|
||||
{"lefty", GAMEPAD_AXIS_LEFTY},
|
||||
{"rightx", GAMEPAD_AXIS_RIGHTX},
|
||||
{"righty", GAMEPAD_AXIS_RIGHTY},
|
||||
{"triggerleft", GAMEPAD_AXIS_TRIGGERLEFT},
|
||||
{"triggerright", GAMEPAD_AXIS_TRIGGERRIGHT},
|
||||
};
|
||||
|
||||
StringMap<Joystick::GamepadAxis, Joystick::GAMEPAD_AXIS_MAX_ENUM> Joystick::gpAxes(Joystick::gpAxisEntries, sizeof(Joystick::gpAxisEntries));
|
||||
|
||||
StringMap<Joystick::GamepadButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM>::Entry Joystick::gpButtonEntries[] =
|
||||
{
|
||||
{"a", GAMEPAD_BUTTON_A},
|
||||
{"b", GAMEPAD_BUTTON_B},
|
||||
{"x", GAMEPAD_BUTTON_X},
|
||||
{"y", GAMEPAD_BUTTON_Y},
|
||||
{"back", GAMEPAD_BUTTON_BACK},
|
||||
{"guide", GAMEPAD_BUTTON_GUIDE},
|
||||
{"start", GAMEPAD_BUTTON_START},
|
||||
{"leftstick", GAMEPAD_BUTTON_LEFTSTICK},
|
||||
{"rightstick", GAMEPAD_BUTTON_RIGHTSTICK},
|
||||
{"leftshoulder", GAMEPAD_BUTTON_LEFTSHOULDER},
|
||||
{"rightshoulder", GAMEPAD_BUTTON_RIGHTSHOULDER},
|
||||
{"dpup", GAMEPAD_BUTTON_DPAD_UP},
|
||||
{"dpdown", GAMEPAD_BUTTON_DPAD_DOWN},
|
||||
{"dpleft", GAMEPAD_BUTTON_DPAD_LEFT},
|
||||
{"dpright", GAMEPAD_BUTTON_DPAD_RIGHT},
|
||||
};
|
||||
|
||||
StringMap<Joystick::GamepadButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM> Joystick::gpButtons(Joystick::gpButtonEntries, sizeof(Joystick::gpButtonEntries));
|
||||
|
||||
StringMap<Joystick::InputType, Joystick::INPUT_TYPE_MAX_ENUM>::Entry Joystick::inputTypeEntries[] =
|
||||
{
|
||||
{"axis", Joystick::INPUT_TYPE_AXIS},
|
||||
{"button", Joystick::INPUT_TYPE_BUTTON},
|
||||
{"hat", Joystick::INPUT_TYPE_HAT},
|
||||
};
|
||||
|
||||
StringMap<Joystick::InputType, Joystick::INPUT_TYPE_MAX_ENUM> Joystick::inputTypes(Joystick::inputTypeEntries, sizeof(Joystick::inputTypeEntries));
|
||||
STRINGMAP_CLASS_END(Joystick, Joystick::InputType, Joystick::INPUT_TYPE_MAX_ENUM, inputType)
|
||||
|
||||
} // joystick
|
||||
} // love
|
||||
|
||||
@@ -56,6 +56,19 @@ public:
|
||||
HAT_MAX_ENUM = 16
|
||||
};
|
||||
|
||||
enum GamepadType
|
||||
{
|
||||
GAMEPAD_TYPE_UNKNOWN,
|
||||
GAMEPAD_TYPE_XBOX360,
|
||||
GAMEPAD_TYPE_XBOXONE,
|
||||
GAMEPAD_TYPE_PS3,
|
||||
GAMEPAD_TYPE_PS4,
|
||||
GAMEPAD_TYPE_PS5,
|
||||
GAMEPAD_TYPE_NINTENDO_SWITCH_PRO,
|
||||
GAMEPAD_TYPE_VIRTUAL,
|
||||
GAMEPAD_TYPE_MAX_ENUM
|
||||
};
|
||||
|
||||
// Valid Gamepad axes.
|
||||
enum GamepadAxis
|
||||
{
|
||||
@@ -88,6 +101,12 @@ public:
|
||||
GAMEPAD_BUTTON_DPAD_DOWN,
|
||||
GAMEPAD_BUTTON_DPAD_LEFT,
|
||||
GAMEPAD_BUTTON_DPAD_RIGHT,
|
||||
GAMEPAD_BUTTON_MISC1, // Xbox Series X share button, PS5 mic button, Switch Pro capture button
|
||||
GAMEPAD_BUTTON_PADDLE1,
|
||||
GAMEPAD_BUTTON_PADDLE2,
|
||||
GAMEPAD_BUTTON_PADDLE3,
|
||||
GAMEPAD_BUTTON_PADDLE4,
|
||||
GAMEPAD_BUTTON_TOUCHPAD,
|
||||
GAMEPAD_BUTTON_MAX_ENUM
|
||||
};
|
||||
|
||||
@@ -146,9 +165,14 @@ public:
|
||||
|
||||
virtual bool isDown(const std::vector<int> &buttonlist) const = 0;
|
||||
|
||||
virtual void setPlayerIndex(int index) = 0;
|
||||
virtual int getPlayerIndex() const = 0;
|
||||
|
||||
virtual bool openGamepad(int deviceindex) = 0;
|
||||
virtual bool isGamepad() const = 0;
|
||||
|
||||
virtual GamepadType getGamepadType() const = 0;
|
||||
|
||||
virtual float getGamepadAxis(GamepadAxis axis) const = 0;
|
||||
virtual bool isGamepadDown(const std::vector<GamepadButton> &blist) const = 0;
|
||||
|
||||
@@ -168,34 +192,14 @@ public:
|
||||
virtual bool setVibration() = 0;
|
||||
virtual void getVibration(float &left, float &right) = 0;
|
||||
|
||||
static bool getConstant(const char *in, Hat &out);
|
||||
static bool getConstant(Hat in, const char *&out);
|
||||
|
||||
static bool getConstant(const char *in, GamepadAxis &out);
|
||||
static bool getConstant(GamepadAxis in, const char *&out);
|
||||
|
||||
static bool getConstant(const char *in, GamepadButton &out);
|
||||
static bool getConstant(GamepadButton in, const char *&out);
|
||||
|
||||
static bool getConstant(const char *in, InputType &out);
|
||||
static bool getConstant(InputType in, const char *&out);
|
||||
STRINGMAP_CLASS_DECLARE(Hat);
|
||||
STRINGMAP_CLASS_DECLARE(GamepadType);
|
||||
STRINGMAP_CLASS_DECLARE(GamepadAxis);
|
||||
STRINGMAP_CLASS_DECLARE(GamepadButton);
|
||||
STRINGMAP_CLASS_DECLARE(InputType);
|
||||
|
||||
static float clampval(float x);
|
||||
|
||||
private:
|
||||
|
||||
static StringMap<Hat, HAT_MAX_ENUM>::Entry hatEntries[];
|
||||
static StringMap<Hat, HAT_MAX_ENUM> hats;
|
||||
|
||||
static StringMap<GamepadAxis, GAMEPAD_AXIS_MAX_ENUM>::Entry gpAxisEntries[];
|
||||
static StringMap<GamepadAxis, GAMEPAD_AXIS_MAX_ENUM> gpAxes;
|
||||
|
||||
static StringMap<GamepadButton, GAMEPAD_BUTTON_MAX_ENUM>::Entry gpButtonEntries[];
|
||||
static StringMap<GamepadButton, GAMEPAD_BUTTON_MAX_ENUM> gpButtons;
|
||||
|
||||
static StringMap<InputType, INPUT_TYPE_MAX_ENUM>::Entry inputTypeEntries[];
|
||||
static StringMap<InputType, INPUT_TYPE_MAX_ENUM> inputTypes;
|
||||
|
||||
}; // Joystick
|
||||
|
||||
} // joystick
|
||||
|
||||
@@ -195,6 +195,30 @@ bool Joystick::isDown(const std::vector<int> &buttonlist) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void Joystick::setPlayerIndex(int index)
|
||||
{
|
||||
if (!isConnected())
|
||||
return;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 12)
|
||||
SDL_JoystickSetPlayerIndex(joyhandle, index);
|
||||
#else
|
||||
LOVE_UNUSED(index);
|
||||
#endif
|
||||
}
|
||||
|
||||
int Joystick::getPlayerIndex() const
|
||||
{
|
||||
if (!isConnected())
|
||||
return -1;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 12)
|
||||
return SDL_JoystickGetPlayerIndex(joyhandle);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Joystick::openGamepad(int deviceindex)
|
||||
{
|
||||
if (!SDL_IsGameController(deviceindex))
|
||||
@@ -215,6 +239,30 @@ bool Joystick::isGamepad() const
|
||||
return controller != nullptr;
|
||||
}
|
||||
|
||||
Joystick::GamepadType Joystick::getGamepadType() const
|
||||
{
|
||||
if (controller == nullptr)
|
||||
return GAMEPAD_TYPE_UNKNOWN;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 12)
|
||||
switch (SDL_GameControllerGetType(controller))
|
||||
{
|
||||
case SDL_CONTROLLER_TYPE_UNKNOWN: return GAMEPAD_TYPE_UNKNOWN;
|
||||
case SDL_CONTROLLER_TYPE_XBOX360: return GAMEPAD_TYPE_XBOX360;
|
||||
case SDL_CONTROLLER_TYPE_XBOXONE: return GAMEPAD_TYPE_XBOXONE;
|
||||
case SDL_CONTROLLER_TYPE_PS3: return GAMEPAD_TYPE_PS3;
|
||||
case SDL_CONTROLLER_TYPE_PS4: return GAMEPAD_TYPE_PS4;
|
||||
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO: return GAMEPAD_TYPE_NINTENDO_SWITCH_PRO;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 14)
|
||||
case SDL_CONTROLLER_TYPE_VIRTUAL: return GAMEPAD_TYPE_VIRTUAL;
|
||||
case SDL_CONTROLLER_TYPE_PS5: return GAMEPAD_TYPE_PS5;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return GAMEPAD_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
float Joystick::getGamepadAxis(love::joystick::Joystick::GamepadAxis axis) const
|
||||
{
|
||||
if (!isConnected() || !isGamepad())
|
||||
@@ -636,6 +684,14 @@ EnumMap<Joystick::GamepadButton, SDL_GameControllerButton, Joystick::GAMEPAD_BUT
|
||||
{Joystick::GAMEPAD_BUTTON_DPAD_DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
|
||||
{Joystick::GAMEPAD_BUTTON_DPAD_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
|
||||
{Joystick::GAMEPAD_BUTTON_DPAD_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 14)
|
||||
{Joystick::GAMEPAD_BUTTON_MISC1, SDL_CONTROLLER_BUTTON_MISC1},
|
||||
{Joystick::GAMEPAD_BUTTON_PADDLE1, SDL_CONTROLLER_BUTTON_PADDLE1},
|
||||
{Joystick::GAMEPAD_BUTTON_PADDLE2, SDL_CONTROLLER_BUTTON_PADDLE2},
|
||||
{Joystick::GAMEPAD_BUTTON_PADDLE3, SDL_CONTROLLER_BUTTON_PADDLE3},
|
||||
{Joystick::GAMEPAD_BUTTON_PADDLE4, SDL_CONTROLLER_BUTTON_PADDLE4},
|
||||
{Joystick::GAMEPAD_BUTTON_TOUCHPAD, SDL_CONTROLLER_BUTTON_TOUCHPAD},
|
||||
#endif
|
||||
};
|
||||
|
||||
EnumMap<Joystick::GamepadButton, SDL_GameControllerButton, Joystick::GAMEPAD_BUTTON_MAX_ENUM> Joystick::gpButtons(Joystick::gpButtonEntries, sizeof(Joystick::gpButtonEntries));
|
||||
|
||||
@@ -61,9 +61,14 @@ public:
|
||||
|
||||
bool isDown(const std::vector<int> &buttonlist) const override;
|
||||
|
||||
void setPlayerIndex(int index) override;
|
||||
int getPlayerIndex() const override;
|
||||
|
||||
bool openGamepad(int deviceindex) override;
|
||||
bool isGamepad() const override;
|
||||
|
||||
GamepadType getGamepadType() const override;
|
||||
|
||||
float getGamepadAxis(GamepadAxis axis) const override;
|
||||
bool isGamepadDown(const std::vector<GamepadButton> &blist) const override;
|
||||
|
||||
|
||||
@@ -171,6 +171,22 @@ int w_Joystick_isDown(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Joystick_setPlayerIndex(lua_State *L)
|
||||
{
|
||||
Joystick *j = luax_checkjoystick(L, 1);
|
||||
int index = (int) luaL_checkinteger(L, 2) - 1;
|
||||
j->setPlayerIndex(index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Joystick_getPlayerIndex(lua_State *L)
|
||||
{
|
||||
Joystick *j = luax_checkjoystick(L, 1);
|
||||
int index = j->getPlayerIndex();
|
||||
lua_pushinteger(L, index >= 0 ? index + 1 : index);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Joystick_isGamepad(lua_State *L)
|
||||
{
|
||||
Joystick *j = luax_checkjoystick(L, 1);
|
||||
@@ -178,6 +194,15 @@ int w_Joystick_isGamepad(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Joystick_getGamepadType(lua_State *L)
|
||||
{
|
||||
Joystick *j = luax_checkjoystick(L, 1);
|
||||
const char *str = "unknown";
|
||||
Joystick::getConstant(j->getGamepadType(), str);
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Joystick_getGamepadAxis(lua_State *L)
|
||||
{
|
||||
Joystick *j = luax_checkjoystick(L, 1);
|
||||
@@ -357,8 +382,11 @@ static const luaL_Reg w_Joystick_functions[] =
|
||||
{ "getAxes", w_Joystick_getAxes },
|
||||
{ "getHat", w_Joystick_getHat },
|
||||
{ "isDown", w_Joystick_isDown },
|
||||
{ "setPlayerIndex", w_Joystick_setPlayerIndex },
|
||||
{ "getPlayerIndex", w_Joystick_getPlayerIndex },
|
||||
|
||||
{ "isGamepad", w_Joystick_isGamepad },
|
||||
{ "getGamepadType", w_Joystick_getGamepadType },
|
||||
{ "getGamepadAxis", w_Joystick_getGamepadAxis },
|
||||
{ "isGamepadDown", w_Joystick_isGamepadDown },
|
||||
{ "getGamepadMapping", w_Joystick_getGamepadMapping },
|
||||
|
||||
Reference in New Issue
Block a user