mirror of
https://github.com/love2d/love-android.git
synced 2026-08-12 08:31:04 +02:00
Updated to latest love-android code (b615972822cb)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
**/
|
||||
|
||||
@@ -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<char*>(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;
|
||||
}
|
||||
|
||||
@@ -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) |
|
||||
|
||||
+7
-13
@@ -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 <string>
|
||||
|
||||
#include "modules/love/love.h"
|
||||
#include <SDL.h>
|
||||
|
||||
#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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
|
||||
{
|
||||
{ "multicanvas", SUPPORT_MULTI_CANVAS },
|
||||
{ "multicanvasformats", SUPPORT_MULTI_CANVAS_FORMATS },
|
||||
{ "srgb", SUPPORT_SRGB },
|
||||
};
|
||||
|
||||
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
// LOVE
|
||||
#include "common/Module.h"
|
||||
#include "common/StringMap.h"
|
||||
#include "Color.h"
|
||||
|
||||
// C++
|
||||
#include <string>
|
||||
@@ -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
|
||||
|
||||
@@ -398,7 +398,7 @@ void Canvas::startGrab(const std::vector<Canvas *> &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<Canvas *> &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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "Graphics.h"
|
||||
#include "font/Font.h"
|
||||
#include "Polyline.h"
|
||||
#include "math/MathModule.h"
|
||||
|
||||
// C++
|
||||
#include <vector>
|
||||
@@ -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<love::window::Window>(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<Color> &colors)
|
||||
void Graphics::clear(const std::vector<Colorf> &colors)
|
||||
{
|
||||
if (colors.size() == 0)
|
||||
return;
|
||||
@@ -447,7 +452,16 @@ void Graphics::clear(const std::vector<Color> &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
|
||||
|
||||
@@ -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<Color> &colors);
|
||||
void clear(const std::vector<Colorf> &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> font;
|
||||
StrongRef<Shader> shader;
|
||||
|
||||
std::vector<StrongRef<Canvas>> 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);
|
||||
|
||||
@@ -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<love::image::ImageData *> &imagedata, const Flags
|
||||
, mipmapSharpness(defaultMipmapSharpness)
|
||||
, compressed(false)
|
||||
, flags(flags)
|
||||
, sRGB(false)
|
||||
, usingDefaultTexture(false)
|
||||
, textureMemorySize(0)
|
||||
{
|
||||
@@ -117,18 +119,22 @@ Image::Image(const std::vector<love::image::CompressedImageData *> &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<Image::FlagType, Image::FLAG_TYPE_MAX_ENUM>::Entry Image::flagNameEntries[] =
|
||||
{
|
||||
{"mipmaps", Image::FLAG_TYPE_MIPMAPS},
|
||||
{"srgb", Image::FLAG_TYPE_SRGB},
|
||||
{"linear", Image::FLAG_TYPE_LINEAR},
|
||||
};
|
||||
|
||||
StringMap<Image::FlagType, Image::FLAG_TYPE_MAX_ENUM> Image::flagNames(Image::flagNameEntries, sizeof(Image::flagNameEntries));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -63,8 +63,6 @@ Mesh::Mesh(const std::vector<AttribFormat> &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<AttribFormat> &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<AttribFormat> &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<AttribFormat> &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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Colorf> &newColors)
|
||||
{
|
||||
colors.resize(1);
|
||||
colors[0] = colorToFloat(color);
|
||||
}
|
||||
colors = newColors;
|
||||
|
||||
void ParticleSystem::setColor(const std::vector<Color> &newColors)
|
||||
{
|
||||
colors.resize(newColors.size());
|
||||
for (size_t i = 0; i < newColors.size(); ++i)
|
||||
colors[i] = colorToFloat(newColors[i]);
|
||||
}
|
||||
|
||||
std::vector<Color> ParticleSystem::getColor() const
|
||||
{
|
||||
// The particle system stores colors as floats...
|
||||
std::vector<Color> 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<Colorf> ParticleSystem::getColor() const
|
||||
{
|
||||
// The particle system stores colors in the range of [0, 1]...
|
||||
std::vector<Colorf> 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;
|
||||
|
||||
|
||||
@@ -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<Color> &newColors);
|
||||
void setColor(const std::vector<Colorf> &newColors);
|
||||
|
||||
/**
|
||||
* Returns the color of the particles.
|
||||
**/
|
||||
std::vector<Color> getColor() const;
|
||||
std::vector<Colorf> 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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -74,7 +74,7 @@ private:
|
||||
Font::AlignMode align;
|
||||
bool use_matrix;
|
||||
bool append_vertices;
|
||||
Matrix4 matrix;
|
||||
Matrix3 matrix;
|
||||
};
|
||||
|
||||
void uploadVertices(const std::vector<Font::GlyphVertex> &vertices, size_t vertoffset);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -54,7 +54,7 @@ int w_reset(lua_State *)
|
||||
|
||||
int w_clear(lua_State *L)
|
||||
{
|
||||
std::vector<Color> colors(1);
|
||||
std::vector<Colorf> 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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 <typename T>
|
||||
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<uint8>(L, components, data);
|
||||
return data + readByteData(L, components, data);
|
||||
case Mesh::DATA_FLOAT:
|
||||
return data + readData<float>(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<Color> colors(nColors);
|
||||
std::vector<Colorf> 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<Colorf> 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<Color> 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<Color> &colors =t->getColor();
|
||||
const std::vector<Colorf> &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);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,11 @@
|
||||
|
||||
#include "wrap_Shader.h"
|
||||
#include "graphics/wrap_Texture.h"
|
||||
#include "math/MathModule.h"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
|
||||
{
|
||||
uint32 *headerArray = (uint32 *) &header.glType;
|
||||
for (int i = 0; i < 12; i++)
|
||||
headerArray[i] = swap32(headerArray[i]);
|
||||
headerArray[i] = swapuint32(headerArray[i]);
|
||||
}
|
||||
|
||||
header.numberOfMipmapLevels = std::max(header.numberOfMipmapLevels, 1u);
|
||||
@@ -203,7 +203,7 @@ uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
|
||||
uint32 mipsize = *(uint32 *) (filebytes + fileoffset);
|
||||
|
||||
if (header.endianness == KTX_ENDIAN_REF_REV)
|
||||
mipsize = swap32(mipsize);
|
||||
mipsize = swapuint32(mipsize);
|
||||
|
||||
fileoffset += sizeof(uint32);
|
||||
|
||||
@@ -235,7 +235,7 @@ uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
|
||||
uint32 mipsize = *(uint32 *) (filebytes + fileoffset);
|
||||
|
||||
if (header.endianness == KTX_ENDIAN_REF_REV)
|
||||
mipsize = swap32(mipsize);
|
||||
mipsize = swapuint32(mipsize);
|
||||
|
||||
fileoffset += sizeof(uint32);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ inline uint16 swap16big(uint16 x)
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
return x;
|
||||
#else
|
||||
return swap16(x);
|
||||
return swapuint16(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ void ConvertPVRHeader(PVRTexHeaderV2 header2, PVRTexHeaderV3 *header3)
|
||||
// All of the struct's members are uint32 values, so we can do this.
|
||||
uint32 *headerArray = (uint32 *) &header2;
|
||||
for (size_t i = 0; i < sizeof(PVRTexHeaderV2) / sizeof(uint32); i++)
|
||||
headerArray[i] = swap32(headerArray[i]);
|
||||
headerArray[i] = swapuint32(headerArray[i]);
|
||||
}
|
||||
|
||||
memset(header3, 0, sizeof(PVRTexHeaderV3));
|
||||
@@ -309,16 +309,16 @@ uint8 *PVRHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
|
||||
if (header3.version == PVRTEX3_IDENT_REV)
|
||||
{
|
||||
header3.version = PVRTEX3_IDENT;
|
||||
header3.flags = swap32(header3.flags);
|
||||
header3.pixelFormat = swap64(header3.pixelFormat);
|
||||
header3.colorSpace = swap32(header3.colorSpace);
|
||||
header3.channelType = swap32(header3.channelType);
|
||||
header3.height = swap32(header3.height);
|
||||
header3.width = swap32(header3.width);
|
||||
header3.depth = swap32(header3.depth);
|
||||
header3.numFaces = swap32(header3.numFaces);
|
||||
header3.numMipmaps = swap32(header3.numMipmaps);
|
||||
header3.metaDataSize = swap32(header3.metaDataSize);
|
||||
header3.flags = swapuint32(header3.flags);
|
||||
header3.pixelFormat = swapuint64(header3.pixelFormat);
|
||||
header3.colorSpace = swapuint32(header3.colorSpace);
|
||||
header3.channelType = swapuint32(header3.channelType);
|
||||
header3.height = swapuint32(header3.height);
|
||||
header3.width = swapuint32(header3.width);
|
||||
header3.depth = swapuint32(header3.depth);
|
||||
header3.numFaces = swapuint32(header3.numFaces);
|
||||
header3.numMipmaps = swapuint32(header3.numMipmaps);
|
||||
header3.metaDataSize = swapuint32(header3.metaDataSize);
|
||||
}
|
||||
|
||||
if (header3.depth > 1)
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -208,11 +208,7 @@ bool Math::isConvex(const std::vector<Vertex> &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)
|
||||
|
||||
@@ -77,7 +77,6 @@ StringMap<Window::Setting, Window::SETTING_MAX_ENUM>::Entry Window::settingEntri
|
||||
{"centered", SETTING_CENTERED},
|
||||
{"display", SETTING_DISPLAY},
|
||||
{"highdpi", SETTING_HIGHDPI},
|
||||
{"srgb", SETTING_SRGB},
|
||||
{"refreshrate", SETTING_REFRESHRATE},
|
||||
{"x", SETTING_X},
|
||||
{"y", SETTING_Y},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<graphics::Graphics>(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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user