Merge branch '12.0-development' into metal

This commit is contained in:
Alex Szpakowski
2021-03-26 21:42:08 -03:00
51 changed files with 1415 additions and 828 deletions
+5
View File
@@ -61,6 +61,11 @@ struct Range
return first <= other.first && last >= other.last;
}
bool intersects(const Range &other)
{
return !(first > other.last || last < other.first);
}
void encapsulate(size_t index)
{
first = std::min(first, index);
+401 -3
View File
@@ -22,13 +22,20 @@
#ifdef LOVE_ANDROID
#include "SDL.h"
#include "jni.h"
#include <cerrno>
#include <unordered_map>
#include <SDL.h>
#include <jni.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "physfs.h"
namespace love
{
@@ -326,6 +333,397 @@ void showRecordingPermissionMissingDialog()
env->DeleteLocalRef(activity);
}
/*
* Helper functions to aid new fusing method
*/
static AAssetManager *getAssetManager()
{
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jobject self = (jobject) SDL_AndroidGetActivity();
jclass activity = env->GetObjectClass(self);
jmethodID method = env->GetMethodID(activity, "getAssetManager", "()Landroid/content/res/AssetManager;");
jobject assetManager = env->CallObjectMethod(self, method);
AAssetManager *assetManagerObject = AAssetManager_fromJava(env, assetManager);
env->DeleteLocalRef(assetManager);
env->DeleteLocalRef(activity);
env->DeleteLocalRef(self);
return assetManagerObject;
}
namespace aasset
{
namespace io
{
struct AssetInfo
{
AAssetManager *assetManager;
AAsset *asset;
char *filename;
size_t size;
};
static std::unordered_map<std::string, PHYSFS_FileType> fileTree;
// Workaround AAsset can't detect whetever something is a directory or doesn't exist
static void buildFileLookup(
AAssetManager *assetManager,
std::unordered_map<std::string, PHYSFS_FileType> &out,
const std::string &path = ""
)
{
if (!path.empty())
{
AAsset *test = AAssetManager_open(assetManager, path.c_str(), AASSET_MODE_STREAMING);
if (test)
{
AAsset_close(test);
out[path] = PHYSFS_FILETYPE_REGULAR;
return;
}
out[path] = PHYSFS_FILETYPE_DIRECTORY;
}
AAssetDir *dir = AAssetManager_openDir(assetManager, path.c_str());
const char *file;
while ((file = AAssetDir_getNextFileName(dir)) != nullptr)
buildFileLookup(assetManager, out, file);
AAssetDir_close(dir);
}
PHYSFS_sint64 read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
{
AAsset *asset = ((AssetInfo *) io->opaque)->asset;
int readed = AAsset_read(asset, buf, (size_t) len);
PHYSFS_setErrorCode(readed < 0 ? PHYSFS_ERR_OS_ERROR : PHYSFS_ERR_OK);
return (PHYSFS_sint64) readed;
}
PHYSFS_sint64 write(PHYSFS_Io *io, const void *buf, PHYSFS_uint64 len)
{
LOVE_UNUSED(io);
LOVE_UNUSED(buf);
LOVE_UNUSED(len);
PHYSFS_setErrorCode(PHYSFS_ERR_READ_ONLY);
return -1;
}
int seek(PHYSFS_Io *io, PHYSFS_uint64 offset)
{
AAsset *asset = ((AssetInfo *) io->opaque)->asset;
int success = AAsset_seek64(asset, (off64_t) offset, SEEK_SET) != -1;
PHYSFS_setErrorCode(success ? PHYSFS_ERR_OK : PHYSFS_ERR_OS_ERROR);
return success;
}
PHYSFS_sint64 tell(PHYSFS_Io *io)
{
AAsset *asset = ((AssetInfo *) io->opaque)->asset;
off64_t len = AAsset_getLength64(asset);
off64_t remain = AAsset_getRemainingLength64(asset);
return len - remain;
}
PHYSFS_sint64 length(PHYSFS_Io *io)
{
AAsset *asset = ((AssetInfo *) io->opaque)->asset;
return AAsset_getLength64(asset);
}
// Forward declaration
PHYSFS_Io *fromAAsset(AAssetManager *assetManager, const char *filename, AAsset *asset);
PHYSFS_Io *duplicate(PHYSFS_Io *io)
{
AssetInfo *assetInfo = (AssetInfo *) io->opaque;
AAsset *asset = AAssetManager_open(assetInfo->assetManager, assetInfo->filename, AASSET_MODE_RANDOM);
if (asset == nullptr)
{
PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR);
return nullptr;
}
AAsset_seek64(asset, tell(io), SEEK_SET);
return fromAAsset(assetInfo->assetManager, assetInfo->filename, asset);
}
void destroy(PHYSFS_Io *io)
{
AssetInfo *assetInfo = (AssetInfo *) io->opaque;
AAsset_close(assetInfo->asset);
delete[] assetInfo->filename;
delete assetInfo;
delete io;
}
PHYSFS_Io *fromAAsset(AAssetManager *assetManager, const char *filename, AAsset *asset)
{
// Create AssetInfo
AssetInfo *assetInfo = new (std::nothrow) AssetInfo();
assetInfo->assetManager = assetManager;
assetInfo->asset = asset;
assetInfo->size = strlen(filename) + 1;
assetInfo->filename = new (std::nothrow) char[assetInfo->size];
memcpy(assetInfo->filename, filename, assetInfo->size);
// Create PHYSFS_Io
PHYSFS_Io *io = new (std::nothrow) PHYSFS_Io();
io->version = 0;
io->opaque = assetInfo;
io->read = read;
io->write = write;
io->seek = seek;
io->tell = tell;
io->length = length;
io->duplicate = duplicate;
io->flush = nullptr;
io->destroy = destroy;
return io;
}
}
void *openArchive(PHYSFS_Io *io, const char *name, int forWrite, int *claimed)
{
if (io->opaque == nullptr || memcmp(io->opaque, "ASET", 4) != 0)
return nullptr;
// It's our archive
*claimed = 1;
AAssetManager *assetManager = getAssetManager();
if (io::fileTree.empty())
io::buildFileLookup(assetManager, io::fileTree);
return assetManager;
}
PHYSFS_EnumerateCallbackResult enumerate(
void *opaque,
const char *dirname,
PHYSFS_EnumerateCallback cb,
const char *origdir,
void *callbackdata
)
{
const char *path = dirname;
if (path == nullptr || (path[0] == '/' && path[1] == 0))
path = "";
AAssetManager *assetManager = (AAssetManager *) opaque;
AAssetDir *dir = AAssetManager_openDir(assetManager, path);
if (dir == nullptr)
{
PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND);
return PHYSFS_ENUM_ERROR;
}
PHYSFS_EnumerateCallbackResult ret = PHYSFS_ENUM_OK;
while (ret == PHYSFS_ENUM_OK)
{
const char *name = AAssetDir_getNextFileName(dir);
// No more files?
if (name == nullptr)
break;
ret = cb(callbackdata, origdir, name);
}
AAssetDir_close(dir);
return ret;
}
PHYSFS_Io *openRead(void *opaque, const char *name)
{
AAssetManager *assetManager = (AAssetManager *) opaque;
AAsset *file = AAssetManager_open(assetManager, name, AASSET_MODE_UNKNOWN);
if (file == nullptr)
{
PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND);
return nullptr;
}
PHYSFS_setErrorCode(PHYSFS_ERR_OK);
return io::fromAAsset(assetManager, name, file);
}
PHYSFS_Io *openWriteAppend(void *opaque, const char *name)
{
LOVE_UNUSED(opaque);
LOVE_UNUSED(name);
// AAsset doesn't support modification
PHYSFS_setErrorCode(PHYSFS_ERR_READ_ONLY);
return nullptr;
}
int removeMkdir(void *opaque, const char *name)
{
LOVE_UNUSED(opaque);
LOVE_UNUSED(name);
// AAsset doesn't support modification
PHYSFS_setErrorCode(PHYSFS_ERR_READ_ONLY);
return 0;
}
int stat(void *opaque, const char *name, PHYSFS_Stat *out)
{
LOVE_UNUSED(opaque);
auto result = io::fileTree.find(name);
if (result != io::fileTree.end())
{
out->filetype = result->second;
out->modtime = -1;
out->createtime = -1;
out->accesstime = -1;
out->readonly = 1;
PHYSFS_setErrorCode(PHYSFS_ERR_OK);
return 1;
}
else
{
PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND);
return 0;
}
}
void closeArchive(void *opaque)
{
// Do nothing
LOVE_UNUSED(opaque);
PHYSFS_setErrorCode(PHYSFS_ERR_OK);
}
static PHYSFS_Archiver g_AAssetArchiver = {
0,
{
"AASSET",
"Android AAsset Wrapper",
"LOVE Development Team",
"https://developer.android.com/ndk/reference/group/asset",
0
},
openArchive,
enumerate,
openRead,
openWriteAppend,
openWriteAppend,
removeMkdir,
removeMkdir,
stat,
closeArchive
};
static PHYSFS_sint64 dummyReturn0(PHYSFS_Io *io)
{
LOVE_UNUSED(io);
PHYSFS_setErrorCode(PHYSFS_ERR_OK);
return 0;
}
static PHYSFS_Io *getDummyIO(PHYSFS_Io *io);
static char dummyOpaque[] = "ASET";
static PHYSFS_Io dummyIo = {
0,
dummyOpaque,
nullptr,
nullptr,
[](PHYSFS_Io *io, PHYSFS_uint64 offset) -> int
{
PHYSFS_setErrorCode(offset == 0 ? PHYSFS_ERR_OK : PHYSFS_ERR_PAST_EOF);
return offset == 0;
},
dummyReturn0,
dummyReturn0,
getDummyIO,
nullptr,
[](PHYSFS_Io *io) { LOVE_UNUSED(io); }
};
static PHYSFS_Io *getDummyIO(PHYSFS_Io *io)
{
return &dummyIo;
}
}
static bool isVirtualArchiveInitialized = false;
bool initializeVirtualArchive()
{
if (isVirtualArchiveInitialized)
return true;
if (!PHYSFS_registerArchiver(&aasset::g_AAssetArchiver))
return false;
if (!PHYSFS_mountIo(&aasset::dummyIo, "ASET.AASSET", nullptr, 0))
{
PHYSFS_deregisterArchiver(aasset::g_AAssetArchiver.info.extension);
return false;
}
isVirtualArchiveInitialized = true;
return true;
}
void deinitializeVirtualArchive()
{
if (isVirtualArchiveInitialized)
{
PHYSFS_deregisterArchiver(aasset::g_AAssetArchiver.info.extension);
isVirtualArchiveInitialized = false;
}
}
bool checkFusedGame(void **physfsIO_Out)
{
// TODO: Reorder the loading in 12.0
PHYSFS_Io *&io = *(PHYSFS_Io **) physfsIO_Out;
AAssetManager *assetManager = getAssetManager();
// Prefer game.love inside assets/ folder
AAsset *asset = AAssetManager_open(assetManager, "game.love", AASSET_MODE_RANDOM);
if (asset)
{
io = aasset::io::fromAAsset(assetManager, "game.love", asset);
return true;
}
// If there's no game.love inside assets/ try main.lua
asset = AAssetManager_open(assetManager, "main.lua", AASSET_MODE_STREAMING);
if (asset)
{
AAsset_close(asset);
io = nullptr;
return true;
}
// Not found
return false;
}
} // android
} // love
+21
View File
@@ -80,6 +80,27 @@ void requestRecordingPermission();
void showRecordingPermissionMissingDialog();
/**
* Initialize Android AAsset virtual archive.
* @return true if successful.
*/
bool initializeVirtualArchive();
/**
* Deinitialize Android AAsset virtual archive.
* @return true if successful.
*/
void deinitializeVirtualArchive();
/**
* Retrieve the fused game inside the APK
* @param physfsIO_Out Pointer to PHYSFS_Io* struct
* @return true if there's game inside the APK. If physfsIO_Out is not null, then it contains
* the game.love which needs to be mounted to root. false if it's not fused, in which case
* physfsIO_Out is undefined.
*/
bool checkFusedGame(void **physfsIO_Out);
} // android
} // love
+52 -12
View File
@@ -93,11 +93,42 @@ static int w__eq(lua_State *L)
return 1;
}
typedef uint64 ObjectKey;
static bool luax_isfulllightuserdatasupported(lua_State *L)
{
// LuaJIT prior to commit e9af1abec542e6f9851ff2368e7f196b6382a44c doesn't
// support lightuserdata > 48 bits. This is not a problem with Android,
// Windows, macOS, and iOS as they'll use updated LuaJIT or won't use
// pointers > 48 bits, but this is not the case for Linux. So check for
// this capability first!
static bool checked = false;
static bool supported = false;
if (!checked)
{
lua_pushcclosure(L, [](lua_State *L) -> int
{
// Try to push pointer with all bits set.
lua_pushlightuserdata(L, (void *) (~((size_t) 0)));
return 1;
}, 0);
supported = lua_pcall(L, 0, 1, 0) == 0;
checked = true;
lua_pop(L, 1);
}
return supported;
}
// For use with the love object pointer -> Proxy pointer registry.
// Using the pointer directly via lightuserdata would be ideal, but LuaJIT
// cannot use lightuserdata with more than 47 bits whereas some newer arm64
// architectures allow pointers which use more than that.
static lua_Number luax_computeloveobjectkey(lua_State *L, love::Object *object)
// (before a commit to 2.1 in 2020) cannot use lightuserdata with more than 47
// bits whereas some newer arm64 architectures allow pointers which use more
// than that.
static ObjectKey luax_computeloveobjectkey(lua_State *L, love::Object *object)
{
// love objects should be allocated on the heap, and thus are subject
// to the alignment rules of operator new / malloc. Lua numbers (doubles)
@@ -118,11 +149,20 @@ static lua_Number luax_computeloveobjectkey(lua_State *L, love::Object *object)
key >>= shift;
// Make sure our key isn't larger than 2^53.
if (key > 0x20000000000000ULL)
luaL_error(L, "Cannot push love object to Lua: pointer value %p is too large", object);
return (ObjectKey) key;
}
return (lua_Number) key;
static void luax_pushloveobjectkey(lua_State *L, ObjectKey key)
{
// If full 64-bit lightuserdata is supported, always use that. Otherwise,
// if the key is smaller than 2^53 (which is integer precision for double
// datatype), then push number. Otherwise, throw error.
if (luax_isfulllightuserdatasupported(L))
lua_pushlightuserdata(L, (void *) key);
else if (key > 0x20000000000000ULL) // 2^53
luaL_error(L, "Cannot push love object to Lua: pointer value %p is too large", key);
else
lua_pushnumber(L, (lua_Number) key);
}
static int w__release(lua_State *L)
@@ -141,8 +181,8 @@ static int w__release(lua_State *L)
if (lua_istable(L, -1))
{
// loveobjects[object] = nil
lua_Number objectkey = luax_computeloveobjectkey(L, object);
lua_pushnumber(L, objectkey);
ObjectKey objectkey = luax_computeloveobjectkey(L, object);
luax_pushloveobjectkey(L, objectkey);
lua_pushnil(L);
lua_settable(L, -3);
}
@@ -622,10 +662,10 @@ void luax_pushtype(lua_State *L, love::Type &type, love::Object *object)
return luax_rawnewtype(L, type, object);
}
lua_Number objectkey = luax_computeloveobjectkey(L, object);
ObjectKey objectkey = luax_computeloveobjectkey(L, object);
// Get the value of loveobjects[object] on the stack.
lua_pushnumber(L, objectkey);
luax_pushloveobjectkey(L, objectkey);
lua_gettable(L, -2);
// If the Proxy userdata isn't in the instantiated types table yet, add it.
@@ -635,7 +675,7 @@ void luax_pushtype(lua_State *L, love::Type &type, love::Object *object)
luax_rawnewtype(L, type, object);
lua_pushnumber(L, objectkey);
luax_pushloveobjectkey(L, objectkey);
lua_pushvalue(L, -2);
// loveobjects[object] = Proxy.
+49 -19
View File
@@ -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
+10 -6
View File
@@ -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;
+15 -20
View File
@@ -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;
+88 -163
View File
@@ -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
+15 -51
View File
@@ -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
+14 -14
View File
@@ -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;
+2 -2
View File
@@ -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();
+3 -3
View File
@@ -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();
+49 -25
View File
@@ -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));
+3 -3
View File
@@ -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);
+8 -8
View File
@@ -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;
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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)
+3 -3
View File
@@ -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
+7 -3
View File
@@ -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);
+3 -3
View File
@@ -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();
+21 -1
View File
@@ -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;
+1
View File
@@ -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; }
+13 -1
View File
@@ -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
+2 -2
View File
@@ -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;
+11 -10
View File
@@ -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;
+1 -1
View File
@@ -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
+4 -4
View File
@@ -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
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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
+34 -20
View File
@@ -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
+2 -1
View File
@@ -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.
+44 -27
View File
@@ -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);
+3 -3
View File
@@ -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];
+162 -152
View File
@@ -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)
+8 -15
View File
@@ -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];
+12 -24
View File
@@ -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;
-7
View File
@@ -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
+7 -7
View File
@@ -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())
{
+1 -1
View File
@@ -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
+5 -13
View File
@@ -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;
+1 -1
View File
@@ -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;
+13 -11
View File
@@ -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)
{
+28 -14
View File
@@ -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);
+41 -22
View File
@@ -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;
}
+36 -13
View File
@@ -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 },
+57 -82
View File
@@ -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
+29 -25
View File
@@ -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
+56
View File
@@ -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));
+5
View File
@@ -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;
+28
View File
@@ -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 },