Updated to latest love-android code (b615972822cb)

This commit is contained in:
fysx
2015-08-13 17:21:53 +02:00
parent f3dd769e98
commit 9cbddc2f5e
50 changed files with 827 additions and 663 deletions
+24
View File
@@ -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
+21
View File
@@ -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.
**/
+71 -83
View File
@@ -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;
}
+3 -3
View File
@@ -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
View File
@@ -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);
+33 -1
View File
@@ -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));
+35 -2
View File
@@ -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
+38 -100
View File
@@ -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
+26 -30
View File
@@ -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);
+61 -26
View File
@@ -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));
+5 -3
View File
@@ -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;
+9 -28
View File
@@ -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);
+1 -1
View File
@@ -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)
+16
View File
@@ -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++)
+2 -2
View File
@@ -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
+3 -11
View File
@@ -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)
-1
View File
@@ -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},
-2
View File
@@ -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;
+31 -15
View File
@@ -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;
+3 -1
View File
@@ -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));
+9 -12
View File
@@ -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()
+24 -29
View File
@@ -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,
+1
View File
@@ -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
+2
View File
@@ -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,