From 9cbddc2f5ee507ab8e3e645f5734926d10916afa Mon Sep 17 00:00:00 2001 From: fysx Date: Thu, 13 Aug 2015 17:21:53 +0200 Subject: [PATCH] Updated to latest love-android code (b615972822cb) --- jni/love/src/common/Matrix.cpp | 24 +++ jni/love/src/common/Matrix.h | 21 +++ jni/love/src/common/android.cpp | 154 ++++++++---------- jni/love/src/common/int.h | 6 +- jni/love/src/love.cpp | 20 +-- .../modules/filesystem/physfs/Filesystem.cpp | 23 +-- jni/love/src/modules/graphics/Graphics.cpp | 34 +++- jni/love/src/modules/graphics/Graphics.h | 37 ++++- .../src/modules/graphics/opengl/Canvas.cpp | 15 +- jni/love/src/modules/graphics/opengl/Canvas.h | 2 +- .../src/modules/graphics/opengl/GLBuffer.cpp | 80 ++++++--- .../src/modules/graphics/opengl/GLBuffer.h | 31 +++- .../src/modules/graphics/opengl/Graphics.cpp | 138 +++++----------- .../src/modules/graphics/opengl/Graphics.h | 56 +++---- .../src/modules/graphics/opengl/Image.cpp | 87 +++++++--- jni/love/src/modules/graphics/opengl/Image.h | 8 +- jni/love/src/modules/graphics/opengl/Mesh.cpp | 37 +---- jni/love/src/modules/graphics/opengl/Mesh.h | 5 - .../graphics/opengl/ParticleSystem.cpp | 89 +++++----- .../modules/graphics/opengl/ParticleSystem.h | 13 +- .../modules/graphics/opengl/SpriteBatch.cpp | 26 +-- .../src/modules/graphics/opengl/SpriteBatch.h | 6 +- jni/love/src/modules/graphics/opengl/Text.cpp | 12 +- jni/love/src/modules/graphics/opengl/Text.h | 2 +- .../modules/graphics/opengl/wrap_Canvas.cpp | 5 +- .../modules/graphics/opengl/wrap_Graphics.cpp | 130 +++++++-------- .../modules/graphics/opengl/wrap_Graphics.h | 1 + .../modules/graphics/opengl/wrap_Graphics.lua | 69 +++++++- .../modules/graphics/opengl/wrap_Image.cpp | 4 +- .../src/modules/graphics/opengl/wrap_Mesh.cpp | 40 +++-- .../src/modules/graphics/opengl/wrap_Mesh.h | 3 + .../graphics/opengl/wrap_ParticleSystem.cpp | 50 +++--- .../modules/graphics/opengl/wrap_Shader.cpp | 36 +++- .../src/modules/graphics/opengl/wrap_Shader.h | 2 + .../graphics/opengl/wrap_SpriteBatch.cpp | 26 +-- .../src/modules/image/magpie/KTXHandler.cpp | 6 +- .../src/modules/image/magpie/PKMHandler.cpp | 2 +- .../src/modules/image/magpie/PVRHandler.cpp | 22 +-- jni/love/src/modules/love/love.cpp | 16 ++ jni/love/src/modules/math/Compressor.cpp | 4 +- jni/love/src/modules/math/MathModule.cpp | 14 +- jni/love/src/modules/window/Window.cpp | 1 - jni/love/src/modules/window/Window.h | 2 - jni/love/src/modules/window/sdl/Window.cpp | 46 ++++-- jni/love/src/modules/window/sdl/Window.h | 4 +- jni/love/src/modules/window/wrap_Window.cpp | 4 - jni/love/src/scripts/boot.lua | 21 +-- jni/love/src/scripts/boot.lua.h | 53 +++--- jni/love/src/scripts/nogame.lua | 1 + jni/love/src/scripts/nogame.lua.h | 2 + 50 files changed, 827 insertions(+), 663 deletions(-) diff --git a/jni/love/src/common/Matrix.cpp b/jni/love/src/common/Matrix.cpp index 61b2b44e..103f293e 100644 --- a/jni/love/src/common/Matrix.cpp +++ b/jni/love/src/common/Matrix.cpp @@ -221,6 +221,11 @@ Matrix3::Matrix3(const Matrix4 &mat4) e[8] = mat4elems[10]; } +Matrix3::Matrix3(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) +{ + setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); +} + Matrix3::~Matrix3() { } @@ -288,4 +293,23 @@ Matrix3 Matrix3::transposedInverse() const return m; } +void Matrix3::setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) +{ + float c = cosf(angle), s = sinf(angle); + // matrix multiplication carried out on paper: + // |1 x| |c -s | |sx | | 1 ky | |1 -ox| + // | 1 y| |s c | | sy | |kx 1 | | 1 -oy| + // | 1| | 1| | 1| | 1| | 1 | + // move rotate scale skew origin + e[0] = c * sx - ky * s * sy; // = a + e[1] = s * sx + ky * c * sy; // = b + e[3] = kx * c * sx - s * sy; // = c + e[4] = kx * s * sx + c * sy; // = d + e[6] = x - ox * e[0] - oy * e[3]; + e[7] = y - ox * e[1] - oy * e[4]; + + e[2] = e[5] = 0.0f; + e[8] = 1.0f; +} + } // love diff --git a/jni/love/src/common/Matrix.h b/jni/love/src/common/Matrix.h index f6f24fbe..a174605e 100644 --- a/jni/love/src/common/Matrix.h +++ b/jni/love/src/common/Matrix.h @@ -185,6 +185,11 @@ public: **/ Matrix3(const Matrix4 &mat4); + /** + * Creates a new matrix set to a transformation. + **/ + Matrix3(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); + ~Matrix3(); /** @@ -205,6 +210,22 @@ public: **/ Matrix3 transposedInverse() const; + /** + * Creates a transformation with a certain position, orientation, scale + * and offset. + * + * @param x The translation along the x-axis. + * @param y The translation along the y-axis. + * @param angle The rotation (rad) around the center with offset (ox,oy). + * @param sx Scale along x-axis. + * @param sy Scale along y-axis. + * @param ox The offset for rotation along the x-axis. + * @param oy The offset for rotation along the y-axis. + * @param kx Shear along x-axis + * @param ky Shear along y-axis + **/ + void setTransformation(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); + /** * Transforms an array of vertices by this matrix. **/ diff --git a/jni/love/src/common/android.cpp b/jni/love/src/common/android.cpp index 1fb2d79d..3261ad9b 100644 --- a/jni/love/src/common/android.cpp +++ b/jni/love/src/common/android.cpp @@ -35,65 +35,67 @@ namespace love namespace android { -void setImmersive (bool immersive_active) { +void setImmersive(bool immersive_active) +{ JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); jobject activity = (jobject) SDL_AndroidGetActivity(); - jclass clazz (env->GetObjectClass(activity)); - jmethodID method_id = env->GetMethodID (clazz, "setImmersiveMode", "(Z)V"); + jclass clazz(env->GetObjectClass(activity)); + jmethodID method_id = env->GetMethodID(clazz, "setImmersiveMode", "(Z)V"); - env->CallVoidMethod (activity, method_id, immersive_active); + env->CallVoidMethod(activity, method_id, immersive_active); - env->DeleteLocalRef (activity); - env->DeleteLocalRef (clazz); + env->DeleteLocalRef(activity); + env->DeleteLocalRef(clazz); } -bool getImmersive () { +bool getImmersive() +{ JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); jobject activity = (jobject) SDL_AndroidGetActivity(); - jclass clazz (env->GetObjectClass(activity)); - jmethodID method_id = env->GetMethodID (clazz, "getImmersiveMode", "()Z"); + jclass clazz(env->GetObjectClass(activity)); + jmethodID method_id = env->GetMethodID(clazz, "getImmersiveMode", "()Z"); - jboolean immersive_active = env->CallBooleanMethod (activity, method_id); + jboolean immersive_active = env->CallBooleanMethod(activity, method_id); - env->DeleteLocalRef (activity); - env->DeleteLocalRef (clazz); + env->DeleteLocalRef(activity); + env->DeleteLocalRef(clazz); - if (immersive_active) - return true; - return false; + return immersive_active; } double getScreenScale() { - static double result = -1.; + static double result = -1.; - if (result == -1.) { - JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); - jclass activity = env->FindClass("org/love2d/android/GameActivity"); + if (result == -1.) + { + JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); + jclass activity = env->FindClass("org/love2d/android/GameActivity"); - jmethodID getMetrics = env->GetStaticMethodID(activity, "getMetrics", "()Landroid/util/DisplayMetrics;"); - jobject metrics = env->CallStaticObjectMethod(activity, getMetrics); - jclass metricsClass = env->GetObjectClass(metrics); + jmethodID getMetrics = env->GetStaticMethodID(activity, "getMetrics", "()Landroid/util/DisplayMetrics;"); + jobject metrics = env->CallStaticObjectMethod(activity, getMetrics); + jclass metricsClass = env->GetObjectClass(metrics); - result = env->GetFloatField(metrics, env->GetFieldID(metricsClass, "density", "F")); + result = env->GetFloatField(metrics, env->GetFieldID(metricsClass, "density", "F")); - env->DeleteLocalRef (metricsClass); - env->DeleteLocalRef (metrics); - env->DeleteLocalRef (activity); - } + env->DeleteLocalRef(metricsClass); + env->DeleteLocalRef(metrics); + env->DeleteLocalRef(activity); + } - return result; + return result; } const char* getSelectedGameFile() { static const char *path = NULL; - if (path) { + if (path) + { delete path; path = NULL; } @@ -110,8 +112,8 @@ const char* getSelectedGameFile() env->ReleaseStringUTFChars(gamePath, utf); } - env->DeleteLocalRef (gamePath); - env->DeleteLocalRef (activity); + env->DeleteLocalRef(gamePath); + env->DeleteLocalRef(activity); return path; } @@ -122,16 +124,16 @@ bool openURL(const std::string &url) jclass activity = env->FindClass("org/love2d/android/GameActivity"); jmethodID openURL= env->GetStaticMethodID(activity, "openURL", "(Ljava/lang/String;)V"); - jstring url_jstring = (jstring) env->NewStringUTF (url.c_str()); + jstring url_jstring = (jstring) env->NewStringUTF(url.c_str()); - env->CallStaticVoidMethod (activity, openURL, url_jstring); + env->CallStaticVoidMethod(activity, openURL, url_jstring); - env->DeleteLocalRef (url_jstring); - env->DeleteLocalRef (activity); + env->DeleteLocalRef(url_jstring); + env->DeleteLocalRef(activity); return true; } -void vibrate (double seconds) +void vibrate(double seconds) { JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); jclass activity = env->FindClass("org/love2d/android/GameActivity"); @@ -139,100 +141,86 @@ void vibrate (double seconds) jmethodID vibrate_method = env->GetStaticMethodID(activity, "vibrate", "(D)V"); env->CallStaticVoidMethod(activity, vibrate_method, seconds); - env->DeleteLocalRef (activity); + env->DeleteLocalRef(activity); } /* * Helper functions for the filesystem module */ -void freeGameArchiveMemory (void *ptr) { - SDL_Log ("Freeing memory for in-memory LÖVE archive 0x%x", (int) ptr); +void freeGameArchiveMemory(void *ptr) +{ char *game_love_data = static_cast(ptr); delete[] game_love_data; } -bool loadGameArchiveToMemory (const char* filename, char **ptr, size_t *size) { - SDL_Log ("Trying to mount %s", filename); +bool loadGameArchiveToMemory(const char* filename, char **ptr, size_t *size) +{ SDL_RWops *asset_game_file = SDL_RWFromFile(filename, "rb"); if (!asset_game_file) { - SDL_Log ("Could not find %s", filename); + SDL_Log("Could not find %s", filename); return false; } Sint64 file_size = asset_game_file->size(asset_game_file); - if (file_size <= 0) { - SDL_Log ("Could not load game from %s. File has invalid file size: %d.", filename, (int) file_size); + SDL_Log("Could not load game from %s. File has invalid file size: %d.", filename, (int) file_size); return false; } - (*ptr) = new char[file_size]; - SDL_Log ("Allocated memory for in-memory LÖVE archive at: 0x%x", (int) (*ptr)); - - if (!(*ptr)) { - SDL_Log ("Could not allocate memory for in-memory game archive"); + *ptr = new char[file_size]; + if (!*ptr) { + SDL_Log("Could not allocate memory for in-memory game archive"); return false; } - size_t bytes_copied = asset_game_file->read(asset_game_file, (void*) (*ptr), sizeof(char), (size_t) file_size); - + size_t bytes_copied = asset_game_file->read(asset_game_file, (void*) *ptr, sizeof(char), (size_t) file_size); if (bytes_copied != file_size) { - SDL_Log ("Only copied %d of %d bytes into in-memory game archive!", (unsigned int) bytes_copied, (unsigned int) file_size); - delete[] (*ptr); + SDL_Log("Incomplete copy of in-memory game archive!"); + delete[] *ptr; return false; } - SDL_Log ("Copied %d of %d bytes into in-memory game archive", (unsigned int) bytes_copied, (unsigned int) file_size); - *size = (size_t) file_size; - return true; } -bool directoryExists(const char* path) { - SDL_Log ("Checking directory exists for %s", path); +bool directoryExists(const char *path) +{ struct stat s; int err = stat(path, &s); - if (err == -1) { - if (errno == ENOENT) - return false; - else { - SDL_Log ("Error checking for directory %s errno = %d: %s", path, errno, strerror (errno)); - return false; - } - } else if(S_ISDIR(s.st_mode)) { - SDL_Log ("Directory %s exists!", path); - return true; + if (err == -1) + { + if (errno != ENOENT) + SDL_Log ("Error checking for directory %s errno = %d: %s", path, errno, strerror(errno)); + return false; } - return false; + + return S_ISDIR(s.st_mode); } -bool mkdir (const char* path) { +bool mkdir(const char* path) +{ int err = ::mkdir (path, 0770); - if (err == -1) { + if (err == -1) + { SDL_Log ("Error: Could not create directory %s", path); - return false; + return false; } return true; } -bool createStorageDirectories () { +bool createStorageDirectories() +{ std::string internal_storage_path = SDL_AndroidGetInternalStoragePath(); std::string save_directory = internal_storage_path + "/save"; - if (!directoryExists (save_directory.c_str())) { - if (!mkdir(save_directory.c_str())) - return false; - } + if (!directoryExists(save_directory.c_str()) && !mkdir(save_directory.c_str())) + return false; std::string game_directory = internal_storage_path + "/game"; - if (!directoryExists (game_directory.c_str())) { - if (!mkdir(game_directory.c_str())) - return false; - } - - SDL_Log ("Creating storage directories successful!"); + if (!directoryExists (game_directory.c_str()) && !mkdir(game_directory.c_str())) + return false; return true; } diff --git a/jni/love/src/common/int.h b/jni/love/src/common/int.h index 72f60f8b..73d8e144 100644 --- a/jni/love/src/common/int.h +++ b/jni/love/src/common/int.h @@ -54,12 +54,12 @@ typedef uint32_t uint32; typedef int64_t int64; typedef uint64_t uint64; -static inline uint16 swap16(uint16 x) +static inline uint16 swapuint16(uint16 x) { return (x >> 8) | (x << 8); } -static inline uint32 swap32(uint32 x) +static inline uint32 swapuint32(uint32 x) { return ((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | @@ -67,7 +67,7 @@ static inline uint32 swap32(uint32 x) ((x & 0xFF000000) >> 24); } -static inline uint64 swap64(uint64 x) +static inline uint64 swapuint64(uint64 x) { return ((x << 56) & 0xFF00000000000000ULL) | ((x << 40) & 0x00FF000000000000ULL) | ((x << 24) & 0x0000FF0000000000ULL) | ((x << 8) & 0x000000FF00000000ULL) | diff --git a/jni/love/src/love.cpp b/jni/love/src/love.cpp index 30619e8e..ecf9ff86 100644 --- a/jni/love/src/love.cpp +++ b/jni/love/src/love.cpp @@ -18,13 +18,8 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include "modules/love/love.h" - -#ifndef LOVE_ANDROID #include "common/version.h" -#endif -#include - +#include "modules/love/love.h" #include #ifdef LOVE_BUILD_EXE @@ -48,6 +43,10 @@ extern "C" { #include "common/iOS.h" #endif +#ifdef LOVE_ANDROID +#include "common/android.h" +#endif + #ifdef LOVE_WINDOWS extern "C" { @@ -192,7 +191,7 @@ static int l_print_sdl_log(lua_State *L) break; default: out_string += lua_typename(L, lua_type(L, i)); - sprintf(pointer_buf, ": 0x%lx", (size_t) lua_topointer(L, i)); + sprintf(pointer_buf, ": 0x%lx", (long unsigned int) lua_topointer(L, i)); out_string += pointer_buf; break; } @@ -238,17 +237,12 @@ int main(int argc, char **argv) argv = hack_argv; #endif // LOVE_LEGENDARY_APP_ARGV_HACK -#ifndef LOVE_ANDROID - // TODO: LOVE for Android creates a single library instead of executable - // and library. Therefore this check is not required, but causes a - // duplicate definition of the love::VERSION symbol. - if (strcmp(love::VERSION, love_version()) != 0) + if (strcmp(LOVE_VERSION_STRING, love_version()) != 0) { printf("Version mismatch detected!\nLOVE binary is version %s\n" "LOVE library is version %s\n", LOVE_VERSION_STRING, love_version()); return 1; } -#endif // Oh, you just want the version? Okay! if (argc > 1 && strcmp(argv[1], "--version") == 0) diff --git a/jni/love/src/modules/filesystem/physfs/Filesystem.cpp b/jni/love/src/modules/filesystem/physfs/Filesystem.cpp index d1f225da..d922ca64 100644 --- a/jni/love/src/modules/filesystem/physfs/Filesystem.cpp +++ b/jni/love/src/modules/filesystem/physfs/Filesystem.cpp @@ -175,25 +175,13 @@ bool Filesystem::setIdentity(const char *ident, bool appendToPath) save_identity = "unnamed"; std::string internal_storage_path = SDL_AndroidGetInternalStoragePath(); - std::string save_directory = internal_storage_path + "/save"; save_path_full = std::string(SDL_AndroidGetInternalStoragePath()) + std::string("/save/") + save_identity; - if (love::android::directoryExists(save_path_full.c_str())) - SDL_Log("dir exists"); - else - SDL_Log("does not exist"); - - if (!love::android::directoryExists(save_path_full.c_str())) - { - if (!love::android::mkdir(save_path_full.c_str())) - SDL_Log("Error: Could not create save directory %s!", save_path_full.c_str()); - else - SDL_Log("Save directory %s successfuly created!", save_path_full.c_str()); - } - else - SDL_Log("Save directory %s exists!", save_path_full.c_str()); + if (!love::android::directoryExists(save_path_full.c_str()) && + !love::android::mkdir(save_path_full.c_str())) + SDL_Log("Error: Could not create save directory %s!", save_path_full.c_str()); #endif // We now have something like: @@ -253,9 +241,7 @@ bool Filesystem::setSource(const char *source) if (archive_loaded) { - if (PHYSFS_mountMemory(game_archive_ptr, game_archive_size, love::android::freeGameArchiveMemory, "archive.zip", "/", 0)) - SDL_Log("Mounting of in-memory game archive successful!"); - else + if (!PHYSFS_mountMemory(game_archive_ptr, game_archive_size, love::android::freeGameArchiveMemory, "archive.zip", "/", 0)) { SDL_Log("Mounting of in-memory game archive failed!"); love::android::freeGameArchiveMemory(game_archive_ptr); @@ -278,7 +264,6 @@ bool Filesystem::setSource(const char *source) if (sdcard_main) { - SDL_Log("using game from %s", game_path.c_str()); new_search_path = game_path; sdcard_main->close(sdcard_main); diff --git a/jni/love/src/modules/graphics/Graphics.cpp b/jni/love/src/modules/graphics/Graphics.cpp index 7c1a24db..245f8260 100644 --- a/jni/love/src/modules/graphics/Graphics.cpp +++ b/jni/love/src/modules/graphics/Graphics.cpp @@ -19,12 +19,45 @@ **/ #include "Graphics.h" +#include "math/MathModule.h" namespace love { namespace graphics { +static bool gammaCorrect = false; + +void setGammaCorrect(bool gammacorrect) +{ + gammaCorrect = gammacorrect; +} + +bool isGammaCorrect() +{ + return gammaCorrect; +} + +void gammaCorrectColor(Colorf &c) +{ + if (isGammaCorrect()) + { + c.r = math::Math::instance.gammaToLinear(c.r); + c.g = math::Math::instance.gammaToLinear(c.g); + c.b = math::Math::instance.gammaToLinear(c.b); + } +} + +void unGammaCorrectColor(Colorf &c) +{ + if (isGammaCorrect()) + { + c.r = math::Math::instance.linearToGamma(c.r); + c.g = math::Math::instance.linearToGamma(c.g); + c.b = math::Math::instance.linearToGamma(c.b); + } +} + Graphics::~Graphics() { } @@ -150,7 +183,6 @@ StringMap::Entry Graphics::suppor { { "multicanvas", SUPPORT_MULTI_CANVAS }, { "multicanvasformats", SUPPORT_MULTI_CANVAS_FORMATS }, - { "srgb", SUPPORT_SRGB }, }; StringMap Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries)); diff --git a/jni/love/src/modules/graphics/Graphics.h b/jni/love/src/modules/graphics/Graphics.h index 13c7eed7..0e587732 100644 --- a/jni/love/src/modules/graphics/Graphics.h +++ b/jni/love/src/modules/graphics/Graphics.h @@ -24,6 +24,7 @@ // LOVE #include "common/Module.h" #include "common/StringMap.h" +#include "Color.h" // C++ #include @@ -33,6 +34,31 @@ namespace love namespace graphics { +/** + * Globally sets whether gamma correction is enabled. Ideally this should be set + * prior to using any Graphics module function. + **/ +void setGammaCorrect(bool gammacorrect); + +/** + * Gets whether global gamma correction is enabled. + **/ +bool isGammaCorrect(); + +/** + * Gamma-corrects a color (converts it from sRGB to linear RGB, if + * gamma correction is enabled.) + * The color's components are expected to be in the range of [0, 1]. + **/ +void gammaCorrectColor(Colorf &c); + +/** + * Un-gamma-corrects a color (converts it from linear RGB to sRGB, if + * gamma correction is enabled.) + * The color's components are expected to be in the range of [0, 1]. + **/ +void unGammaCorrectColor(Colorf &c); + class Graphics : public Module { public: @@ -74,7 +100,6 @@ public: { SUPPORT_MULTI_CANVAS, SUPPORT_MULTI_CANVAS_FORMATS, - SUPPORT_SRGB, SUPPORT_MAX_ENUM }; @@ -134,6 +159,14 @@ public: { bool r, g, b, a; + ColorMask() + : r(true), g(true), b(true), a(true) + {} + + ColorMask(bool _r, bool _g, bool _b, bool _a) + : r(_r), g(_g), b(_b), a(_a) + {} + bool operator == (const ColorMask &m) const { return r == m.r && g == m.g && b == m.b && a == m.a; @@ -160,7 +193,7 @@ public: * @param width The viewport width. * @param height The viewport height. **/ - virtual bool setMode(int width, int height, bool &sRGB) = 0; + virtual bool setMode(int width, int height) = 0; /** * Un-sets the current graphics display mode (uninitializing objects if diff --git a/jni/love/src/modules/graphics/opengl/Canvas.cpp b/jni/love/src/modules/graphics/opengl/Canvas.cpp index 7869ab71..f3c735a1 100644 --- a/jni/love/src/modules/graphics/opengl/Canvas.cpp +++ b/jni/love/src/modules/graphics/opengl/Canvas.cpp @@ -398,7 +398,7 @@ void Canvas::startGrab(const std::vector &canvases) // Whether the new canvas list is different from the old one. // A more thorough check is done below. bool canvaseschanged = canvases.size() != attachedCanvases.size(); - bool hasSRGBcanvas = (format == FORMAT_SRGB); + bool hasSRGBcanvas = getSizedFormat(format) == FORMAT_SRGB; if (canvases.size() > 0) { @@ -430,7 +430,7 @@ void Canvas::startGrab(const std::vector &canvases) if (!canvaseschanged && canvases[i] != attachedCanvases[i]) canvaseschanged = true; - if (otherformat == FORMAT_SRGB) + if (getSizedFormat(otherformat) == FORMAT_SRGB) hasSRGBcanvas = true; } @@ -484,9 +484,10 @@ void Canvas::startGrab() // Make sure the correct sRGB setting is used when drawing to the canvas. if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control) { - if (format == FORMAT_SRGB && !gl.hasFramebufferSRGB()) + bool isSRGB = getSizedFormat(format) == FORMAT_SRGB; + if (isSRGB && !gl.hasFramebufferSRGB()) gl.setFramebufferSRGB(true); - else if (format != FORMAT_SRGB && gl.hasFramebufferSRGB()) + else if (!isSRGB && gl.hasFramebufferSRGB()) gl.setFramebufferSRGB(false); } @@ -655,8 +656,10 @@ Canvas::Format Canvas::getSizedFormat(Canvas::Format format) switch (format) { case FORMAT_NORMAL: - // 32-bit render targets don't have guaranteed support on OpenGL ES 2. - if (GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8)) + if (isGammaCorrect()) + return FORMAT_SRGB; + else if (GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8)) + // 32-bit render targets don't have guaranteed support on GLES2. return FORMAT_RGBA4; else return FORMAT_RGBA8; diff --git a/jni/love/src/modules/graphics/opengl/Canvas.h b/jni/love/src/modules/graphics/opengl/Canvas.h index 8d63d15f..23e89c21 100644 --- a/jni/love/src/modules/graphics/opengl/Canvas.h +++ b/jni/love/src/modules/graphics/opengl/Canvas.h @@ -46,7 +46,7 @@ public: // Different Canvas render target formats. enum Format { - FORMAT_NORMAL, // Usually RGBA8 or a similar fallback. Always supported. + FORMAT_NORMAL, // Usually SRGB, RGBA8 or a similar fallback. Always supported. FORMAT_HDR, // Usually RGBA16F. Not always supported. FORMAT_RGBA4, // RGBA with 4 bits per channel. FORMAT_RGB5A1, // RGB with 5 bits per channel, and A with 1 bit. diff --git a/jni/love/src/modules/graphics/opengl/GLBuffer.cpp b/jni/love/src/modules/graphics/opengl/GLBuffer.cpp index b13ff89f..416edee1 100644 --- a/jni/love/src/modules/graphics/opengl/GLBuffer.cpp +++ b/jni/love/src/modules/graphics/opengl/GLBuffer.cpp @@ -34,7 +34,7 @@ namespace graphics namespace opengl { -GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage) +GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage, uint32 mapflags) : is_bound(false) , is_mapped(false) , size(size) @@ -42,6 +42,9 @@ GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage) , usage(usage) , vbo(0) , memory_map(nullptr) + , modified_offset(0) + , modified_size(0) + , map_flags(mapflags) { try { @@ -79,6 +82,9 @@ void *GLBuffer::map() is_mapped = true; + modified_offset = 0; + modified_size = 0; + return memory_map; } @@ -96,13 +102,21 @@ void GLBuffer::unmapStream() glBufferData(getTarget(), (GLsizeiptr) getSize(), memory_map, getUsage()); } -void GLBuffer::unmap(size_t usedOffset, size_t usedSize) +void GLBuffer::unmap() { if (!is_mapped) return; - usedOffset = std::min(usedOffset, getSize()); - usedSize = std::min(usedSize, getSize() - usedOffset); + if ((map_flags & MAP_EXPLICIT_RANGE_MODIFY) != 0) + { + modified_offset = std::min(modified_offset, getSize() - 1); + modified_size = std::min(modified_size, getSize() - modified_offset); + } + else + { + modified_offset = 0; + modified_size = getSize(); + } // VBO::bind is a no-op when the VBO is mapped, so we have to make sure it's // bound here. @@ -112,28 +126,52 @@ void GLBuffer::unmap(size_t usedOffset, size_t usedSize) is_bound = true; } - switch (getUsage()) + if (modified_size > 0) { - case GL_STATIC_DRAW: - unmapStatic(usedOffset, usedSize); - break; - case GL_STREAM_DRAW: - unmapStream(); - break; - case GL_DYNAMIC_DRAW: - default: - // It's probably more efficient to treat it like a streaming buffer if - // more than a third of its contents have been modified during the map(). - if (usedSize >= getSize() / 3) + switch (getUsage()) + { + case GL_STATIC_DRAW: + unmapStatic(modified_offset, modified_size); + break; + case GL_STREAM_DRAW: unmapStream(); - else - unmapStatic(usedOffset, usedSize); - break; + break; + case GL_DYNAMIC_DRAW: + default: + // It's probably more efficient to treat it like a streaming buffer if + // at least a third of its contents have been modified during the map(). + if (modified_size >= getSize() / 3) + unmapStream(); + else + unmapStatic(modified_offset, modified_size); + break; + } } + modified_offset = 0; + modified_size = 0; + is_mapped = false; } +void GLBuffer::setMappedRangeModified(size_t offset, size_t modifiedsize) +{ + if (!is_mapped || !(map_flags & MAP_EXPLICIT_RANGE_MODIFY)) + return; + + // We're being conservative right now by internally marking the whole range + // from the start of section a to the end of section b as modified if both + // a and b are marked as modified. + + size_t old_range_end = modified_offset + modified_offset; + + modified_offset = std::min(modified_offset, offset); + + size_t new_range_end = std::max(offset + modifiedsize, old_range_end); + + modified_size = new_range_end - modified_offset; +} + void GLBuffer::bind() { if (!is_mapped) @@ -155,7 +193,9 @@ void GLBuffer::fill(size_t offset, size_t size, const void *data) { memcpy(memory_map + offset, data, size); - if (!is_mapped) + if (is_mapped) + setMappedRangeModified(offset, size); + else glBufferSubData(getTarget(), (GLintptr) offset, (GLsizeiptr) size, data); } diff --git a/jni/love/src/modules/graphics/opengl/GLBuffer.h b/jni/love/src/modules/graphics/opengl/GLBuffer.h index 44a95e2d..940db89b 100644 --- a/jni/love/src/modules/graphics/opengl/GLBuffer.h +++ b/jni/love/src/modules/graphics/opengl/GLBuffer.h @@ -47,6 +47,11 @@ class GLBuffer : public Volatile { public: + enum MapFlags + { + MAP_EXPLICIT_RANGE_MODIFY = 0x01, // see setMappedRangeModified. + }; + /** * Constructor. * @@ -54,7 +59,7 @@ public: * @param target The target GLBuffer object, e.g. GL_ARRAY_BUFFER. * @param usage Usage hint, e.g. GL_DYNAMIC_DRAW. */ - GLBuffer(size_t size, const void *data, GLenum target, GLenum usage); + GLBuffer(size_t size, const void *data, GLenum target, GLenum usage, uint32 mapflags = 0); /** * Destructor. @@ -118,12 +123,14 @@ public: * when used to draw elements. * * The GLBuffer must be bound to use this function. - * - * @param usedOffset The offset into the mapped buffer indicating the - * sub-range of data modified. Optional. - * @param usedSize The size of the sub-range of modified data. Optional. */ - void unmap(size_t usedOffset = 0, size_t usedSize = -1); + void unmap(); + + /** + * Marks a range of mapped data as modified. + * NOTE: GLBuffer::fill calls this internally for you. + **/ + void setMappedRangeModified(size_t offset, size_t size); /** * Bind the GLBuffer to its specified target. @@ -137,7 +144,7 @@ public: void unbind(); /** - * Fill a portion of the buffer with data. + * Fill a portion of the buffer with data and marks the range as modified. * * The GLBuffer must be bound to use this function. * @@ -155,6 +162,11 @@ public: */ const void *getPointer(size_t offset) const; + uint32 getMapFlags() const + { + return map_flags; + } + // Implements Volatile. bool loadVolatile() override; void unloadVolatile() override; @@ -262,6 +274,11 @@ private: // A pointer to mapped memory. char *memory_map; + size_t modified_offset; + size_t modified_size; + + uint32 map_flags; + }; // GLBuffer diff --git a/jni/love/src/modules/graphics/opengl/Graphics.cpp b/jni/love/src/modules/graphics/opengl/Graphics.cpp index 0c5bccd9..dd13fa21 100644 --- a/jni/love/src/modules/graphics/opengl/Graphics.cpp +++ b/jni/love/src/modules/graphics/opengl/Graphics.cpp @@ -26,6 +26,7 @@ #include "Graphics.h" #include "font/Font.h" #include "Polyline.h" +#include "math/MathModule.h" // C++ #include @@ -70,7 +71,7 @@ Graphics::Graphics() currentWindow->getWindow(w, h, wsettings); if (currentWindow->isOpen()) - setMode(w, h, wsettings.sRGB); + setMode(w, h); } } @@ -235,7 +236,7 @@ void Graphics::setViewportSize(int width, int height) setCanvas(canvases); } -bool Graphics::setMode(int width, int height, bool &sRGB) +bool Graphics::setMode(int width, int height) { currentWindow.set(Module::getInstance(Module::M_WINDOW)); @@ -275,12 +276,12 @@ bool Graphics::setMode(int width, int height, bool &sRGB) || GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB) { if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control) - gl.setFramebufferSRGB(sRGB); + gl.setFramebufferSRGB(isGammaCorrect()); } else - sRGB = false; + setGammaCorrect(false); - Canvas::screenHasSRGB = sRGB; + Canvas::screenHasSRGB = isGammaCorrect(); bool enabledebug = false; @@ -345,7 +346,7 @@ void Graphics::unSetMode() void Graphics::setActive(bool enable) { // Make sure all pending OpenGL commands have fully executed before - // returning, if we're going from active to inactive. + // returning, when going from active to inactive. This is required on iOS. if (isCreated() && this->active && !enable) glFinish(); @@ -426,13 +427,17 @@ void Graphics::reset() origin(); } -void Graphics::clear(Color c) +void Graphics::clear(Colorf c) { - glClearColor(c.r / 255.0f, c.g / 255.0f, c.b / 255.0f, c.a / 255.0f); + Colorf nc = Colorf(c.r/255.0f, c.g/255.0f, c.b/255.0f, c.a/255.0f); + + gammaCorrectColor(nc); + + glClearColor(nc.r, nc.g, nc.b, nc.a); glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void Graphics::clear(const std::vector &colors) +void Graphics::clear(const std::vector &colors) { if (colors.size() == 0) return; @@ -447,7 +452,16 @@ void Graphics::clear(const std::vector &colors) for (int i = 0; i < (int) colors.size(); i++) { - const GLfloat c[] = {colors[i].r/255.f, colors[i].g/255.f, colors[i].b/255.f, colors[i].a/255.f}; + GLfloat c[] = {colors[i].r/255.f, colors[i].g/255.f, colors[i].b/255.f, colors[i].a/255.f}; + + // TODO: Investigate a potential bug on AMD drivers in Windows/Linux + // which apparently causes the clear color to be incorrect when mixed + // sRGB and linear render targets are active. + if (isGammaCorrect()) + { + for (int i = 0; i < 3; i++) + c[i] = math::Math::instance.gammaToLinear(c[i]); + } if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0) glClearBufferfv(GL_COLOR, i, c); @@ -785,23 +799,32 @@ Text *Graphics::newText(Font *font, const std::string &text) return new Text(font, text); } -void Graphics::setColor(Color c) +bool Graphics::isGammaCorrect() const { - glVertexAttrib4f(ATTRIB_CONSTANTCOLOR, c.r/255.0f, c.g/255.0f, c.b/255.0f, c.a/255.0f); + return love::graphics::isGammaCorrect(); +} + +void Graphics::setColor(Colorf c) +{ + Colorf nc = Colorf(c.r/255.0f, c.g/255.0f, c.b/255.0f, c.a/255.0f); + + gammaCorrectColor(nc); + + glVertexAttrib4f(ATTRIB_CONSTANTCOLOR, nc.r, nc.g, nc.b, nc.a); states.back().color = c; } -Color Graphics::getColor() const +Colorf Graphics::getColor() const { return states.back().color; } -void Graphics::setBackgroundColor(Color c) +void Graphics::setBackgroundColor(Colorf c) { states.back().backgroundColor = c; } -Color Graphics::getBackgroundColor() const +Colorf Graphics::getBackgroundColor() const { return states.back().backgroundColor; } @@ -1456,10 +1479,6 @@ bool Graphics::isSupported(Support feature) const return Canvas::isMultiCanvasSupported(); case SUPPORT_MULTI_CANVAS_FORMATS: return Canvas::isMultiFormatMultiCanvasSupported(); - case SUPPORT_SRGB: - // sRGB support for the screen is guaranteed if it's supported as a - // Canvas format. - return Canvas::isFormatSupported(Canvas::FORMAT_SRGB); default: return false; } @@ -1528,87 +1547,6 @@ void Graphics::origin() pixelSizeStack.back() = 1; } -Graphics::DisplayState::DisplayState() - : color(255, 255, 255, 255) - , backgroundColor(0, 0, 0, 255) - , blendMode(BLEND_ALPHA) - , blendMultiplyAlpha(true) - , lineWidth(1.0f) - , lineStyle(LINE_SMOOTH) - , lineJoin(LINE_JOIN_MITER) - , pointSize(1.0f) - , scissor(false) - , scissorBox() - , stencilTest(false) - , stencilInvert(false) - , font(nullptr) - , shader(nullptr) - , colorMask({true, true, true, true}) - , wireframe(false) - , defaultFilter() - , defaultMipmapFilter(Texture::FILTER_NEAREST) - , defaultMipmapSharpness(0.0f) -{ -} - -Graphics::DisplayState::DisplayState(const DisplayState &other) - : color(other.color) - , backgroundColor(other.backgroundColor) - , blendMode(other.blendMode) - , blendMultiplyAlpha(other.blendMultiplyAlpha) - , lineWidth(other.lineWidth) - , lineStyle(other.lineStyle) - , lineJoin(other.lineJoin) - , pointSize(other.pointSize) - , scissor(other.scissor) - , scissorBox(other.scissorBox) - , stencilTest(other.stencilTest) - , stencilInvert(other.stencilInvert) - , font(other.font) - , shader(other.shader) - , canvases(other.canvases) - , colorMask(other.colorMask) - , wireframe(other.wireframe) - , defaultFilter(other.defaultFilter) - , defaultMipmapFilter(other.defaultMipmapFilter) - , defaultMipmapSharpness(other.defaultMipmapSharpness) -{ -} - -Graphics::DisplayState::~DisplayState() -{ -} - -Graphics::DisplayState &Graphics::DisplayState::operator = (const DisplayState &other) -{ - color = other.color; - backgroundColor = other.backgroundColor; - blendMode = other.blendMode; - blendMultiplyAlpha = other.blendMultiplyAlpha; - lineWidth = other.lineWidth; - lineStyle = other.lineStyle; - lineJoin = other.lineJoin; - pointSize = other.pointSize; - scissor = other.scissor; - scissorBox = other.scissorBox; - stencilTest = other.stencilTest; - stencilInvert = other.stencilInvert; - - font = other.font; - shader = other.shader; - canvases = other.canvases; - - colorMask = other.colorMask; - - wireframe = other.wireframe; - - defaultFilter = other.defaultFilter; - defaultMipmapFilter = other.defaultMipmapFilter; - defaultMipmapSharpness = other.defaultMipmapSharpness; - - return *this; -} - } // opengl } // graphics } // love diff --git a/jni/love/src/modules/graphics/opengl/Graphics.h b/jni/love/src/modules/graphics/opengl/Graphics.h index c8457752..1dfe655e 100644 --- a/jni/love/src/modules/graphics/opengl/Graphics.h +++ b/jni/love/src/modules/graphics/opengl/Graphics.h @@ -66,7 +66,7 @@ public: const char *getName() const; virtual void setViewportSize(int width, int height); - virtual bool setMode(int width, int height, bool &sRGB); + virtual bool setMode(int width, int height); virtual void unSetMode(); virtual void setActive(bool active); @@ -84,12 +84,12 @@ public: /** * Clears the screen to a specific color. **/ - void clear(Color c); + void clear(Colorf c); /** * Clears each active canvas to a different color. **/ - void clear(const std::vector &colors); + void clear(const std::vector &colors); /** * Discards the contents of the screen. @@ -183,26 +183,28 @@ public: Text *newText(Font *font, const std::string &text = ""); + bool isGammaCorrect() const; + /** * Sets the foreground color. * @param c The new foreground color. **/ - void setColor(Color c); + void setColor(Colorf c); /** * Gets current color. **/ - Color getColor() const; + Colorf getColor() const; /** * Sets the background Color. **/ - void setBackgroundColor(Color c); + void setBackgroundColor(Colorf c); /** * Gets the current background color. **/ - Color getBackgroundColor() const; + Colorf getBackgroundColor() const; void setFont(Font *font); Font *getFont(); @@ -463,44 +465,38 @@ private: struct DisplayState { - Color color; - Color backgroundColor; + Colorf color = Colorf(255.0, 255.0, 255.0, 255.0); + Colorf backgroundColor = Colorf(0.0, 0.0, 0.0, 255.0); - BlendMode blendMode; - bool blendMultiplyAlpha; + BlendMode blendMode = BLEND_ALPHA; + bool blendMultiplyAlpha = true; - float lineWidth; - LineStyle lineStyle; - LineJoin lineJoin; + float lineWidth = 1.0f; + LineStyle lineStyle = LINE_SMOOTH; + LineJoin lineJoin = LINE_JOIN_MITER; - float pointSize; + float pointSize = 1.0f; - bool scissor; - OpenGL::Viewport scissorBox; + bool scissor = false; + OpenGL::Viewport scissorBox = OpenGL::Viewport(); // Stencil. - bool stencilTest; - bool stencilInvert; + bool stencilTest = false; + bool stencilInvert = false; StrongRef font; StrongRef shader; std::vector> canvases; - ColorMask colorMask; + ColorMask colorMask = ColorMask(true, true, true, true); - bool wireframe; + bool wireframe = false; - Texture::Filter defaultFilter; + Texture::Filter defaultFilter = Texture::Filter(); - Texture::FilterMode defaultMipmapFilter; - float defaultMipmapSharpness; - - DisplayState(); - DisplayState(const DisplayState &other); - ~DisplayState(); - - DisplayState &operator = (const DisplayState &other); + Texture::FilterMode defaultMipmapFilter = Texture::FILTER_NEAREST; + float defaultMipmapSharpness = 0.0f; }; void restoreState(const DisplayState &s); diff --git a/jni/love/src/modules/graphics/opengl/Image.cpp b/jni/love/src/modules/graphics/opengl/Image.cpp index a217e7fb..9503d12e 100644 --- a/jni/love/src/modules/graphics/opengl/Image.cpp +++ b/jni/love/src/modules/graphics/opengl/Image.cpp @@ -20,6 +20,7 @@ #include "Image.h" +#include "graphics/Graphics.h" #include "common/int.h" // STD @@ -91,6 +92,7 @@ Image::Image(const std::vector &imagedata, const Flags , mipmapSharpness(defaultMipmapSharpness) , compressed(false) , flags(flags) + , sRGB(false) , usingDefaultTexture(false) , textureMemorySize(0) { @@ -117,18 +119,22 @@ Image::Image(const std::vector &compressedda , mipmapSharpness(defaultMipmapSharpness) , compressed(true) , flags(flags) + , sRGB(false) , usingDefaultTexture(false) , textureMemorySize(0) { - this->flags.sRGB = (flags.sRGB || compresseddata[0]->isSRGB()); - width = compresseddata[0]->getWidth(0); height = compresseddata[0]->getHeight(0); if (verifyMipmapLevels(compresseddata)) this->flags.mipmaps = true; else if (flags.mipmaps && getMipmapCount(width, height) != compresseddata[0]->getMipmapCount()) - throw love::Exception("Image cannot have mipmaps: compressed image data does not have all required mipmap levels."); + { + if (compresseddata[0]->getMipmapCount() == 1) + this->flags.mipmaps = false; + else + throw love::Exception("Image cannot have mipmaps: compressed image data does not have all required mipmap levels."); + } for (const auto &cd : compresseddata) { @@ -179,6 +185,14 @@ void Image::preload() if (flags.mipmaps) filter.mipmap = defaultMipmapFilter; + + if (!isGammaCorrect()) + flags.linear = false; + + if (isGammaCorrect() && !flags.linear) + sRGB = true; + else + sRGB = false; } void Image::generateMipmaps() @@ -214,7 +228,10 @@ void Image::loadDefaultTexture() void Image::loadFromCompressedData() { - GLenum iformat = getCompressedFormat(cdata[0]->getFormat()); + GLenum iformat = getCompressedFormat(cdata[0]->getFormat(), sRGB); + + if (isGammaCorrect() && !sRGB) + flags.linear = true; int count = 1; @@ -238,13 +255,13 @@ void Image::loadFromCompressedData() void Image::loadFromImageData() { - GLenum iformat = flags.sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8; + GLenum iformat = sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8; GLenum format = GL_RGBA; // in GLES2, the internalformat and format params of TexImage have to match. if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0) { - format = flags.sRGB ? GL_SRGB_ALPHA : GL_RGBA; + format = sRGB ? GL_SRGB_ALPHA : GL_RGBA; iformat = format; } @@ -267,24 +284,24 @@ bool Image::loadVolatile() { OpenGL::TempDebugGroup debuggroup("Image load"); - if (isCompressed() && !hasCompressedTextureSupport(cdata[0]->getFormat(), flags.sRGB)) + if (isCompressed() && !hasCompressedTextureSupport(cdata[0]->getFormat(), sRGB)) { const char *str; if (image::CompressedImageData::getConstant(cdata[0]->getFormat(), str)) { throw love::Exception("Cannot create image: " - "%s%s compressed images are not supported on this system.", flags.sRGB ? "sRGB " : "", str); + "%s%s compressed images are not supported on this system.", sRGB ? "sRGB " : "", str); } else throw love::Exception("cannot create image: format is not supported on this system."); } else if (!isCompressed()) { - if (flags.sRGB && !hasSRGBSupport()) + if (sRGB && !hasSRGBSupport()) throw love::Exception("sRGB images are not supported on this system."); // GL_EXT_sRGB doesn't support glGenerateMipmap for sRGB textures. - if (flags.sRGB && (GLAD_ES_VERSION_2_0 && GLAD_EXT_sRGB && !GLAD_ES_VERSION_3_0) + if (sRGB && (GLAD_ES_VERSION_2_0 && GLAD_EXT_sRGB && !GLAD_ES_VERSION_3_0) && data.size() <= 1) { flags.mipmaps = false; @@ -402,7 +419,7 @@ bool Image::refresh(int xoffset, int yoffset, int w, int h) // In ES2, the format parameter of TexSubImage must match the internal // format of the texture. - if (flags.sRGB && (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)) + if (sRGB && (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)) format = GL_SRGB_ALPHA; int mipcount = flags.mipmaps ? (int) data.size() : 1; @@ -570,93 +587,111 @@ bool Image::isCompressed() const return compressed; } -GLenum Image::getCompressedFormat(image::CompressedImageData::Format cformat) const +GLenum Image::getCompressedFormat(image::CompressedImageData::Format cformat, bool &isSRGB) const { switch (cformat) { case image::CompressedImageData::FORMAT_DXT1: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT; else return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; case image::CompressedImageData::FORMAT_DXT3: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; else return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; case image::CompressedImageData::FORMAT_DXT5: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; else return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; case image::CompressedImageData::FORMAT_BC4: + isSRGB = false; return GL_COMPRESSED_RED_RGTC1; case image::CompressedImageData::FORMAT_BC4s: + isSRGB = false; return GL_COMPRESSED_SIGNED_RED_RGTC1; case image::CompressedImageData::FORMAT_BC5: + isSRGB = false; return GL_COMPRESSED_RG_RGTC2; case image::CompressedImageData::FORMAT_BC5s: + isSRGB = false; return GL_COMPRESSED_SIGNED_RG_RGTC2; case image::CompressedImageData::FORMAT_BC6H: + isSRGB = false; return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; case image::CompressedImageData::FORMAT_BC6Hs: + isSRGB = false; return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; case image::CompressedImageData::FORMAT_BC7: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; else return GL_COMPRESSED_RGBA_BPTC_UNORM; case image::CompressedImageData::FORMAT_ETC1: // The ETC2 format can load ETC1 textures. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility) - return GL_COMPRESSED_RGB8_ETC2; + { + if (isSRGB) + return GL_COMPRESSED_SRGB8_ETC2; + else + return GL_COMPRESSED_RGB8_ETC2; + } else + { + isSRGB = false; return GL_ETC1_RGB8_OES; + } case image::CompressedImageData::FORMAT_ETC2_RGB: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB8_ETC2; else return GL_COMPRESSED_RGB8_ETC2; case image::CompressedImageData::FORMAT_ETC2_RGBA: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; else return GL_COMPRESSED_RGBA8_ETC2_EAC; case image::CompressedImageData::FORMAT_ETC2_RGBA1: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; else return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; case image::CompressedImageData::FORMAT_EAC_R: + isSRGB = false; return GL_COMPRESSED_R11_EAC; case image::CompressedImageData::FORMAT_EAC_Rs: + isSRGB = false; return GL_COMPRESSED_SIGNED_R11_EAC; case image::CompressedImageData::FORMAT_EAC_RG: + isSRGB = false; return GL_COMPRESSED_RG11_EAC; case image::CompressedImageData::FORMAT_EAC_RGs: + isSRGB = false; return GL_COMPRESSED_SIGNED_RG11_EAC; case image::CompressedImageData::FORMAT_PVR1_RGB2: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT; else return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; case image::CompressedImageData::FORMAT_PVR1_RGB4: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT; else return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; case image::CompressedImageData::FORMAT_PVR1_RGBA2: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT; else return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; case image::CompressedImageData::FORMAT_PVR1_RGBA4: - if (flags.sRGB) + if (isSRGB) return GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT; else return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; default: - if (flags.sRGB) + if (isSRGB) return GL_SRGB8_ALPHA8; else return GL_RGBA8; @@ -729,7 +764,7 @@ bool Image::getConstant(FlagType in, const char *&out) StringMap::Entry Image::flagNameEntries[] = { {"mipmaps", Image::FLAG_TYPE_MIPMAPS}, - {"srgb", Image::FLAG_TYPE_SRGB}, + {"linear", Image::FLAG_TYPE_LINEAR}, }; StringMap Image::flagNames(Image::flagNameEntries, sizeof(Image::flagNameEntries)); diff --git a/jni/love/src/modules/graphics/opengl/Image.h b/jni/love/src/modules/graphics/opengl/Image.h index 57308df2..f9966cc9 100644 --- a/jni/love/src/modules/graphics/opengl/Image.h +++ b/jni/love/src/modules/graphics/opengl/Image.h @@ -55,14 +55,14 @@ public: enum FlagType { FLAG_TYPE_MIPMAPS, - FLAG_TYPE_SRGB, + FLAG_TYPE_LINEAR, FLAG_TYPE_MAX_ENUM }; struct Flags { bool mipmaps = false; - bool sRGB = false;; + bool linear = false; }; /** @@ -147,7 +147,7 @@ private: void loadFromCompressedData(); void loadFromImageData(); - GLenum getCompressedFormat(image::CompressedImageData::Format cformat) const; + GLenum getCompressedFormat(image::CompressedImageData::Format cformat, bool &isSRGB) const; // The ImageData from which the texture is created. May be empty if // Compressed image data was used to create the texture. @@ -170,6 +170,8 @@ private: // The flags used to initialize this Image. Flags flags; + bool sRGB; + // True if the image wasn't able to be properly created and it had to fall // back to a default texture. bool usingDefaultTexture; diff --git a/jni/love/src/modules/graphics/opengl/Mesh.cpp b/jni/love/src/modules/graphics/opengl/Mesh.cpp index 8b39b172..cc051134 100644 --- a/jni/love/src/modules/graphics/opengl/Mesh.cpp +++ b/jni/love/src/modules/graphics/opengl/Mesh.cpp @@ -63,8 +63,6 @@ Mesh::Mesh(const std::vector &vertexformat, const void *data, size , vbo(nullptr) , vertexCount(0) , vertexStride(0) - , vboUsedOffset(0) - , vboUsedSize(0) , ibo(nullptr) , elementCount(0) , elementDataType(0) @@ -81,7 +79,7 @@ Mesh::Mesh(const std::vector &vertexformat, const void *data, size if (vertexCount == 0) throw love::Exception("Data size is too small for specified vertex attribute formats."); - vbo = new GLBuffer(datasize, data, GL_ARRAY_BUFFER, getGLBufferUsage(usage)); + vbo = new GLBuffer(datasize, data, GL_ARRAY_BUFFER, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); vertexScratchBuffer = new char[vertexStride]; } @@ -91,8 +89,6 @@ Mesh::Mesh(const std::vector &vertexformat, int vertexcount, DrawM , vbo(nullptr) , vertexCount((size_t) vertexcount) , vertexStride(0) - , vboUsedOffset(0) - , vboUsedSize(0) , ibo(nullptr) , elementCount(0) , elementDataType(getGLDataTypeFromMax(vertexcount)) @@ -108,11 +104,12 @@ Mesh::Mesh(const std::vector &vertexformat, int vertexcount, DrawM size_t buffersize = vertexCount * vertexStride; - vbo = new GLBuffer(buffersize, nullptr, GL_ARRAY_BUFFER, getGLBufferUsage(usage)); + vbo = new GLBuffer(buffersize, nullptr, GL_ARRAY_BUFFER, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); // Initialize the buffer's contents to 0. GLBuffer::Bind bind(*vbo); memset(vbo->map(), 0, buffersize); + vbo->setMappedRangeModified(0, vbo->getSize()); vbo->unmap(); vertexScratchBuffer = new char[vertexStride]; @@ -198,8 +195,7 @@ void Mesh::setVertex(size_t vertindex, const void *data, size_t datasize) memcpy(bufferdata + offset, data, size); - vboUsedOffset = std::min(vboUsedOffset, offset); - vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset); + vbo->setMappedRangeModified(offset, size); } size_t Mesh::getVertex(size_t vertindex, void *data, size_t datasize) @@ -216,12 +212,6 @@ size_t Mesh::getVertex(size_t vertindex, void *data, size_t datasize) memcpy(data, bufferdata + offset, size); - if (vboUsedSize == 0) - { - vboUsedOffset = std::min(vboUsedOffset, offset); - vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset); - } - return size; } @@ -246,8 +236,7 @@ void Mesh::setVertexAttribute(size_t vertindex, int attribindex, const void *dat memcpy(bufferdata + offset, data, size); - vboUsedOffset = std::min(vboUsedOffset, offset); - vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset); + vbo->setMappedRangeModified(offset, size); } size_t Mesh::getVertexAttribute(size_t vertindex, int attribindex, void *data, size_t datasize) @@ -267,12 +256,6 @@ size_t Mesh::getVertexAttribute(size_t vertindex, int attribindex, void *data, s memcpy(data, bufferdata + offset, size); - if (vboUsedSize == 0) - { - vboUsedOffset = std::min(vboUsedOffset, offset); - vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset); - } - return size; } @@ -298,6 +281,7 @@ Mesh::DataType Mesh::getAttributeInfo(int attribindex, int &components) const DataType type = vertexFormat[attribindex].type; components = vertexFormat[attribindex].components; + return type; } @@ -377,17 +361,15 @@ void Mesh::unmapVertexData() { // Assume the whole buffer was modified. GLBuffer::Bind bind(*vbo); + vbo->setMappedRangeModified(0, vbo->getSize()); vbo->unmap(); - - vboUsedOffset = vboUsedSize = 0; } void Mesh::flush() { { GLBuffer::Bind vbobind(*vbo); - vbo->unmap(vboUsedOffset, vboUsedSize); - vboUsedOffset = vboUsedSize = 0; + vbo->unmap(); } if (ibo != nullptr) @@ -574,8 +556,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo GLBuffer::Bind vbobind(*mesh->vbo); // Make sure the buffer isn't mapped (sends data to GPU if needed.) - mesh->vbo->unmap(mesh->vboUsedOffset, mesh->vboUsedSize); - mesh->vboUsedOffset = mesh->vboUsedSize = 0; + mesh->vbo->unmap(); size_t offset = mesh->getAttributeOffset(attrib.second.index); const void *gloffset = mesh->vbo->getPointer(offset); diff --git a/jni/love/src/modules/graphics/opengl/Mesh.h b/jni/love/src/modules/graphics/opengl/Mesh.h index ab608ea1..5482dec2 100644 --- a/jni/love/src/modules/graphics/opengl/Mesh.h +++ b/jni/love/src/modules/graphics/opengl/Mesh.h @@ -240,11 +240,6 @@ private: // avoid memory allocations when using Mesh::setVertex etc. char *vertexScratchBuffer; - // Tracks the range of the vertex buffer that has been used, to make unmap() - // calls as efficient as possible. - size_t vboUsedOffset; - size_t vboUsedSize; - // Element (vertex index) buffer, for the vertex map. GLBuffer *ibo; size_t elementCount; diff --git a/jni/love/src/modules/graphics/opengl/ParticleSystem.cpp b/jni/love/src/modules/graphics/opengl/ParticleSystem.cpp index 302c12d4..b08ee83b 100644 --- a/jni/love/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/jni/love/src/modules/graphics/opengl/ParticleSystem.cpp @@ -43,11 +43,6 @@ namespace love::math::RandomGenerator rng; -Colorf colorToFloat(const Color &c) -{ - return Colorf((float)c.r/255.0f, (float)c.g/255.0f, (float)c.b/255.0f, (float)c.a/255.0f); -} - float calculate_variation(float inner, float outer, float var) { float low = inner - (outer/2.0f)*var; @@ -261,35 +256,34 @@ void ParticleSystem::initParticle(Particle *p, float t) p->life = (float) rng.random(min, max); p->lifetime = p->life; - p->position[0] = pos.x; - p->position[1] = pos.y; + p->position = pos; switch (areaSpreadDistribution) { case DISTRIBUTION_UNIFORM: - p->position[0] += (float) rng.random(-areaSpread.getX(), areaSpread.getX()); - p->position[1] += (float) rng.random(-areaSpread.getY(), areaSpread.getY()); + p->position.x += (float) rng.random(-areaSpread.getX(), areaSpread.getX()); + p->position.y += (float) rng.random(-areaSpread.getY(), areaSpread.getY()); break; case DISTRIBUTION_NORMAL: - p->position[0] += (float) rng.randomNormal(areaSpread.getX()); - p->position[1] += (float) rng.randomNormal(areaSpread.getY()); + p->position.x += (float) rng.randomNormal(areaSpread.getX()); + p->position.y += (float) rng.randomNormal(areaSpread.getY()); break; case DISTRIBUTION_NONE: default: break; } - min = direction - spread/2.0f; - max = direction + spread/2.0f; - p->direction = (float) rng.random(min, max); - p->origin = pos; min = speedMin; max = speedMax; float speed = (float) rng.random(min, max); - p->velocity = love::Vector(cosf(p->direction), sinf(p->direction)); - p->velocity *= speed; + + min = direction - spread/2.0f; + max = direction + spread/2.0f; + float dir = (float) rng.random(min, max); + + p->velocity = love::Vector(cosf(dir), sinf(dir)) * speed; p->linearAcceleration.x = (float) rng.random(linearAccelerationMin.x, linearAccelerationMax.x); p->linearAcceleration.y = (float) rng.random(linearAccelerationMin.y, linearAccelerationMax.y); @@ -706,30 +700,31 @@ love::Vector ParticleSystem::getOffset() const return offset; } -void ParticleSystem::setColor(const Color &color) +void ParticleSystem::setColor(const std::vector &newColors) { - colors.resize(1); - colors[0] = colorToFloat(color); -} + colors = newColors; -void ParticleSystem::setColor(const std::vector &newColors) -{ - colors.resize(newColors.size()); - for (size_t i = 0; i < newColors.size(); ++i) - colors[i] = colorToFloat(newColors[i]); -} - -std::vector ParticleSystem::getColor() const -{ - // The particle system stores colors as floats... - std::vector ncolors(colors.size()); - - for (size_t i = 0; i < colors.size(); ++i) + for (Colorf &c : colors) { - ncolors[i].r = (unsigned char) (colors[i].r * 255); - ncolors[i].g = (unsigned char) (colors[i].g * 255); - ncolors[i].b = (unsigned char) (colors[i].b * 255); - ncolors[i].a = (unsigned char) (colors[i].a * 255); + // We want to store the colors as [0, 1], rather than [0, 255]. + c.r /= 255.0f; + c.g /= 255.0f; + c.b /= 255.0f; + c.a /= 255.0f; + } +} + +std::vector ParticleSystem::getColor() const +{ + // The particle system stores colors in the range of [0, 1]... + std::vector ncolors(colors); + + for (Colorf &c : ncolors) + { + c.r *= 255.0f; + c.g *= 255.0f; + c.b *= 255.0f; + c.a *= 255.0f; } return ncolors; @@ -854,10 +849,8 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo OpenGL::TempDebugGroup debuggroup("ParticleSystem draw"); - Matrix4 t(x, y, angle, sx, sy, ox, oy, kx, ky); - OpenGL::TempTransform transform(gl); - transform.get() *= t; + transform.get() *= Matrix4(x, y, angle, sx, sy, ox, oy, kx, ky); const Vertex *textureVerts = texture->getVertices(); Vertex *pVerts = particleVerts; @@ -865,14 +858,16 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo bool useQuads = !quads.empty(); + Matrix3 t; + // set the vertex data for each particle (transformation, texcoords, color) while (p) { if (useQuads) textureVerts = quads[p->quadIndex]->getVertices(); - // particle vertices are image vertices transformed by particle information - t.setTransformation(p->position[0], p->position[1], p->angle, p->size, p->size, offset.x, offset.y, 0.0f, 0.0f); + // particle vertices are image vertices transformed by particle info + t.setTransformation(p->position.x, p->position.y, p->angle, p->size, p->size, offset.x, offset.y, 0.0f, 0.0f); t.transform(pVerts, textureVerts, 4); // set the texture coordinate and color data for particle vertices @@ -881,7 +876,8 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo pVerts[v].s = textureVerts[v].s; pVerts[v].t = textureVerts[v].t; - // particle colors are stored as floats (0-1) but vertex colors are stored as unsigned bytes (0-255) + // Particle colors are stored as floats (0-1) but vertex colors are + // unsigned bytes (0-255). pVerts[v].r = (unsigned char) (p->color.r*255); pVerts[v].g = (unsigned char) (p->color.g*255); pVerts[v].b = (unsigned char) (p->color.b*255); @@ -927,7 +923,7 @@ void ParticleSystem::update(float dt) { // Temp variables. love::Vector radial, tangential; - love::Vector ppos(p->position[0], p->position[1]); + love::Vector ppos = p->position; // Get vector from particle center to particle. radial = ppos - p->origin; @@ -956,8 +952,7 @@ void ParticleSystem::update(float dt) // Modify position. ppos += p->velocity * dt; - p->position[0] = ppos.getX(); - p->position[1] = ppos.getY(); + p->position = ppos; const float t = 1.0f - p->life / p->lifetime; diff --git a/jni/love/src/modules/graphics/opengl/ParticleSystem.h b/jni/love/src/modules/graphics/opengl/ParticleSystem.h index 05c16fcf..8502f826 100644 --- a/jni/love/src/modules/graphics/opengl/ParticleSystem.h +++ b/jni/love/src/modules/graphics/opengl/ParticleSystem.h @@ -417,22 +417,16 @@ public: **/ love::Vector getOffset() const; - /** - * Sets the color of the particles. - * @param color The color. - **/ - void setColor(const Color &color); - /** * Sets the color of the particles. * @param newColors Array of colors **/ - void setColor(const std::vector &newColors); + void setColor(const std::vector &newColors); /** * Returns the color of the particles. **/ - std::vector getColor() const; + std::vector getColor() const; /** * Sets a list of Quads to use for particles over their lifetime. @@ -534,8 +528,7 @@ protected: float lifetime; float life; - float position[2]; - float direction; + love::Vector position; // Particles gravitate towards this point. love::Vector origin; diff --git a/jni/love/src/modules/graphics/opengl/SpriteBatch.cpp b/jni/love/src/modules/graphics/opengl/SpriteBatch.cpp index c15a9417..6d2d12c3 100644 --- a/jni/love/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/jni/love/src/modules/graphics/opengl/SpriteBatch.cpp @@ -48,8 +48,6 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, Mesh::Usage usage) , color(0) , array_buf(nullptr) , quad_indices(size) - , buffer_used_offset(0) - , buffer_used_size(0) { if (size <= 0) throw love::Exception("Invalid SpriteBatch size."); @@ -60,7 +58,7 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, Mesh::Usage usage) try { - array_buf = new GLBuffer(vertex_size, nullptr, GL_ARRAY_BUFFER, gl_usage); + array_buf = new GLBuffer(vertex_size, nullptr, GL_ARRAY_BUFFER, gl_usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY); } catch (love::Exception &) { @@ -86,7 +84,7 @@ int SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, fl if ((index == -1 && next >= size) || index < -1 || index >= size) return -1; - Matrix4 t(x, y, a, sx, sy, ox, oy, kx, ky); + Matrix3 t(x, y, a, sx, sy, ox, oy, kx, ky); addv(texture->getVertices(), t, (index == -1) ? next : index); @@ -103,7 +101,7 @@ int SpriteBatch::addq(Quad *quad, float x, float y, float a, float sx, float sy, if ((index == -1 && next >= size) || index < -1 || index >= next) return -1; - Matrix4 t(x, y, a, sx, sy, ox, oy, kx, ky); + Matrix3 t(x, y, a, sx, sy, ox, oy, kx, ky); addv(quad->getVertices(), t, (index == -1) ? next : index); @@ -123,9 +121,7 @@ void SpriteBatch::clear() void SpriteBatch::flush() { GLBuffer::Bind bind(*array_buf); - array_buf->unmap(buffer_used_offset, buffer_used_size); - - buffer_used_offset = buffer_used_size = 0; + array_buf->unmap(); } void SpriteBatch::setTexture(Texture *newtexture) @@ -182,7 +178,7 @@ void SpriteBatch::setBufferSize(int newsize) try { - new_array_buf = new GLBuffer(vertex_size, nullptr, array_buf->getTarget(), array_buf->getUsage()); + new_array_buf = new GLBuffer(vertex_size, nullptr, array_buf->getTarget(), array_buf->getUsage(), array_buf->getMapFlags()); // Copy as much of the old data into the new GLBuffer as can fit. GLBuffer::Bind bind(*new_array_buf); @@ -222,10 +218,8 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float OpenGL::TempDebugGroup debuggroup("SpriteBatch draw"); - Matrix4 t(x, y, angle, sx, sy, ox, oy, kx, ky); - OpenGL::TempTransform transform(gl); - transform.get() *= t; + transform.get() *= Matrix4(x, y, angle, sx, sy, ox, oy, kx, ky); gl.bindTexture(*(GLuint *) texture->getHandle()); @@ -233,8 +227,7 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float GLBuffer::Bind element_bind(*quad_indices.getBuffer()); // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.) - array_buf->unmap(buffer_used_offset, buffer_used_size); - buffer_used_offset = buffer_used_size = 0; + array_buf->unmap(); uint32 enabledattribs = ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD; @@ -254,7 +247,7 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float gl.drawElements(GL_TRIANGLES, (GLsizei) quad_indices.getIndexCount(next), quad_indices.getType(), quad_indices.getPointer(0)); } -void SpriteBatch::addv(const Vertex *v, const Matrix4 &m, int index) +void SpriteBatch::addv(const Vertex *v, const Matrix3 &m, int index) { // Needed for colors. Vertex sprite[4] = {v[0], v[1], v[2], v[3]}; @@ -272,9 +265,6 @@ void SpriteBatch::addv(const Vertex *v, const Matrix4 &m, int index) array_buf->map(); array_buf->fill(index * sprite_size, sprite_size, sprite); - - buffer_used_offset = std::min(buffer_used_offset, index * sprite_size); - buffer_used_size = std::max(buffer_used_size, (index + 1) * sprite_size - buffer_used_offset); } void SpriteBatch::setColorv(Vertex *v, const Color &color) diff --git a/jni/love/src/modules/graphics/opengl/SpriteBatch.h b/jni/love/src/modules/graphics/opengl/SpriteBatch.h index 28e33af4..0db524c5 100644 --- a/jni/love/src/modules/graphics/opengl/SpriteBatch.h +++ b/jni/love/src/modules/graphics/opengl/SpriteBatch.h @@ -103,7 +103,7 @@ public: private: - void addv(const Vertex *v, const Matrix4 &m, int index); + void addv(const Vertex *v, const Matrix3 &m, int index); /** * Set the color for vertices. @@ -129,10 +129,6 @@ private: GLBuffer *array_buf; QuadIndices quad_indices; - // The portion of the vertex buffer that's been modified while mapped. - size_t buffer_used_offset; - size_t buffer_used_size; - }; // SpriteBatch } // opengl diff --git a/jni/love/src/modules/graphics/opengl/Text.cpp b/jni/love/src/modules/graphics/opengl/Text.cpp index 5758a9d0..b87f4a38 100644 --- a/jni/love/src/modules/graphics/opengl/Text.cpp +++ b/jni/love/src/modules/graphics/opengl/Text.cpp @@ -170,7 +170,7 @@ void Text::set(const std::string &text) if (text.empty()) return set(); - addTextData({text, -1.0f, Font::ALIGN_MAX_ENUM, false, false, Matrix4()}); + addTextData({text, -1.0f, Font::ALIGN_MAX_ENUM, false, false, Matrix3()}); } void Text::set(const std::string &text, float wrap, Font::AlignMode align) @@ -178,7 +178,7 @@ void Text::set(const std::string &text, float wrap, Font::AlignMode align) if (text.empty()) return set(); - addTextData({text, wrap, align, false, false, Matrix4()}); + addTextData({text, wrap, align, false, false, Matrix3()}); } void Text::set() @@ -191,7 +191,7 @@ void Text::add(const std::string &text, float x, float y, float angle, float sx, if (text.empty()) return; - Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky); + Matrix3 m(x, y, angle, sx, sy, ox, oy, kx, ky); addTextData({text, -1.0f, Font::ALIGN_MAX_ENUM, true, true, m}); } @@ -201,7 +201,7 @@ void Text::addf(const std::string &text, float wrap, Font::AlignMode align, floa if (text.empty()) return; - Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky); + Matrix3 m(x, y, angle, sx, sy, ox, oy, kx, ky); addTextData({text, wrap, align, true, true, m}); } @@ -230,10 +230,8 @@ void Text::draw(float x, float y, float angle, float sx, float sy, float ox, flo const size_t tex_offset = offsetof(Font::GlyphVertex, s); const size_t stride = sizeof(Font::GlyphVertex); - Matrix4 t(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky); - OpenGL::TempTransform transform(gl); - transform.get() *= t; + transform.get() *= Matrix4(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky); { GLBuffer::Bind bind(*vbo); diff --git a/jni/love/src/modules/graphics/opengl/Text.h b/jni/love/src/modules/graphics/opengl/Text.h index 1e8b70d3..15e02b74 100644 --- a/jni/love/src/modules/graphics/opengl/Text.h +++ b/jni/love/src/modules/graphics/opengl/Text.h @@ -74,7 +74,7 @@ private: Font::AlignMode align; bool use_matrix; bool append_vertices; - Matrix4 matrix; + Matrix3 matrix; }; void uploadVertices(const std::vector &vertices, size_t vertoffset); diff --git a/jni/love/src/modules/graphics/opengl/wrap_Canvas.cpp b/jni/love/src/modules/graphics/opengl/wrap_Canvas.cpp index b1d9cdbf..004ee2f9 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -51,12 +51,15 @@ int w_Canvas_renderTo(lua_State *L) luax_catchexcept(L, [&](){ graphics->setCanvas(canvas); }); lua_settop(L, 2); // make sure the function is on top of the stack - lua_call(L, 0, 0); + int status = lua_pcall(L, 0, 0, 0); graphics->setCanvas(oldcanvases); for (Canvas *c : oldcanvases) c->release(); + + if (status != 0) + return lua_error(L); } return 0; diff --git a/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp b/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp index a27e333f..56362d6f 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -54,7 +54,7 @@ int w_reset(lua_State *) int w_clear(lua_State *L) { - std::vector colors(1); + std::vector colors(1); if (lua_isnoneornil(L, 1)) colors[0].set(0, 0, 0, 0); @@ -67,20 +67,20 @@ int w_clear(lua_State *L) for (int j = 1; j <= 4; j++) lua_rawgeti(L, i + 1, j); - colors[i].r = (unsigned char) luaL_checkinteger(L, -4); - colors[i].g = (unsigned char) luaL_checkinteger(L, -3); - colors[i].b = (unsigned char) luaL_checkinteger(L, -2); - colors[i].a = (unsigned char) luaL_optinteger(L, -1, 255); + colors[i].r = (float) luaL_checknumber(L, -4); + colors[i].g = (float) luaL_checknumber(L, -3); + colors[i].b = (float) luaL_checknumber(L, -2); + colors[i].a = (float) luaL_optnumber(L, -1, 255); lua_pop(L, 4); } } else { - colors[0].r = (unsigned char) luaL_checkinteger(L, 1); - colors[0].g = (unsigned char) luaL_checkinteger(L, 2); - colors[0].b = (unsigned char) luaL_checkinteger(L, 3); - colors[0].a = (unsigned char) luaL_optinteger(L, 4, 255); + colors[0].r = (float) luaL_checknumber(L, 1); + colors[0].g = (float) luaL_checknumber(L, 2); + colors[0].b = (float) luaL_checknumber(L, 3); + colors[0].a = (float) luaL_optnumber(L, 4, 255); } luax_catchexcept(L, [&]() { @@ -136,6 +136,12 @@ int w_isActive(lua_State *L) return 1; } +int w_isGammaCorrect(lua_State *L) +{ + luax_pushboolean(L, instance()->isGammaCorrect()); + return 1; +} + int w_getWidth(lua_State *L) { lua_pushinteger(L, instance()->getWidth()); @@ -245,7 +251,7 @@ int w_newImage(lua_State *L) { luaL_checktype(L, 2, LUA_TTABLE); flags.mipmaps = luax_boolflag(L, 2, imageFlagName(Image::FLAG_TYPE_MIPMAPS), flags.mipmaps); - flags.sRGB = luax_boolflag(L, 2, imageFlagName(Image::FLAG_TYPE_SRGB), flags.sRGB); + flags.linear = luax_boolflag(L, 2, imageFlagName(Image::FLAG_TYPE_LINEAR), flags.linear); } bool releasedata = false; @@ -617,24 +623,6 @@ static Mesh::DrawMode luax_optmeshdrawmode(lua_State *L, int idx, Mesh::DrawMode return def; } -static inline size_t writeVertexByteData(lua_State *L, int startidx, int components, char *data) -{ - uint8 *componentdata = (uint8 *) data; - for (int i = 0; i < components; i++) - componentdata[i] = (uint8) luaL_optnumber(L, startidx + i, 255); - - return sizeof(uint8) * components; -} - -static inline size_t writeVertexFloatData(lua_State *L, int startidx, int components, char *data) -{ - float *componentdata = (float *) data; - for (int i = 0; i < components; i++) - componentdata[i] = (float) luaL_optnumber(L, startidx + i, 0); - - return sizeof(float) * components; -} - static Mesh *newStandardMesh(lua_State *L) { Mesh *t = nullptr; @@ -670,10 +658,20 @@ static Mesh *newStandardMesh(lua_State *L) v.y = (float) luaL_checknumber(L, -7); v.s = (float) luaL_optnumber(L, -6, 0.0); v.t = (float) luaL_optnumber(L, -5, 0.0); - v.r = (unsigned char) luaL_optinteger(L, -4, 255); - v.g = (unsigned char) luaL_optinteger(L, -3, 255); - v.b = (unsigned char) luaL_optinteger(L, -2, 255); - v.a = (unsigned char) luaL_optinteger(L, -1, 255); + + Colorf c = { + (float) luaL_optnumber(L, -4, 255) / 255.0f, + (float) luaL_optnumber(L, -3, 255) / 255.0f, + (float) luaL_optnumber(L, -2, 255) / 255.0f, + (float) luaL_optnumber(L, -1, 255) / 255.0f + }; + + gammaCorrectColor(c); + + v.r = (unsigned char) (c.r * 255.0f); + v.g = (unsigned char) (c.g * 255.0f); + v.b = (unsigned char) (c.b * 255.0f); + v.a = (unsigned char) (c.a * 255.0f); lua_pop(L, 9); vertices.push_back(v); @@ -799,16 +797,7 @@ static Mesh *newCustomMesh(lua_State *L) } // Fetch the values from Lua and store them in data buffer. - switch (vertexformat[i].type) - { - case Mesh::DATA_BYTE: - writeVertexByteData(L, -components, components, data); - break; - case Mesh::DATA_FLOAT: - default: - writeVertexFloatData(L, -components, components, data); - break; - } + luax_writeAttributeData(L, -components, vertexformat[i].type, components, data); lua_pop(L, components); @@ -867,25 +856,25 @@ int w_newText(lua_State *L) int w_setColor(lua_State *L) { - Color c; + Colorf c; if (lua_istable(L, 1)) { for (int i = 1; i <= 4; i++) lua_rawgeti(L, 1, i); - c.r = (unsigned char) luaL_checknumber(L, -4); - c.g = (unsigned char) luaL_checknumber(L, -3); - c.b = (unsigned char) luaL_checknumber(L, -2); - c.a = (unsigned char) luaL_optnumber(L, -1, 255); + c.r = (float) luaL_checknumber(L, -4); + c.g = (float) luaL_checknumber(L, -3); + c.b = (float) luaL_checknumber(L, -2); + c.a = (float) luaL_optnumber(L, -1, 255); lua_pop(L, 4); } else { - c.r = (unsigned char) luaL_checknumber(L, 1); - c.g = (unsigned char) luaL_checknumber(L, 2); - c.b = (unsigned char) luaL_checknumber(L, 3); - c.a = (unsigned char) luaL_optnumber(L, 4, 255); + c.r = (float) luaL_checknumber(L, 1); + c.g = (float) luaL_checknumber(L, 2); + c.b = (float) luaL_checknumber(L, 3); + c.a = (float) luaL_optnumber(L, 4, 255); } instance()->setColor(c); return 0; @@ -893,35 +882,35 @@ int w_setColor(lua_State *L) int w_getColor(lua_State *L) { - Color c = instance()->getColor(); - lua_pushinteger(L, c.r); - lua_pushinteger(L, c.g); - lua_pushinteger(L, c.b); - lua_pushinteger(L, c.a); + Colorf c = instance()->getColor(); + lua_pushnumber(L, c.r); + lua_pushnumber(L, c.g); + lua_pushnumber(L, c.b); + lua_pushnumber(L, c.a); return 4; } int w_setBackgroundColor(lua_State *L) { - Color c; + Colorf c; if (lua_istable(L, 1)) { for (int i = 1; i <= 4; i++) lua_rawgeti(L, 1, i); - c.r = (unsigned char) luaL_checknumber(L, -4); - c.g = (unsigned char) luaL_checknumber(L, -3); - c.b = (unsigned char) luaL_checknumber(L, -2); - c.a = (unsigned char) luaL_optnumber(L, -1, 255); + c.r = (float) luaL_checknumber(L, -4); + c.g = (float) luaL_checknumber(L, -3); + c.b = (float) luaL_checknumber(L, -2); + c.a = (float) luaL_optnumber(L, -1, 255); lua_pop(L, 4); } else { - c.r = (unsigned char) luaL_checknumber(L, 1); - c.g = (unsigned char) luaL_checknumber(L, 2); - c.b = (unsigned char) luaL_checknumber(L, 3); - c.a = (unsigned char) luaL_optnumber(L, 4, 255); + c.r = (float) luaL_checknumber(L, 1); + c.g = (float) luaL_checknumber(L, 2); + c.b = (float) luaL_checknumber(L, 3); + c.a = (float) luaL_optnumber(L, 4, 255); } instance()->setBackgroundColor(c); return 0; @@ -929,11 +918,11 @@ int w_setBackgroundColor(lua_State *L) int w_getBackgroundColor(lua_State *L) { - Color c = instance()->getBackgroundColor(); - lua_pushinteger(L, c.r); - lua_pushinteger(L, c.g); - lua_pushinteger(L, c.b); - lua_pushinteger(L, c.a); + Colorf c = instance()->getBackgroundColor(); + lua_pushnumber(L, c.r); + lua_pushnumber(L, c.g); + lua_pushnumber(L, c.b); + lua_pushnumber(L, c.a); return 4; } @@ -1837,6 +1826,7 @@ static const luaL_Reg functions[] = { "isCreated", w_isCreated }, { "isActive", w_isActive }, + { "isGammaCorrect", w_isGammaCorrect }, { "getWidth", w_getWidth }, { "getHeight", w_getHeight }, { "getDimensions", w_getDimensions }, diff --git a/jni/love/src/modules/graphics/opengl/wrap_Graphics.h b/jni/love/src/modules/graphics/opengl/wrap_Graphics.h index 6540d60b..35e63085 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Graphics.h +++ b/jni/love/src/modules/graphics/opengl/wrap_Graphics.h @@ -47,6 +47,7 @@ int w_discard(lua_State *L); int w_present(lua_State *L); int w_isCreated(lua_State *L); int w_isActive(lua_State *L); +int w_isGammaCorrect(lua_State *L); int w_getWidth(lua_State *L); int w_getHeight(lua_State *L); int w_getDimensions(lua_State *L); diff --git a/jni/love/src/modules/graphics/opengl/wrap_Graphics.lua b/jni/love/src/modules/graphics/opengl/wrap_Graphics.lua index a78f0f84..5a52d4b3 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Graphics.lua +++ b/jni/love/src/modules/graphics/opengl/wrap_Graphics.lua @@ -66,9 +66,66 @@ uniform LOVE_UNIFORM_PRECISION mat3 NormalMatrix; #endif uniform mediump vec4 love_ScreenSize;]] +GLSL.FUNCTIONS = [[ +float gammaToLinearPrecise(float c) { + return c <= 0.04045 ? c * 0.077399380804954 : pow((c + 0.055) * 0.9478672985782, 2.4); +} +vec3 gammaToLinearPrecise(vec3 c) { + bvec3 leq = lessThanEqual(c, vec3(0.04045)); + c.r = leq.r ? c.r * 0.077399380804954 : pow((c.r + 0.055) * 0.9478672985782, 2.4); + c.g = leq.g ? c.g * 0.077399380804954 : pow((c.g + 0.055) * 0.9478672985782, 2.4); + c.b = leq.b ? c.b * 0.077399380804954 : pow((c.b + 0.055) * 0.9478672985782, 2.4); + return c; +} +vec4 gammaToLinearPrecise(vec4 c) { return vec4(gammaToLinearPrecise(c.rgb), c.a); } +float linearToGammaPrecise(float c) { + return c < 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1.0 / 2.4) - 0.055; +} +vec3 linearToGammaPrecise(vec3 c) { + bvec3 lt = lessThan(c, vec3(0.0031308)); + c.r = lt.r ? c.r * 12.92 : 1.055 * pow(c.r, 1.0 / 2.4) - 0.055; + c.g = lt.g ? c.g * 12.92 : 1.055 * pow(c.g, 1.0 / 2.4) - 0.055; + c.b = lt.b ? c.b * 12.92 : 1.055 * pow(c.b, 1.0 / 2.4) - 0.055; + return c; +} +vec4 linearToGammaPrecise(vec4 c) { return vec4(linearToGammaPrecise(c.rgb), c.a); } + +// pow(x, 2.2) isn't an amazing approximation, but at least it's efficient... +mediump float gammaToLinearFast(mediump float c) { return pow(max(c, 0.0), 2.2); } +mediump vec3 gammaToLinearFast(mediump vec3 c) { return pow(max(c, vec3(0.0)), vec3(2.2)); } +mediump vec4 gammaToLinearFast(mediump vec4 c) { return vec4(gammaToLinearFast(c.rgb), c.a); } +mediump float linearToGammaFast(mediump float c) { return pow(max(c, 0.0), 1.0 / 2.2); } +mediump vec3 linearToGammaFast(mediump vec3 c) { return pow(max(c, vec3(0.0)), vec3(1.0 / 2.2)); } +mediump vec4 linearToGammaFast(mediump vec4 c) { return vec4(linearToGammaFast(c.rgb), c.a); } + +#ifdef LOVE_PRECISE_GAMMA +#define gammaToLinear gammaToLinearPrecise +#define linearToGamma linearToGammaPrecise +#else +#define gammaToLinear gammaToLinearFast +#define linearToGamma linearToGammaFast +#endif + +#ifdef LOVE_GAMMA_CORRECT +#define gammaCorrectColor gammaToLinear +#define unGammaCorrectColor linearToGamma +#define gammaCorrectColorPrecise gammaToLinearPrecise +#define unGammaCorrectColorPrecise linearToGammaPrecise +#define gammaCorrectColorFast gammaToLinearFast +#define unGammaCorrectColorFast linearToGammaFast +#else +#define gammaCorrectColor +#define unGammaCorrectColor +#define gammaCorrectColorPrecise +#define unGammaCorrectColorPrecise +#define gammaCorrectColorFast +#define unGammaCorrectColorFast +#endif]] + GLSL.VERTEX = { HEADER = [[ #define VERTEX +#define LOVE_PRECISE_GAMMA attribute vec4 VertexPosition; attribute vec4 VertexTexCoord; @@ -85,7 +142,7 @@ uniform mediump float love_PointSize; FOOTER = [[ void main() { VaryingTexCoord = VertexTexCoord; - VaryingColor = VertexColor * ConstantColor; + VaryingColor = gammaCorrectColor(VertexColor) * ConstantColor; #ifdef GL_ES gl_PointSize = love_PointSize; #endif @@ -134,7 +191,10 @@ void main() { local function createVertexCode(vertexcode, lang) local vertexcodes = { lang == "glsles" and GLSL.VERSION_ES or GLSL.VERSION, - GLSL.SYNTAX, GLSL.VERTEX.HEADER, GLSL.UNIFORMS, + GLSL.SYNTAX, + love.graphics.isGammaCorrect() and "#define LOVE_GAMMA_CORRECT 1" or "", + GLSL.VERTEX.HEADER, GLSL.UNIFORMS, + GLSL.FUNCTIONS, lang == "glsles" and "#line 1" or "#line 0", vertexcode, GLSL.VERTEX.FOOTER, @@ -145,7 +205,10 @@ end local function createPixelCode(pixelcode, is_multicanvas, lang) local pixelcodes = { lang == "glsles" and GLSL.VERSION_ES or GLSL.VERSION, - GLSL.SYNTAX, GLSL.PIXEL.HEADER, GLSL.UNIFORMS, + GLSL.SYNTAX, + love.graphics.isGammaCorrect() and "#define LOVE_GAMMA_CORRECT 1" or "", + GLSL.PIXEL.HEADER, GLSL.UNIFORMS, + GLSL.FUNCTIONS, lang == "glsles" and "#line 1" or "#line 0", pixelcode, is_multicanvas and GLSL.PIXEL.FOOTER_MULTI_CANVAS or GLSL.PIXEL.FOOTER, diff --git a/jni/love/src/modules/graphics/opengl/wrap_Image.cpp b/jni/love/src/modules/graphics/opengl/wrap_Image.cpp index d598bde8..8a3a147f 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Image.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_Image.cpp @@ -131,8 +131,8 @@ int w_Image_getFlags(lua_State *L) lua_pushboolean(L, flags.mipmaps); lua_setfield(L, -2, imageFlagName(Image::FLAG_TYPE_MIPMAPS)); - lua_pushboolean(L, flags.sRGB); - lua_setfield(L, -2, imageFlagName(Image::FLAG_TYPE_SRGB)); + lua_pushboolean(L, flags.linear); + lua_setfield(L, -2, imageFlagName(Image::FLAG_TYPE_LINEAR)); return 1; } diff --git a/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp b/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp index 0538edc6..6d6c25b9 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -42,6 +42,7 @@ Mesh *luax_checkmesh(lua_State *L, int idx) static inline size_t writeByteData(lua_State *L, int startidx, int components, char *data) { uint8 *componentdata = (uint8 *) data; + for (int i = 0; i < components; i++) componentdata[i] = (uint8) luaL_optnumber(L, startidx + i, 255); @@ -51,13 +52,14 @@ static inline size_t writeByteData(lua_State *L, int startidx, int components, c static inline size_t writeFloatData(lua_State *L, int startidx, int components, char *data) { float *componentdata = (float *) data; + for (int i = 0; i < components; i++) componentdata[i] = (float) luaL_optnumber(L, startidx + i, 0); return sizeof(float) * components; } -static inline char *writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data) +char *luax_writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data) { switch (type) { @@ -70,24 +72,34 @@ static inline char *writeAttributeData(lua_State *L, int startidx, Mesh::DataTyp } } -template -static inline size_t readData(lua_State *L, int components, const char *data) +static inline size_t readByteData(lua_State *L, int components, const char *data) { - const T *componentdata = (const T *) data; + const uint8 *componentdata = (const uint8 *) data; + for (int i = 0; i < components; i++) lua_pushnumber(L, (lua_Number) componentdata[i]); - return sizeof(T) * components; + return sizeof(uint8) * components; } -static inline const char *readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data) +static inline size_t readFloatData(lua_State *L, int components, const char *data) +{ + const float *componentdata = (const float *) data; + + for (int i = 0; i < components; i++) + lua_pushnumber(L, componentdata[i]); + + return sizeof(float) * components; +} + +const char *luax_readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data) { switch (type) { case Mesh::DATA_BYTE: - return data + readData(L, components, data); + return data + readByteData(L, components, data); case Mesh::DATA_FLOAT: - return data + readData(L, components, data); + return data + readFloatData(L, components, data); default: return data; } @@ -125,7 +137,7 @@ int w_Mesh_setVertices(lua_State *L) for (const Mesh::AttribFormat &format : vertexformat) { // Fetch the values from Lua and store them in data buffer. - data = writeAttributeData(L, idx, format.type, format.components, data); + data = luax_writeAttributeData(L, idx, format.type, format.components, data); idx += format.components; } @@ -159,7 +171,7 @@ int w_Mesh_setVertex(lua_State *L) lua_rawgeti(L, 3, i); // Fetch the values from Lua and store them in data buffer. - writtendata = writeAttributeData(L, -format.components, format.type, format.components, writtendata); + writtendata = luax_writeAttributeData(L, -format.components, format.type, format.components, writtendata); idx += format.components; lua_pop(L, format.components); @@ -170,7 +182,7 @@ int w_Mesh_setVertex(lua_State *L) for (const Mesh::AttribFormat &format : vertexformat) { // Fetch the values from Lua and store them in data buffer. - writtendata = writeAttributeData(L, idx, format.type, format.components, writtendata); + writtendata = luax_writeAttributeData(L, idx, format.type, format.components, writtendata); idx += format.components; } } @@ -195,7 +207,7 @@ int w_Mesh_getVertex(lua_State *L) for (const Mesh::AttribFormat &format : vertexformat) { - readdata = readAttributeData(L, format.type, format.components, readdata); + readdata = luax_readAttributeData(L, format.type, format.components, readdata); n += format.components; } @@ -216,7 +228,7 @@ int w_Mesh_setVertexAttribute(lua_State *L) char data[sizeof(float) * 4]; // Fetch the values from Lua and store them in the data buffer. - writeAttributeData(L, 4, type, components, data); + luax_writeAttributeData(L, 4, type, components, data); luax_catchexcept(L, [&](){ t->setVertexAttribute(vertindex, attribindex, data, sizeof(float) * 4); }); return 0; @@ -237,7 +249,7 @@ int w_Mesh_getVertexAttribute(lua_State *L) luax_catchexcept(L, [&](){ t->getVertexAttribute(vertindex, attribindex, data, sizeof(float) * 4); }); - readAttributeData(L, type, components, data); + luax_readAttributeData(L, type, components, data); return components; } diff --git a/jni/love/src/modules/graphics/opengl/wrap_Mesh.h b/jni/love/src/modules/graphics/opengl/wrap_Mesh.h index 5ba254ca..fe8334a8 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Mesh.h +++ b/jni/love/src/modules/graphics/opengl/wrap_Mesh.h @@ -32,6 +32,9 @@ namespace graphics namespace opengl { +char *luax_writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data); +const char *luax_readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data); + Mesh *luax_checkmesh(lua_State *L, int idx); int w_Mesh_setVertices(lua_State *L); int w_Mesh_setVertex(lua_State *L); diff --git a/jni/love/src/modules/graphics/opengl/wrap_ParticleSystem.cpp b/jni/love/src/modules/graphics/opengl/wrap_ParticleSystem.cpp index 399db4e0..8c547b77 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_ParticleSystem.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_ParticleSystem.cpp @@ -499,7 +499,7 @@ int w_ParticleSystem_setColors(lua_State *L) if (nColors > 8) return luaL_error(L, "At most eight (8) colors may be used."); - std::vector colors(nColors); + std::vector colors(nColors); for (int i = 0; i < nColors; i++) { @@ -512,15 +512,13 @@ int w_ParticleSystem_setColors(lua_State *L) // push args[i+2][j+1] onto the stack lua_rawgeti(L, i + 2, j + 1); - unsigned char r = (unsigned char) luaL_checkinteger(L, -4); - unsigned char g = (unsigned char) luaL_checkinteger(L, -3); - unsigned char b = (unsigned char) luaL_checkinteger(L, -2); - unsigned char a = (unsigned char) luaL_optinteger(L, -1, 255); + colors[i].r = (float) luaL_checknumber(L, -4); + colors[i].g = (float) luaL_checknumber(L, -3); + colors[i].b = (float) luaL_checknumber(L, -2); + colors[i].a = (float) luaL_optnumber(L, -1, 255); // pop the color components from the stack lua_pop(L, 4); - - colors[i] = Color(r, g, b, a); } t->setColor(colors); @@ -536,27 +534,17 @@ int w_ParticleSystem_setColors(lua_State *L) if (nColors > 8) return luaL_error(L, "At most eight (8) colors may be used."); - if (nColors == 1) + std::vector colors(nColors); + + for (int i = 0; i < nColors; ++i) { - unsigned char r = (unsigned char) luaL_checkinteger(L, 2); - unsigned char g = (unsigned char) luaL_checkinteger(L, 3); - unsigned char b = (unsigned char) luaL_checkinteger(L, 4); - unsigned char a = (unsigned char) luaL_optinteger(L, 5, 255); - t->setColor(Color(r,g,b,a)); - } - else - { - std::vector colors(nColors); - for (int i = 0; i < nColors; ++i) - { - unsigned char r = (unsigned char) luaL_checkinteger(L, 1 + i*4 + 1); - unsigned char g = (unsigned char) luaL_checkinteger(L, 1 + i*4 + 2); - unsigned char b = (unsigned char) luaL_checkinteger(L, 1 + i*4 + 3); - unsigned char a = (unsigned char) luaL_checkinteger(L, 1 + i*4 + 4); - colors[i] = Color(r,g,b,a); - } - t->setColor(colors); + colors[i].r = (float) luaL_checknumber(L, 1 + i*4 + 1); + colors[i].g = (float) luaL_checknumber(L, 1 + i*4 + 2); + colors[i].b = (float) luaL_checknumber(L, 1 + i*4 + 3); + colors[i].a = (float) luaL_checknumber(L, 1 + i*4 + 4); } + + t->setColor(colors); } return 0; @@ -566,19 +554,19 @@ int w_ParticleSystem_getColors(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); - const std::vector &colors =t->getColor(); + const std::vector &colors =t->getColor(); for (size_t i = 0; i < colors.size(); i++) { lua_createtable(L, 4, 0); - lua_pushinteger(L, colors[i].r); + lua_pushnumber(L, colors[i].r); lua_rawseti(L, -2, 1); - lua_pushinteger(L, colors[i].g); + lua_pushnumber(L, colors[i].g); lua_rawseti(L, -2, 2); - lua_pushinteger(L, colors[i].b); + lua_pushnumber(L, colors[i].b); lua_rawseti(L, -2, 3); - lua_pushinteger(L, colors[i].a); + lua_pushnumber(L, colors[i].a); lua_rawseti(L, -2, 4); } diff --git a/jni/love/src/modules/graphics/opengl/wrap_Shader.cpp b/jni/love/src/modules/graphics/opengl/wrap_Shader.cpp index 562ac8f6..cbd8cfdf 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Shader.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_Shader.cpp @@ -20,8 +20,11 @@ #include "wrap_Shader.h" #include "graphics/wrap_Texture.h" +#include "math/MathModule.h" + #include #include +#include namespace love { @@ -148,7 +151,7 @@ int w_Shader_sendInt(lua_State *L) return 0; } -int w_Shader_sendFloat(lua_State *L) +static int w__Shader_sendFloat(lua_State *L, bool colors) { Shader *shader = luax_checkshader(L, 1); const char *name = luaL_checkstring(L, 2); @@ -157,7 +160,7 @@ int w_Shader_sendFloat(lua_State *L) if (count < 1) return luaL_error(L, "No variable to send."); - float *values = 0; + float *values = nullptr; size_t dimension = 1; if (lua_isnumber(L, 3) || lua_isboolean(L, 3)) @@ -170,6 +173,24 @@ int w_Shader_sendFloat(lua_State *L) if (!values) return luaL_error(L, "Error in arguments."); + if (colors) + { + bool gammacorrect = love::graphics::isGammaCorrect(); + const auto &m = love::math::Math::instance; + + for (int i = 0; i < count; i++) + { + for (int j = 0; j < (int) dimension; j++) + { + // the fourth component (alpha) is always already linear, if it exists. + if (gammacorrect && i < 4) + values[i * dimension + j] = m.gammaToLinear(values[i * dimension + j] / 255.0f); + else + values[i * dimension + j] /= 255.0f; + } + } + } + bool should_error = false; try { @@ -189,6 +210,16 @@ int w_Shader_sendFloat(lua_State *L) return 0; } +int w_Shader_sendFloat(lua_State *L) +{ + return w__Shader_sendFloat(L, false); +} + +int w_Shader_sendColor(lua_State *L) +{ + return w__Shader_sendFloat(L, true); +} + int w_Shader_sendMatrix(lua_State *L) { int count = lua_gettop(L) - 2; @@ -372,6 +403,7 @@ static const luaL_Reg functions[] = { "sendInt", w_Shader_sendInt }, { "sendBoolean", w_Shader_sendInt }, { "sendFloat", w_Shader_sendFloat }, + { "sendColor", w_Shader_sendColor }, { "sendMatrix", w_Shader_sendMatrix }, { "sendTexture", w_Shader_sendTexture }, { "send", w_Shader_send }, diff --git a/jni/love/src/modules/graphics/opengl/wrap_Shader.h b/jni/love/src/modules/graphics/opengl/wrap_Shader.h index 7b31c3d0..8cc77383 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Shader.h +++ b/jni/love/src/modules/graphics/opengl/wrap_Shader.h @@ -22,6 +22,7 @@ #define LOVE_GRAPHICS_OPENGL_WRAP_PROGRAM_H #include "common/runtime.h" +#include "common/config.h" #include "Shader.h" namespace love @@ -35,6 +36,7 @@ Shader *luax_checkshader(lua_State *L, int idx); int w_Shader_getWarnings(lua_State *L); int w_Shader_sendInt(lua_State *L); int w_Shader_sendFloat(lua_State *L); +int w_Shader_sendColor(lua_State *L); int w_Shader_sendMatrix(lua_State *L); int w_Shader_sendTexture(lua_State *L); int w_Shader_send(lua_State *L); diff --git a/jni/love/src/modules/graphics/opengl/wrap_SpriteBatch.cpp b/jni/love/src/modules/graphics/opengl/wrap_SpriteBatch.cpp index c550fd6f..52f76d3c 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_SpriteBatch.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_SpriteBatch.cpp @@ -144,19 +144,19 @@ int w_SpriteBatch_setColor(lua_State *L) for (int i = 1; i <= 4; i++) lua_rawgeti(L, 2, i); - c.r = (unsigned char) luaL_checkinteger(L, -4); - c.g = (unsigned char) luaL_checkinteger(L, -3); - c.b = (unsigned char) luaL_checkinteger(L, -2); - c.a = (unsigned char) luaL_optinteger(L, -1, 255); + c.r = (unsigned char) luaL_checknumber(L, -4); + c.g = (unsigned char) luaL_checknumber(L, -3); + c.b = (unsigned char) luaL_checknumber(L, -2); + c.a = (unsigned char) luaL_optnumber(L, -1, 255); lua_pop(L, 4); } else { - c.r = (unsigned char)luaL_checkinteger(L, 2); - c.g = (unsigned char)luaL_checkinteger(L, 3); - c.b = (unsigned char)luaL_checkinteger(L, 4); - c.a = (unsigned char)luaL_optinteger(L, 5, 255); + c.r = (unsigned char) luaL_checknumber(L, 2); + c.g = (unsigned char) luaL_checknumber(L, 3); + c.b = (unsigned char) luaL_checknumber(L, 4); + c.a = (unsigned char) luaL_optnumber(L, 5, 255); } t->setColor(c); @@ -169,14 +169,14 @@ int w_SpriteBatch_getColor(lua_State *L) SpriteBatch *t = luax_checkspritebatch(L, 1); const Color *color = t->getColor(); - // getColor returns NULL if no color is set. + // getColor returns null if no color is set. if (!color) return 0; - lua_pushinteger(L, (lua_Integer) color->r); - lua_pushinteger(L, (lua_Integer) color->g); - lua_pushinteger(L, (lua_Integer) color->b); - lua_pushinteger(L, (lua_Integer) color->a); + lua_pushnumber(L, color->r); + lua_pushnumber(L, color->g); + lua_pushnumber(L, color->b); + lua_pushnumber(L, color->a); return 4; } diff --git a/jni/love/src/modules/image/magpie/KTXHandler.cpp b/jni/love/src/modules/image/magpie/KTXHandler.cpp index 1530e7dd..4b3f095e 100644 --- a/jni/love/src/modules/image/magpie/KTXHandler.cpp +++ b/jni/love/src/modules/image/magpie/KTXHandler.cpp @@ -170,7 +170,7 @@ uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector 1) diff --git a/jni/love/src/modules/love/love.cpp b/jni/love/src/modules/love/love.cpp index 86345976..25f21d66 100644 --- a/jni/love/src/modules/love/love.cpp +++ b/jni/love/src/modules/love/love.cpp @@ -55,6 +55,11 @@ # include "libraries/luautf8/lutf8lib.h" #endif +// For love::graphics::setGammaCorrect. +#ifdef LOVE_ENABLE_GRAPHICS +# include "graphics/Graphics.h" +#endif + // Scripts #include "scripts/nogame.lua.h" #include "scripts/boot.lua.h" @@ -238,6 +243,14 @@ static int w_love_isVersionCompatible(lua_State *L) return 1; } +static int w__setGammaCorrect(lua_State *L) +{ +#ifdef LOVE_ENABLE_GRAPHICS + love::graphics::setGammaCorrect((bool) lua_toboolean(L, 1)); +#endif + return 0; +} + int luaopen_love(lua_State *L) { love::luax_insistpinnedthread(L); @@ -268,6 +281,9 @@ int luaopen_love(lua_State *L) lua_setfield(L, -2, "_setAccelerometerAsJoystick"); #endif + lua_pushcfunction(L, w__setGammaCorrect); + lua_setfield(L, -2, "_setGammaCorrect"); + lua_newtable(L); for (int i = 0; love::VERSION_COMPATIBILITY[i] != nullptr; i++) diff --git a/jni/love/src/modules/math/Compressor.cpp b/jni/love/src/modules/math/Compressor.cpp index 48827c94..2a15fba6 100644 --- a/jni/love/src/modules/math/Compressor.cpp +++ b/jni/love/src/modules/math/Compressor.cpp @@ -63,7 +63,7 @@ public: // Store the size of the uncompressed data as a header. #ifdef LOVE_BIG_ENDIAN // Make sure it's little-endian for storage. - *(uint32 *) compressedbytes = swap32((uint32) dataSize); + *(uint32 *) compressedbytes = swapuint32((uint32) dataSize); #else *(uint32 *) compressedbytes = (uint32) dataSize; #endif @@ -110,7 +110,7 @@ public: // Extract the original uncompressed size (stored in our custom header.) #ifdef LOVE_BIG_ENDIAN // Convert from stored little-endian to big-endian. - uint32 rawsize = swap32(*(uint32 *) data); + uint32 rawsize = swapuint32(*(uint32 *) data); #else uint32 rawsize = *(uint32 *) data; #endif diff --git a/jni/love/src/modules/math/MathModule.cpp b/jni/love/src/modules/math/MathModule.cpp index 3ad86d67..71c3459d 100644 --- a/jni/love/src/modules/math/MathModule.cpp +++ b/jni/love/src/modules/math/MathModule.cpp @@ -208,11 +208,7 @@ bool Math::isConvex(const std::vector &polygon) **/ float Math::gammaToLinear(float c) const { - if (c > 1.0f) - return 1.0f; - else if (c < 0.0f) - return 0.0f; - else if (c <= 0.04045) + if (c <= 0.04045f) return c / 12.92f; else return powf((c + 0.055f) / 1.055f, 2.4f); @@ -223,14 +219,10 @@ float Math::gammaToLinear(float c) const **/ float Math::linearToGamma(float c) const { - if (c > 1.0f) - return 1.0f; - else if (c < 0.0f) - return 0.0f; - else if (c < 0.0031308f) + if (c < 0.0031308f) return c * 12.92f; else - return 1.055f * powf(c, 0.41666f) - 0.055f; + return 1.055f * powf(c, 1.0f / 2.4f) - 0.055f; } CompressedData *Math::compress(Compressor::Format format, love::Data *rawdata, int level) diff --git a/jni/love/src/modules/window/Window.cpp b/jni/love/src/modules/window/Window.cpp index 0131b3c2..e2a82363 100644 --- a/jni/love/src/modules/window/Window.cpp +++ b/jni/love/src/modules/window/Window.cpp @@ -77,7 +77,6 @@ StringMap::Entry Window::settingEntri {"centered", SETTING_CENTERED}, {"display", SETTING_DISPLAY}, {"highdpi", SETTING_HIGHDPI}, - {"srgb", SETTING_SRGB}, {"refreshrate", SETTING_REFRESHRATE}, {"x", SETTING_X}, {"y", SETTING_Y}, diff --git a/jni/love/src/modules/window/Window.h b/jni/love/src/modules/window/Window.h index 8c70b153..e7049614 100644 --- a/jni/love/src/modules/window/Window.h +++ b/jni/love/src/modules/window/Window.h @@ -57,7 +57,6 @@ public: SETTING_CENTERED, SETTING_DISPLAY, SETTING_HIGHDPI, - SETTING_SRGB, SETTING_REFRESHRATE, SETTING_X, SETTING_Y, @@ -210,7 +209,6 @@ struct WindowSettings bool centered = true; int display = 0; bool highdpi = false; - bool sRGB = false; double refreshrate = 0.0; bool useposition = false; int x = 0; diff --git a/jni/love/src/modules/window/sdl/Window.cpp b/jni/love/src/modules/window/sdl/Window.cpp index cd04baa3..83e04c57 100644 --- a/jni/love/src/modules/window/sdl/Window.cpp +++ b/jni/love/src/modules/window/sdl/Window.cpp @@ -62,9 +62,14 @@ Window::Window() , context(nullptr) , displayedWindowError(false) , displayedContextError(false) + , hasSDL203orEarlier(false) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) throw love::Exception("Could not initialize SDL video subsystem (%s)", SDL_GetError()); + + SDL_version version = {}; + SDL_GetVersion(&version); + hasSDL203orEarlier = (version.major == 2 && version.minor == 0 && version.patch <= 3); } Window::~Window() @@ -88,12 +93,17 @@ void Window::setGLFramebufferAttributes(int msaa, bool sRGB) SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (msaa > 0) ? 1 : 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (msaa > 0) ? msaa : 0); - // SDL or GLX may have bugs with this: https://bugzilla.libsdl.org/show_bug.cgi?id=2897 - // It's fine to leave the attribute disabled on desktops though, because in - // practice the framebuffer will be sRGB-capable even if it's not requested. -#if !defined(LOVE_LINUX) SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, sRGB ? 1 : 0); -#endif + + const char *driver = SDL_GetCurrentVideoDriver(); + if (driver && strstr(driver, "x11") == driver) + { + // Always disable the sRGB flag when GLX is used with older SDL versions, + // because of this bug: https://bugzilla.libsdl.org/show_bug.cgi?id=2897 + // In practice GLX will always give an sRGB-capable framebuffer anyway. + if (hasSDL203orEarlier) + SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 0); + } #if defined(LOVE_WINDOWS) // Avoid the Microsoft OpenGL 1.1 software renderer on Windows. Apparently @@ -158,7 +168,7 @@ bool Window::checkGLVersion(const ContextAttribs &attribs) return true; } -bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, int msaa, bool sRGB) +bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, int msaa) { bool preferGLES = false; @@ -175,6 +185,14 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla if (curdriver && strstr(curdriver, glesdriver) == curdriver) { preferGLES = true; + + // Prior to SDL 2.0.4, backends that use OpenGL ES didn't properly + // ask for a sRGB framebuffer when requested by SDL_GL_SetAttribute. + // FIXME: This doesn't account for windowing backends that sometimes + // use EGL, e.g. the X11 and windows SDL backends. + if (hasSDL203orEarlier) + graphics::setGammaCorrect(false); + break; } } @@ -196,11 +214,8 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla {2, 0, true, debug}, // OpenGL ES 2. }; - SDL_version sdlversion = {}; - SDL_GetVersion(&sdlversion); - // OpenGL ES 3+ contexts are only properly supported in SDL 2.0.4+. - if (sdlversion.major == 2 && sdlversion.minor == 0 && sdlversion.patch <= 3) + if (hasSDL203orEarlier) attribslist.erase(attribslist.begin() + 1); // Move OpenGL ES to the front of the list if we should prefer GLES. @@ -229,7 +244,7 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla } int curMSAA = msaa; - bool curSRGB = sRGB; + bool curSRGB = love::graphics::isGammaCorrect(); setGLFramebufferAttributes(curMSAA, curSRGB); setGLContextAttributes(attribs); @@ -312,7 +327,10 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla } if (context) + { + love::graphics::setGammaCorrect(curSRGB); break; + } } if (!context || !window) @@ -437,7 +455,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) close(); - if (!createWindowAndContext(x, y, width, height, sdlflags, f.msaa, f.sRGB)) + if (!createWindowAndContext(x, y, width, height, sdlflags, f.msaa)) return false; // Make sure the window keeps any previously set icon. @@ -460,7 +478,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) auto gfx = Module::getInstance(Module::M_GRAPHICS); if (gfx != nullptr) - gfx->setMode(curMode.pixelwidth, curMode.pixelheight, curMode.settings.sRGB); + gfx->setMode(curMode.pixelwidth, curMode.pixelheight); #ifdef LOVE_ANDROID love::android::setImmersive(f.fullscreen); @@ -538,8 +556,6 @@ void Window::updateSettings(const WindowSettings &newsettings) else SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); - curMode.settings.sRGB = newsettings.sRGB; - // Verify MSAA setting. int buffers = 0; int samples = 0; diff --git a/jni/love/src/modules/window/sdl/Window.h b/jni/love/src/modules/window/sdl/Window.h index d985f7b7..29b34020 100644 --- a/jni/love/src/modules/window/sdl/Window.h +++ b/jni/love/src/modules/window/sdl/Window.h @@ -119,7 +119,7 @@ private: void setGLFramebufferAttributes(int msaa, bool sRGB); void setGLContextAttributes(const ContextAttribs &attribs); bool checkGLVersion(const ContextAttribs &attribs); - bool createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, int msaa, bool sRGB); + bool createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, int msaa); // Update the saved window settings based on the window's actual state. void updateSettings(const WindowSettings &newsettings); @@ -149,6 +149,8 @@ private: bool displayedWindowError; bool displayedContextError; + bool hasSDL203orEarlier; + }; // Window } // sdl diff --git a/jni/love/src/modules/window/wrap_Window.cpp b/jni/love/src/modules/window/wrap_Window.cpp index b32c0196..e805d29e 100644 --- a/jni/love/src/modules/window/wrap_Window.cpp +++ b/jni/love/src/modules/window/wrap_Window.cpp @@ -107,7 +107,6 @@ int w_setMode(lua_State *L) settings.centered = luax_boolflag(L, 3, settingName(Window::SETTING_CENTERED), true); settings.display = luax_intflag(L, 3, settingName(Window::SETTING_DISPLAY), 1) - 1; settings.highdpi = luax_boolflag(L, 3, settingName(Window::SETTING_HIGHDPI), false); - settings.sRGB = luax_boolflag(L, 3, settingName(Window::SETTING_SRGB), false); lua_getfield(L, 3, settingName(Window::SETTING_X)); lua_getfield(L, 3, settingName(Window::SETTING_Y)); @@ -175,9 +174,6 @@ int w_getMode(lua_State *L) luax_pushboolean(L, settings.highdpi); lua_setfield(L, -2, settingName(Window::SETTING_HIGHDPI)); - luax_pushboolean(L, settings.sRGB); - lua_setfield(L, -2, settingName(Window::SETTING_SRGB)); - lua_pushnumber(L, settings.refreshrate); lua_setfield(L, -2, settingName(Window::SETTING_REFRESHRATE)); diff --git a/jni/love/src/scripts/boot.lua b/jni/love/src/scripts/boot.lua index 164a334d..61d3c245 100644 --- a/jni/love/src/scripts/boot.lua +++ b/jni/love/src/scripts/boot.lua @@ -351,7 +351,6 @@ function love.init() resizable = false, centered = true, highdpi = false, - srgb = false, }, modules = { event = true, @@ -375,6 +374,7 @@ function love.init() identity = false, appendidentity = false, accelerometerjoystick = true, -- Only relevant for Android / iOS. + gammacorrect = false, } -- Console hack, part 1. @@ -408,6 +408,10 @@ function love.init() love._setAccelerometerAsJoystick(c.accelerometerjoystick) end + if love._setGammaCorrect then + love._setGammaCorrect(c.gammacorrect) + end + -- Gets desired modules. for k,v in ipairs{ "thread", @@ -441,8 +445,8 @@ function love.init() if not love.isVersionCompatible(c.version) then local major, minor, revision = c.version:match("^(%d+)%.(%d+)%.(%d+)$") if (not major or not minor or not revision) or (major ~= love._version_major and minor ~= love._version_minor) then - local msg = "This game was made for a different version of LOVE.\n".. - "It may not be not be compatible with the running version ("..love._version..")." + local msg = ("This game indicates it was made for version '%s' of LOVE.\n".. + "It may not be compatible with the running version (%s)."):format(c.version, love._version) print(msg) @@ -471,13 +475,12 @@ function love.init() centered = c.window.centered, display = c.window.display, highdpi = c.window.highdpi, - srgb = c.window.srgb, x = c.window.x, y = c.window.y, }), "Could not set window mode") love.window.setTitle(c.window.title or c.title) if c.window.icon then - assert(love.image, "If an icon is set in love.conf, love.image has to be loaded!") + assert(love.image, "If an icon is set in love.conf, love.image must be loaded!") love.window.setIcon(love.image.newImageData(c.window.icon)) end end @@ -589,13 +592,7 @@ function love.errhand(msg) love.graphics.reset() local font = love.graphics.setNewFont(math.floor(love.window.toPixels(14))) - local sRGB = select(3, love.window.getMode()).srgb - if sRGB and love.math then - love.graphics.setBackgroundColor(love.math.gammaToLinear(89, 157, 220)) - else - love.graphics.setBackgroundColor(89, 157, 220) - end - + love.graphics.setBackgroundColor(89, 157, 220) love.graphics.setColor(255, 255, 255, 255) local trace = debug.traceback() diff --git a/jni/love/src/scripts/boot.lua.h b/jni/love/src/scripts/boot.lua.h index 28a238e8..956b67d5 100644 --- a/jni/love/src/scripts/boot.lua.h +++ b/jni/love/src/scripts/boot.lua.h @@ -654,7 +654,6 @@ const unsigned char boot_lua[] = 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x73, 0x72, 0x67, 0x62, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x2c, 0x0a, 0x09, 0x09, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, @@ -688,6 +687,8 @@ const unsigned char boot_lua[] = 0x73, 0x74, 0x69, 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x2d, 0x2d, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x72, 0x65, 0x6c, 0x65, 0x76, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x2f, 0x20, 0x69, 0x4f, 0x53, 0x2e, 0x0a, + 0x09, 0x09, 0x67, 0x61, 0x6d, 0x6d, 0x61, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, + 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x68, 0x61, 0x63, 0x6b, 0x2c, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x31, 0x2e, 0x0a, @@ -757,6 +758,12 @@ const unsigned char boot_lua[] = 0x2e, 0x61, 0x63, 0x63, 0x65, 0x6c, 0x65, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x47, 0x61, 0x6d, 0x6d, 0x61, + 0x43, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x73, 0x65, 0x74, 0x47, 0x61, 0x6d, 0x6d, 0x61, 0x43, 0x6f, + 0x72, 0x72, 0x65, 0x63, 0x74, 0x28, 0x63, 0x2e, 0x67, 0x61, 0x6d, 0x6d, 0x61, 0x63, 0x6f, 0x72, 0x72, 0x65, + 0x63, 0x74, 0x29, 0x0a, + 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x47, 0x65, 0x74, 0x73, 0x20, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, @@ -808,15 +815,17 @@ const unsigned char boot_lua[] = 0x5f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x20, 0x7e, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x73, 0x67, 0x20, 0x3d, 0x20, 0x22, 0x54, 0x68, - 0x69, 0x73, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x66, - 0x6f, 0x72, 0x20, 0x61, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x2e, 0x5c, 0x6e, 0x22, 0x2e, 0x2e, 0x0a, - 0x09, 0x09, 0x09, 0x22, 0x49, 0x74, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, - 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x20, - 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x22, 0x2e, 0x2e, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x2e, 0x22, 0x29, 0x2e, 0x22, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x73, 0x67, 0x20, 0x3d, 0x20, 0x28, 0x22, 0x54, + 0x68, 0x69, 0x73, 0x20, 0x67, 0x61, 0x6d, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x27, 0x25, 0x73, 0x27, 0x20, 0x6f, 0x66, 0x20, 0x4c, 0x4f, 0x56, + 0x45, 0x2e, 0x5c, 0x6e, 0x22, 0x2e, 0x2e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x22, 0x49, 0x74, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x25, 0x73, 0x29, 0x2e, 0x22, 0x29, 0x3a, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x74, 0x28, 0x63, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x6c, 0x6f, + 0x76, 0x65, 0x2e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x28, 0x6d, 0x73, 0x67, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, @@ -864,8 +873,6 @@ const unsigned char boot_lua[] = 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x73, 0x72, 0x67, 0x62, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, - 0x2e, 0x73, 0x72, 0x67, 0x62, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x78, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x78, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x79, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x79, 0x2c, 0x0a, 0x09, 0x09, 0x7d, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, @@ -878,8 +885,8 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x09, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x22, 0x49, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x69, 0x63, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x73, 0x65, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x2c, - 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x68, 0x61, 0x73, 0x20, 0x74, 0x6f, - 0x20, 0x62, 0x65, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x21, 0x22, 0x29, 0x0a, + 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, + 0x65, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x21, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x49, 0x63, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x6e, 0x65, 0x77, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x28, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, @@ -1073,21 +1080,9 @@ const unsigned char boot_lua[] = 0x6e, 0x74, 0x28, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x74, 0x6f, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x73, 0x28, 0x31, 0x34, 0x29, 0x29, 0x29, 0x0a, - 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x52, 0x47, 0x42, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x28, 0x33, 0x2c, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, - 0x67, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x29, 0x29, 0x2e, 0x73, 0x72, 0x67, 0x62, 0x0a, - 0x09, 0x69, 0x66, 0x20, 0x73, 0x52, 0x47, 0x42, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, - 0x6d, 0x61, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, - 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x67, 0x61, 0x6d, 0x6d, 0x61, 0x54, 0x6f, 0x4c, 0x69, - 0x6e, 0x65, 0x61, 0x72, 0x28, 0x38, 0x39, 0x2c, 0x20, 0x31, 0x35, 0x37, 0x2c, 0x20, 0x32, 0x32, 0x30, 0x29, - 0x29, 0x0a, - 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, - 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x38, - 0x39, 0x2c, 0x20, 0x31, 0x35, 0x37, 0x2c, 0x20, 0x32, 0x32, 0x30, 0x29, 0x0a, - 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, + 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x38, 0x39, + 0x2c, 0x20, 0x31, 0x35, 0x37, 0x2c, 0x20, 0x32, 0x32, 0x30, 0x29, 0x0a, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x2c, 0x20, 0x32, 0x35, 0x35, 0x29, 0x0a, diff --git a/jni/love/src/scripts/nogame.lua b/jni/love/src/scripts/nogame.lua index 7b6b8e68..0e9f56ef 100644 --- a/jni/love/src/scripts/nogame.lua +++ b/jni/love/src/scripts/nogame.lua @@ -994,6 +994,7 @@ function love.nogame() function love.conf(t) t.title = "L\195\150VE " .. love._version .. " (" .. love._version_codename .. ")" + t.gammacorrect = true t.modules.audio = false t.modules.sound = false t.modules.physics = false diff --git a/jni/love/src/scripts/nogame.lua.h b/jni/love/src/scripts/nogame.lua.h index 92ef83e7..23ee81bb 100644 --- a/jni/love/src/scripts/nogame.lua.h +++ b/jni/love/src/scripts/nogame.lua.h @@ -4313,6 +4313,8 @@ const unsigned char nogame_lua[] = 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x20, 0x28, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x29, 0x22, 0x0a, + 0x09, 0x09, 0x74, 0x2e, 0x67, 0x61, 0x6d, 0x6d, 0x61, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x20, 0x3d, + 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x09, 0x09, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x09, 0x09, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x6f, 0x75, 0x6e, 0x64, 0x20,