updated to latest mobile-common branch of Löve

This commit is contained in:
fysx
2014-01-30 08:51:28 +01:00
parent 4c481f9933
commit 33d979caf6
49 changed files with 824 additions and 199 deletions
+3 -3
View File
@@ -27,9 +27,9 @@ namespace love
// Version stuff. // Version stuff.
const int VERSION_MAJOR = 0; const int VERSION_MAJOR = 0;
const int VERSION_MINOR = 9; const int VERSION_MINOR = 9;
const int VERSION_REV = 0; const int VERSION_REV = 1;
const char *VERSION = "0.9.0"; const char *VERSION = "0.9.1";
const char *VERSION_COMPATIBILITY[] = { VERSION, 0 }; const char *VERSION_COMPATIBILITY[] = { VERSION, "0.9.0", 0 };
const char *VERSION_CODENAME = "Baby Inspector"; const char *VERSION_CODENAME = "Baby Inspector";
} // love } // love
+1 -1
View File
@@ -88,7 +88,7 @@ public:
* Play the specified Source. * Play the specified Source.
* @param source The Source to play. * @param source The Source to play.
**/ **/
virtual void play(Source *source) = 0; virtual bool play(Source *source) = 0;
/** /**
* Stops playback on the specified source. * Stops playback on the specified source.
+1 -1
View File
@@ -53,7 +53,7 @@ public:
virtual Source *clone() = 0; virtual Source *clone() = 0;
virtual void play() = 0; virtual bool play() = 0;
virtual void stop() = 0; virtual void stop() = 0;
virtual void pause() = 0; virtual void pause() = 0;
virtual void resume() = 0; virtual void resume() = 0;
+2 -5
View File
@@ -61,12 +61,9 @@ int Audio::getMaxSources() const
return 0; return 0;
} }
void Audio::play(love::audio::Source *) bool Audio::play(love::audio::Source *)
{
}
void Audio::play()
{ {
return false;
} }
void Audio::stop(love::audio::Source *) void Audio::stop(love::audio::Source *)
+1 -2
View File
@@ -48,8 +48,7 @@ public:
love::audio::Source *newSource(love::sound::SoundData *soundData); love::audio::Source *newSource(love::sound::SoundData *soundData);
int getSourceCount() const; int getSourceCount() const;
int getMaxSources() const; int getMaxSources() const;
void play(love::audio::Source *source); bool play(love::audio::Source *source);
void play();
void stop(love::audio::Source *source); void stop(love::audio::Source *source);
void stop(); void stop();
void pause(love::audio::Source *source); void pause(love::audio::Source *source);
+2 -1
View File
@@ -42,8 +42,9 @@ love::audio::Source *Source::clone()
return this; return this;
} }
void Source::play() bool Source::play()
{ {
return false;
} }
void Source::stop() void Source::stop()
+1 -1
View File
@@ -39,7 +39,7 @@ public:
virtual ~Source(); virtual ~Source();
virtual love::audio::Source *clone(); virtual love::audio::Source *clone();
virtual void play(); virtual bool play();
virtual void stop(); virtual void stop();
virtual void pause(); virtual void pause();
virtual void resume(); virtual void resume();
+28 -14
View File
@@ -69,22 +69,25 @@ void Audio::PoolThread::setFinish()
} }
Audio::Audio() Audio::Audio()
: distanceModel(DISTANCE_INVERSE_CLAMPED) : device(nullptr)
, capture(nullptr)
, context(nullptr)
, pool(nullptr)
, poolThread(nullptr)
, distanceModel(DISTANCE_INVERSE_CLAMPED)
{ {
// Passing zero for default device. // Passing null for default device.
device = alcOpenDevice(0); device = alcOpenDevice(nullptr);
if (device == 0) if (device == nullptr)
throw love::Exception("Could not open device."); throw love::Exception("Could not open device.");
context = alcCreateContext(device, 0); context = alcCreateContext(device, nullptr);
if (context == 0) if (context == nullptr)
throw love::Exception("Could not create context."); throw love::Exception("Could not create context.");
alcMakeContextCurrent(context); if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR)
if (alcGetError(device) != ALC_NO_ERROR)
throw love::Exception("Could not make context current."); throw love::Exception("Could not make context current.");
/*std::string captureName(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)); /*std::string captureName(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
@@ -108,7 +111,18 @@ Audio::Audio()
}*/ }*/
// pool must be allocated after AL context. // pool must be allocated after AL context.
pool = new Pool(); try
{
pool = new Pool();
}
catch (love::Exception &)
{
alcMakeContextCurrent(nullptr);
alcDestroyContext(context);
//if (capture) alcCaptureCloseDevice(capture);
alcCloseDevice(device);
throw;
}
poolThread = new PoolThread(pool); poolThread = new PoolThread(pool);
poolThread->start(); poolThread->start();
@@ -122,7 +136,7 @@ Audio::~Audio()
delete poolThread; delete poolThread;
delete pool; delete pool;
alcMakeContextCurrent(0); alcMakeContextCurrent(nullptr);
alcDestroyContext(context); alcDestroyContext(context);
//if (capture) alcCaptureCloseDevice(capture); //if (capture) alcCaptureCloseDevice(capture);
alcCloseDevice(device); alcCloseDevice(device);
@@ -154,9 +168,9 @@ int Audio::getMaxSources() const
return pool->getMaxSources(); return pool->getMaxSources();
} }
void Audio::play(love::audio::Source *source) bool Audio::play(love::audio::Source *source)
{ {
source->play(); return source->play();
} }
void Audio::stop(love::audio::Source *source) void Audio::stop(love::audio::Source *source)
@@ -281,7 +295,7 @@ bool Audio::canRecord()
Audio::DistanceModel Audio::getDistanceModel() const Audio::DistanceModel Audio::getDistanceModel() const
{ {
return this->distanceModel; return distanceModel;
} }
void Audio::setDistanceModel(DistanceModel distanceModel) void Audio::setDistanceModel(DistanceModel distanceModel)
+1 -2
View File
@@ -67,8 +67,7 @@ public:
love::audio::Source *newSource(love::sound::SoundData *soundData); love::audio::Source *newSource(love::sound::SoundData *soundData);
int getSourceCount() const; int getSourceCount() const;
int getMaxSources() const; int getMaxSources() const;
void play(love::audio::Source *source); bool play(love::audio::Source *source);
void play();
void stop(love::audio::Source *source); void stop(love::audio::Source *source);
void stop(); void stop();
void pause(love::audio::Source *source); void pause(love::audio::Source *source);
+31 -13
View File
@@ -30,23 +30,43 @@ namespace openal
{ {
Pool::Pool() Pool::Pool()
: sources()
, totalSources(0)
, mutex(nullptr)
{ {
// Clear errors.
alGetError();
// Generate sources. // Generate sources.
alGenSources(NUM_SOURCES, sources); for (int i = 0; i < MAX_SOURCES; i++)
{
alGenSources(1, &sources[i]);
// We might hit an implementation-dependent limit on the total number
// of sources before reaching MAX_SOURCES.
if (alGetError() != AL_NO_ERROR)
break;
totalSources++;
}
if (totalSources < 4)
throw love::Exception("Could not generate sources.");
// Create the mutex. // Create the mutex.
mutex = thread::newMutex(); mutex = thread::newMutex();
if (alGetError() != AL_NO_ERROR) ALboolean hasext = alIsExtensionPresent("AL_SOFT_direct_channels");
throw love::Exception("Could not generate sources.");
// Make all sources available initially. // Make all sources available initially.
for (int i = 0; i < NUM_SOURCES; i++) for (int i = 0; i < totalSources; i++)
{ {
#ifdef AL_DIRECT_CHANNELS_SOFT if (hasext)
// Bypassing virtualization of speakers for multi-channel sources in OpenAL Soft. {
alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE); // Bypass virtualization of speakers for multi-channel sources in OpenAL Soft.
#endif alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE);
}
available.push(sources[i]); available.push(sources[i]);
} }
} }
@@ -58,7 +78,7 @@ Pool::~Pool()
delete mutex; delete mutex;
// Free all sources. // Free all sources.
alDeleteSources(NUM_SOURCES, sources); alDeleteSources(totalSources, sources);
} }
bool Pool::isAvailable() const bool Pool::isAvailable() const
@@ -113,7 +133,7 @@ int Pool::getSourceCount() const
int Pool::getMaxSources() const int Pool::getMaxSources() const
{ {
return NUM_SOURCES; return totalSources;
} }
bool Pool::play(Source *source, ALuint &out) bool Pool::play(Source *source, ALuint &out)
@@ -141,9 +161,7 @@ bool Pool::play(Source *source, ALuint &out)
source->retain(); source->retain();
source->playAtomic(); ok = source->playAtomic();
ok = true;
} }
else else
{ {
+8 -3
View File
@@ -36,6 +36,7 @@
#ifdef LOVE_MACOSX_USE_FRAMEWORKS #ifdef LOVE_MACOSX_USE_FRAMEWORKS
#include <OpenAL-Soft/alc.h> #include <OpenAL-Soft/alc.h>
#include <OpenAL-Soft/al.h> #include <OpenAL-Soft/al.h>
#include <OpenAL-Soft/alext.h>
#else #else
#include <AL/alc.h> #include <AL/alc.h>
#include <AL/al.h> #include <AL/al.h>
@@ -99,11 +100,15 @@ private:
bool findSource(Source *source, ALuint &out); bool findSource(Source *source, ALuint &out);
bool removeSource(Source *source); bool removeSource(Source *source);
// Number of OpenAL sources.
static const int NUM_SOURCES = 64; // Maximum possible number of OpenAL sources the pool attempts to generate.
static const int MAX_SOURCES = 64;
// OpenAL sources // OpenAL sources
ALuint sources[NUM_SOURCES]; ALuint sources[MAX_SOURCES];
// Total number of created sources in the pool.
int totalSources;
// A queue of available sources. // A queue of available sources.
std::queue<ALuint> available; std::queue<ALuint> available;
+13 -3
View File
@@ -165,15 +165,16 @@ love::audio::Source *Source::clone()
return new Source(*this); return new Source(*this);
} }
void Source::play() bool Source::play()
{ {
if (valid && paused) if (valid && paused)
{ {
pool->resume(this); pool->resume(this);
return; return true;
} }
valid = pool->play(this, source); valid = pool->play(this, source);
return valid;
} }
void Source::stop() void Source::stop()
@@ -512,7 +513,7 @@ bool Source::isLooping() const
return looping; return looping;
} }
void Source::playAtomic() bool Source::playAtomic()
{ {
if (type == TYPE_STATIC) if (type == TYPE_STATIC)
{ {
@@ -539,10 +540,19 @@ void Source::playAtomic()
// of the new one. // of the new one.
reset(); reset();
// Clear errors.
alGetError();
alSourcePlay(source); alSourcePlay(source);
// alSourcePlay may fail if the system has reached its limit of simultaneous
// playing sources.
bool success = alGetError() == AL_NO_ERROR;
valid = true; //if it fails it will be set to false again valid = true; //if it fails it will be set to false again
//but this prevents a horrible, horrible bug //but this prevents a horrible, horrible bug
return success;
} }
void Source::stopAtomic() void Source::stopAtomic()
+2 -2
View File
@@ -76,7 +76,7 @@ public:
virtual ~Source(); virtual ~Source();
virtual love::audio::Source *clone(); virtual love::audio::Source *clone();
virtual void play(); virtual bool play();
virtual void stop(); virtual void stop();
virtual void pause(); virtual void pause();
virtual void resume(); virtual void resume();
@@ -118,7 +118,7 @@ public:
virtual float getMaxDistance() const; virtual float getMaxDistance() const;
virtual int getChannels() const; virtual int getChannels() const;
void playAtomic(); bool playAtomic();
void stopAtomic(); void stopAtomic();
void pauseAtomic(); void pauseAtomic();
void resumeAtomic(); void resumeAtomic();
+2 -2
View File
@@ -75,8 +75,8 @@ int w_newSource(lua_State *L)
int w_play(lua_State *L) int w_play(lua_State *L)
{ {
Source *s = luax_checksource(L, 1); Source *s = luax_checksource(L, 1);
instance->play(s); luax_pushboolean(L, instance->play(s));
return 0; return 1;
} }
int w_stop(lua_State *L) int w_stop(lua_State *L)
+2 -2
View File
@@ -44,8 +44,8 @@ int w_Source_clone(lua_State *L)
int w_Source_play(lua_State *L) int w_Source_play(lua_State *L)
{ {
Source *t = luax_checksource(L, 1); Source *t = luax_checksource(L, 1);
t->play(); luax_pushboolean(L, t->play());
return 0; return 1;
} }
int w_Source_stop(lua_State *L) int w_Source_stop(lua_State *L)
+8
View File
@@ -224,6 +224,14 @@ Message *Event::convert(const SDL_Event &e) const
txt = "touchmoved"; txt = "touchmoved";
msg = new Message(txt, vargs); msg = new Message(txt, vargs);
break; break;
case SDL_MULTIGESTURE:
vargs.push_back(new Variant((double) e.mgesture.x));
vargs.push_back(new Variant((double) e.mgesture.y));
vargs.push_back(new Variant((double) e.mgesture.dTheta));
vargs.push_back(new Variant((double) e.mgesture.dDist));
vargs.push_back(new Variant((double) e.mgesture.numFingers));
msg = new Message("touchgestured", vargs);
break;
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP: case SDL_JOYBUTTONUP:
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
+1 -1
View File
@@ -55,7 +55,7 @@ public:
* @param kx Shear along the x-axis. * @param kx Shear along the x-axis.
* @param ky Shear along the y-axis. * @param ky Shear along the y-axis.
**/ **/
virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const = 0; virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) = 0;
}; };
} // graphics } // graphics
@@ -99,6 +99,16 @@ bool Graphics::getConstant(Support in, const char *&out)
return support.find(in, out); return support.find(in, out);
} }
bool Graphics::getConstant(const char *in, SystemLimit &out)
{
return systemLimits.find(in, out);
}
bool Graphics::getConstant(SystemLimit in, const char *&out)
{
return systemLimits.find(in, out);
}
StringMap<Graphics::DrawMode, Graphics::DRAW_MAX_ENUM>::Entry Graphics::drawModeEntries[] = StringMap<Graphics::DrawMode, Graphics::DRAW_MAX_ENUM>::Entry Graphics::drawModeEntries[] =
{ {
{ "line", Graphics::DRAW_LINE }, { "line", Graphics::DRAW_LINE },
@@ -170,5 +180,15 @@ StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries)); StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));
StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM>::Entry Graphics::systemLimitEntries[] =
{
{"pointsize", Graphics::LIMIT_POINT_SIZE},
{"texturesize", Graphics::LIMIT_TEXTURE_SIZE},
{"multicanvas", Graphics::LIMIT_MULTI_CANVAS},
{"canvasfsaa", Graphics::LIMIT_CANVAS_FSAA},
};
StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM> Graphics::systemLimits(Graphics::systemLimitEntries, sizeof(Graphics::systemLimitEntries));
} // graphics } // graphics
} // love } // love
+15
View File
@@ -114,6 +114,15 @@ public:
RENDERER_INFO_MAX_ENUM RENDERER_INFO_MAX_ENUM
}; };
enum SystemLimit
{
LIMIT_POINT_SIZE,
LIMIT_TEXTURE_SIZE,
LIMIT_MULTI_CANVAS,
LIMIT_CANVAS_FSAA,
LIMIT_MAX_ENUM
};
virtual ~Graphics(); virtual ~Graphics();
/** /**
@@ -155,6 +164,9 @@ public:
static bool getConstant(const char *in, Support &out); static bool getConstant(const char *in, Support &out);
static bool getConstant(Support in, const char *&out); static bool getConstant(Support in, const char *&out);
static bool getConstant(const char *in, SystemLimit &out);
static bool getConstant(SystemLimit in, const char *&out);
private: private:
static StringMap<DrawMode, DRAW_MAX_ENUM>::Entry drawModeEntries[]; static StringMap<DrawMode, DRAW_MAX_ENUM>::Entry drawModeEntries[];
@@ -178,6 +190,9 @@ private:
static StringMap<Support, SUPPORT_MAX_ENUM>::Entry supportEntries[]; static StringMap<Support, SUPPORT_MAX_ENUM>::Entry supportEntries[];
static StringMap<Support, SUPPORT_MAX_ENUM> support; static StringMap<Support, SUPPORT_MAX_ENUM> support;
static StringMap<SystemLimit, LIMIT_MAX_ENUM>::Entry systemLimitEntries[];
static StringMap<SystemLimit, LIMIT_MAX_ENUM> systemLimits;
}; // Graphics }; // Graphics
} // graphics } // graphics
+1 -1
View File
@@ -88,7 +88,7 @@ public:
* @param kx Shear along the x-axis. * @param kx Shear along the x-axis.
* @param ky Shear along the y-axis. * @param ky Shear along the y-axis.
**/ **/
virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const = 0; virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) = 0;
virtual int getWidth() const; virtual int getWidth() const;
virtual int getHeight() const; virtual int getHeight() const;
+245 -33
View File
@@ -63,12 +63,26 @@ struct FramebufferStrategy
return false; return false;
} }
/// Create a MSAA renderbuffer and attach it to the active FBO.
/**
* @param[in] width Width of the MSAA buffer
* @param[in] height Height of the MSAA buffer
* @param[inout] samples Number of samples to use
* @param[in] internalformat The internal format to use for the buffer
* @param[out] buffer Name for the MSAA buffer
* @return Whether the MSAA buffer was successfully created and attached
**/
virtual bool createMSAABuffer(int, int, int &, GLenum, GLuint &)
{
return false;
}
/// remove objects /// remove objects
/** /**
* @param[in] framebuffer Framebuffer name * @param[in] framebuffer Framebuffer name
* @param[in] depth_stencil Name for packed depth and stencil buffer * @param[in] depth_stencil Name for packed depth and stencil buffer
*/ */
virtual void deleteFBO(GLuint, GLuint) {} virtual void deleteFBO(GLuint, GLuint, GLuint) {}
virtual void bindFBO(GLuint) {} virtual void bindFBO(GLuint) {}
/// attach additional canvases to the active framebuffer for rendering /// attach additional canvases to the active framebuffer for rendering
@@ -93,8 +107,11 @@ struct FramebufferStrategyCore : public FramebufferStrategy
glGenFramebuffers(1, &framebuffer); glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, if (texture != 0)
GL_TEXTURE_2D, texture, 0); {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, texture, 0);
}
// check status // check status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -118,13 +135,44 @@ struct FramebufferStrategyCore : public FramebufferStrategy
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
// check status // check status
return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE; if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
glDeleteRenderbuffers(1, &stencil);
stencil = 0;
return false;
}
return true;
} }
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil) virtual bool createMSAABuffer(int width, int height, int &samples, GLenum internalformat, GLuint &buffer)
{
glGenRenderbuffers(1, &buffer);
glBindRenderbuffer(GL_RENDERBUFFER, buffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalformat,
width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, buffer);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
glDeleteRenderbuffers(1, &buffer);
buffer = 0;
return false;
}
return true;
}
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil, GLuint msaa_buffer)
{ {
if (depth_stencil != 0) if (depth_stencil != 0)
glDeleteRenderbuffers(1, &depth_stencil); glDeleteRenderbuffers(1, &depth_stencil);
if (msaa_buffer != 0)
glDeleteRenderbuffers(1, &msaa_buffer);
if (framebuffer != 0) if (framebuffer != 0)
glDeleteFramebuffers(1, &framebuffer); glDeleteFramebuffers(1, &framebuffer);
} }
@@ -212,7 +260,7 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy
virtual bool createStencil(int width, int height, GLuint &stencil) virtual bool createStencil(int width, int height, GLuint &stencil)
{ {
// create combined depth/stencil buffer // create combined depth/stencil buffer
glDeleteRenderbuffers(1, &stencil); glDeleteRenderbuffersEXT(1, &stencil);
glGenRenderbuffersEXT(1, &stencil); glGenRenderbuffersEXT(1, &stencil);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT,
@@ -223,13 +271,47 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// check status // check status
return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT; if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
glDeleteRenderbuffersEXT(1, &stencil);
stencil = 0;
return false;
}
return true;
} }
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil) virtual bool createMSAABuffer(int width, int height, int &samples, GLenum internalformat, GLuint &buffer)
{
if (!GLAD_EXT_framebuffer_multisample)
return false;
glGenRenderbuffersEXT(1, &buffer);
glBindRenderbufferEXT(GL_RENDERBUFFER, buffer);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
internalformat, width, height);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, buffer);
glGetRenderbufferParameterivEXT(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
glDeleteRenderbuffersEXT(1, &buffer);
buffer = 0;
return false;
}
return true;
}
virtual void deleteFBO(GLuint framebuffer, GLuint depth_stencil, GLuint msaa_buffer)
{ {
if (depth_stencil != 0) if (depth_stencil != 0)
glDeleteRenderbuffersEXT(1, &depth_stencil); glDeleteRenderbuffersEXT(1, &depth_stencil);
if (msaa_buffer != 0)
glDeleteRenderbuffersEXT(1, &msaa_buffer);
if (framebuffer != 0) if (framebuffer != 0)
glDeleteFramebuffersEXT(1, &framebuffer); glDeleteFramebuffersEXT(1, &framebuffer);
} }
@@ -277,7 +359,7 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT
virtual bool createStencil(int width, int height, GLuint &stencil) virtual bool createStencil(int width, int height, GLuint &stencil)
{ {
// create stencil buffer // create stencil buffer
glDeleteRenderbuffers(1, &stencil); glDeleteRenderbuffersEXT(1, &stencil);
glGenRenderbuffersEXT(1, &stencil); glGenRenderbuffersEXT(1, &stencil);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencil);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX,
@@ -288,14 +370,21 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// check status // check status
return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT; if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
glDeleteRenderbuffersEXT(1, &stencil);
stencil = 0;
return false;
}
return true;
} }
bool isSupported() bool isSupported()
{ {
GLuint fb = 0, stencil = 0; GLuint fb = 0, stencil = 0;
GLenum status = createFBO(fb, 0); GLenum status = createFBO(fb, 0);
deleteFBO(fb, stencil); deleteFBO(fb, stencil, 0);
return status == GL_FRAMEBUFFER_COMPLETE; return status == GL_FRAMEBUFFER_COMPLETE;
} }
}; };
@@ -335,11 +424,15 @@ static void getStrategy()
static int maxFBOColorAttachments = 0; static int maxFBOColorAttachments = 0;
static int maxDrawBuffers = 0; static int maxDrawBuffers = 0;
Canvas::Canvas(int width, int height, TextureType texture_type) Canvas::Canvas(int width, int height, TextureType texture_type, int fsaa)
: fbo(0) : fbo(0)
, resolve_fbo(0)
, texture(0) , texture(0)
, fsaa_buffer(0)
, depth_stencil(0) , depth_stencil(0)
, texture_type(texture_type) , texture_type(texture_type)
, fsaa_samples(fsaa)
, fsaa_dirty(false)
{ {
this->width = width; this->width = width;
this->height = height; this->height = height;
@@ -381,9 +474,50 @@ Canvas::~Canvas()
unloadVolatile(); unloadVolatile();
} }
bool Canvas::createFSAAFBO(GLenum internalformat)
{
// Create our FBO without a texture.
status = strategy->createFBO(fbo, 0);
GLuint previous = 0;
if (current != this)
{
if (current != nullptr)
previous = current->fbo;
strategy->bindFBO(fbo);
}
// Create and attach the MSAA buffer for our FBO.
if (strategy->createMSAABuffer(width, height, fsaa_samples, internalformat, fsaa_buffer))
status = GL_FRAMEBUFFER_COMPLETE;
else
status = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
// Create the FBO used for the MSAA resolve, and attach the texture.
if (status == GL_FRAMEBUFFER_COMPLETE)
status = strategy->createFBO(resolve_fbo, texture);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
// Clean up.
strategy->deleteFBO(fbo, 0, fsaa_buffer);
strategy->deleteFBO(resolve_fbo, 0, 0);
fbo = fsaa_buffer = resolve_fbo = 0;
fsaa_samples = 0;
}
if (current != this)
strategy->bindFBO(previous);
return status == GL_FRAMEBUFFER_COMPLETE;
}
bool Canvas::loadVolatile() bool Canvas::loadVolatile()
{ {
fbo = depth_stencil = texture = 0; fbo = depth_stencil = texture = 0;
resolve_fbo = fsaa_buffer = 0;
status = GL_FRAMEBUFFER_COMPLETE;
// glTexImage2D is guaranteed to error in this case. // glTexImage2D is guaranteed to error in this case.
if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize()) if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize())
@@ -430,7 +564,25 @@ bool Canvas::loadVolatile()
return false; return false;
} }
status = strategy->createFBO(fbo, texture); int max_samples = 0;
if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object
|| GLAD_EXT_framebuffer_multisample)
{
glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
}
if (fsaa_samples > max_samples)
fsaa_samples = max_samples;
// Try to create a FSAA FBO if requested.
bool fsaasuccess = false;
if (fsaa_samples > 1)
fsaasuccess = createFSAAFBO(internalformat);
// On failure (or no requested FSAA), fall back to a regular FBO.
if (!fsaasuccess)
status = strategy->createFBO(fbo, texture);
if (status != GL_FRAMEBUFFER_COMPLETE) if (status != GL_FRAMEBUFFER_COMPLETE)
return false; return false;
@@ -440,11 +592,13 @@ bool Canvas::loadVolatile()
void Canvas::unloadVolatile() void Canvas::unloadVolatile()
{ {
strategy->deleteFBO(fbo, depth_stencil); strategy->deleteFBO(fbo, depth_stencil, fsaa_buffer);
strategy->deleteFBO(resolve_fbo, 0, 0);
gl.deleteTexture(texture); gl.deleteTexture(texture);
fbo = depth_stencil = texture = 0; fbo = depth_stencil = texture = 0;
resolve_fbo = fsaa_buffer = 0;
for (size_t i = 0; i < attachedCanvases.size(); i++) for (size_t i = 0; i < attachedCanvases.size(); i++)
attachedCanvases[i]->release(); attachedCanvases[i]->release();
@@ -452,7 +606,7 @@ void Canvas::unloadVolatile()
attachedCanvases.clear(); attachedCanvases.clear();
} }
void Canvas::drawv(const Matrix &t, const Vertex *v) const void Canvas::drawv(const Matrix &t, const Vertex *v)
{ {
gl.matrices.transform.push(gl.matrices.transform.top()); gl.matrices.transform.push(gl.matrices.transform.top());
gl.matrices.transform.top() *= t; gl.matrices.transform.top() *= t;
@@ -475,10 +629,9 @@ void Canvas::drawv(const Matrix &t, const Vertex *v) const
postdraw(); postdraw();
gl.matrices.transform.pop(); gl.matrices.transform.pop();
} }
void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
static Matrix t; static Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
@@ -486,7 +639,7 @@ void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, f
drawv(t, vertices); drawv(t, vertices);
} }
void Canvas::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const void Canvas::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
static Matrix t; static Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
@@ -514,8 +667,12 @@ GLuint Canvas::getGLTexture() const
return texture; return texture;
} }
void Canvas::predraw() const void Canvas::predraw()
{ {
// We need to make sure the texture is up-to-date by resolving the MSAA
// buffer (which we render to when the canvas is active) to it.
resolveMSAA();
gl.bindTexture(texture); gl.bindTexture(texture);
} }
@@ -539,6 +696,9 @@ void Canvas::setupGrab()
// indicate we are using this fbo // indicate we are using this fbo
current = this; current = this;
if (fsaa_buffer != 0)
fsaa_dirty = true;
} }
void Canvas::startGrab(const std::vector<Canvas *> &canvases) void Canvas::startGrab(const std::vector<Canvas *> &canvases)
@@ -554,6 +714,9 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
if (canvases.size()+1 > size_t(maxDrawBuffers) || canvases.size()+1 > size_t(maxFBOColorAttachments)) if (canvases.size()+1 > size_t(maxDrawBuffers) || canvases.size()+1 > size_t(maxFBOColorAttachments))
throw love::Exception("This system can't simultaniously render to %d canvases.", canvases.size()+1); throw love::Exception("This system can't simultaniously render to %d canvases.", canvases.size()+1);
if (fsaa_samples != 0)
throw love::Exception("Multi-canvas rendering is not supported with FSAA.");
} }
for (size_t i = 0; i < canvases.size(); i++) for (size_t i = 0; i < canvases.size(); i++)
@@ -564,6 +727,9 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
if (canvases[i]->getTextureType() != texture_type) if (canvases[i]->getTextureType() != texture_type)
throw love::Exception("All canvas arguments must have the same texture type."); throw love::Exception("All canvas arguments must have the same texture type.");
if (canvases[i]->getFSAA() != 0)
throw love::Exception("Multi-canvas rendering is not supported with FSAA.");
if (!canvaseschanged && canvases[i] != attachedCanvases[i]) if (!canvaseschanged && canvases[i] != attachedCanvases[i])
canvaseschanged = true; canvaseschanged = true;
} }
@@ -698,12 +864,22 @@ bool Canvas::checkCreateStencil()
love::image::ImageData *Canvas::getImageData(love::image::Image *image) love::image::ImageData *Canvas::getImageData(love::image::Image *image)
{ {
resolveMSAA();
int row = 4 * width; int row = 4 * width;
int size = row * height; int size = row * height;
GLubyte *pixels = new GLubyte[size]; GLubyte *pixels = new GLubyte[size];
strategy->bindFBO(fbo); // Our texture is attached to 'resolve_fbo' when we use MSAA.
if (fsaa_samples > 1 && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo);
else if (fsaa_samples > 1 && GLAD_EXT_framebuffer_multisample)
glBindFramebufferEXT(GL_READ_FRAMEBUFFER, resolve_fbo);
else
strategy->bindFBO(fbo);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
if (current) if (current)
strategy->bindFBO(current->fbo); strategy->bindFBO(current->fbo);
else else
@@ -716,10 +892,17 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image)
void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y) void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y)
{ {
if (current != this) resolveMSAA();
// Our texture is attached to 'resolve_fbo' when we use MSAA.
if (fsaa_samples > 1 && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo);
else if (fsaa_samples > 1 && GLAD_EXT_framebuffer_multisample)
glBindFramebufferEXT(GL_READ_FRAMEBUFFER, resolve_fbo);
else if (current != this)
strategy->bindFBO(fbo); strategy->bindFBO(fbo);
glReadPixels(x, height - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_rgba); glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_rgba);
if (current && current != this) if (current && current != this)
strategy->bindFBO(current->fbo); strategy->bindFBO(current->fbo);
@@ -727,6 +910,44 @@ void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y)
strategy->bindFBO(gl.getDefaultFBO()); strategy->bindFBO(gl.getDefaultFBO());
} }
bool Canvas::resolveMSAA()
{
if (resolve_fbo == 0 || fsaa_buffer == 0)
return false;
if (!fsaa_dirty)
return true;
GLuint previous = 0;
if (current != nullptr)
previous = current->fbo;
// Do the MSAA resolve by blitting the MSAA renderbuffer to the texture.
if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
else if (GLAD_EXT_framebuffer_multisample && GLAD_EXT_framebuffer_blit)
{
glBindFramebufferEXT(GL_READ_FRAMEBUFFER, fbo);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, resolve_fbo);
glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
else
return false;
strategy->bindFBO(previous);
if (current != this)
fsaa_dirty = false;
return true;
}
bool Canvas::isSupported() bool Canvas::isSupported()
{ {
getStrategy(); getStrategy();
@@ -740,17 +961,8 @@ bool Canvas::isHDRSupported()
bool Canvas::isMultiCanvasSupported() bool Canvas::isMultiCanvasSupported()
{ {
if (!(isSupported() && (GLAD_VERSION_2_0 || GLAD_ARB_draw_buffers))) // system must support at least 4 simultanious active canvases.
return false; return gl.getMaxRenderTargets() >= 4;
if (maxFBOColorAttachments == 0 || maxDrawBuffers == 0)
{
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxFBOColorAttachments);
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
}
// system must support at least 4 simultanious active canvases
return maxFBOColorAttachments >= 4 && maxDrawBuffers >= 4;
} }
void Canvas::bindDefaultCanvas() void Canvas::bindDefaultCanvas()
+20 -5
View File
@@ -46,7 +46,7 @@ public:
TYPE_MAX_ENUM TYPE_MAX_ENUM
}; };
Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL); Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL, int fsaa = 0);
virtual ~Canvas(); virtual ~Canvas();
// Implements Volatile. // Implements Volatile.
@@ -54,14 +54,14 @@ public:
virtual void unloadVolatile(); virtual void unloadVolatile();
// Implements Drawable. // Implements Drawable.
virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
// Implements Texture. // Implements Texture.
virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
virtual void setFilter(const Texture::Filter &f); virtual void setFilter(const Texture::Filter &f);
virtual void setWrap(const Texture::Wrap &w); virtual void setWrap(const Texture::Wrap &w);
virtual GLuint getGLTexture() const; virtual GLuint getGLTexture() const;
virtual void predraw() const; virtual void predraw();
/** /**
* @param canvases A list of other canvases to temporarily attach to this one, * @param canvases A list of other canvases to temporarily attach to this one,
@@ -97,6 +97,13 @@ public:
return texture_type; return texture_type;
} }
inline int getFSAA() const
{
return fsaa_samples;
}
bool resolveMSAA();
static bool isSupported(); static bool isSupported();
static bool isHDRSupported(); static bool isHDRSupported();
static bool isMultiCanvasSupported(); static bool isMultiCanvasSupported();
@@ -112,8 +119,13 @@ public:
private: private:
bool createFSAAFBO(GLenum internalformat);
GLuint fbo; GLuint fbo;
GLuint resolve_fbo;
GLuint texture; GLuint texture;
GLuint fsaa_buffer;
GLuint depth_stencil; GLuint depth_stencil;
TextureType texture_type; TextureType texture_type;
@@ -122,8 +134,11 @@ private:
std::vector<Canvas *> attachedCanvases; std::vector<Canvas *> attachedCanvases;
int fsaa_samples;
bool fsaa_dirty;
void setupGrab(); void setupGrab();
void drawv(const Matrix &t, const Vertex *v) const; void drawv(const Matrix &t, const Vertex *v);
static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[]; static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[];
static StringMap<TextureType, TYPE_MAX_ENUM> textureTypes; static StringMap<TextureType, TYPE_MAX_ENUM> textureTypes;
+106 -14
View File
@@ -228,6 +228,18 @@ bool Graphics::setMode(int width, int height)
Shader::defaultShader->attach(); Shader::defaultShader->attach();
} }
bool enabledebug = false;
if (GLAD_VERSION_3_0)
{
// Enable OpenGL's debug output if a debug context has been created.
GLint flags = 0;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
enabledebug = (flags & GL_CONTEXT_FLAG_DEBUG_BIT) != 0;
}
setDebug(enabledebug);
return true; return true;
} }
@@ -246,6 +258,63 @@ void Graphics::unSetMode()
} }
} }
static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, const GLvoid* /*usr*/)
{
// Human-readable strings for the debug info.
const char *sourceStr = OpenGL::debugSourceString(source);
const char *typeStr = OpenGL::debugTypeString(type);
const char *severityStr = OpenGL::debugSeverityString(severity);
const char *fmt = "OpenGL: %s [source=%s, type=%s, severity=%s, id=%d]\n";
printf(fmt, msg, sourceStr, typeStr, severityStr, id);
}
void Graphics::setDebug(bool enable)
{
// Make sure debug output is supported. The AMD ext. is a bit different
// so we don't make use of it, since AMD drivers now support KHR_debug.
if (!(GLAD_VERSION_4_3 || GLAD_KHR_debug || GLAD_ARB_debug_output))
return;
// Ugly hack to reduce code duplication.
if (GLAD_ARB_debug_output && !(GLAD_VERSION_4_3 || GLAD_KHR_debug))
{
fp_glDebugMessageCallback = (pfn_glDebugMessageCallback) fp_glDebugMessageCallbackARB;
fp_glDebugMessageControl = (pfn_glDebugMessageControl) fp_glDebugMessageControlARB;
}
else if (GLAD_ES_VERSION_2_0 && GLAD_KHR_debug)
{
fp_glDebugMessageCallback = (pfn_glDebugMessageCallback) fp_glDebugMessageCallbackKHR;
fp_glDebugMessageControl = (pfn_glDebugMessageControl) fp_glDebugMessageControlKHR;
}
if (!enable)
{
// Disable the debug callback function.
glDebugMessageCallback(nullptr, nullptr);
// We can disable debug output entirely with KHR_debug.
if (GLAD_VERSION_4_3 || GLAD_KHR_debug)
glDisable(GL_DEBUG_OUTPUT);
return;
}
// We don't want asynchronous debug output.
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(debugCB, nullptr);
// Initially, enable everything.
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE);
// Disable messages about deprecated OpenGL functionality.
glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE);
glDebugMessageControl(GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE);
::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n");
}
void Graphics::reset() void Graphics::reset()
{ {
DisplayState s; DisplayState s;
@@ -361,11 +430,6 @@ void Graphics::discardStencil()
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);
} }
int Graphics::getMaxTextureSize() const
{
return gl.getMaxTextureSize();
}
Image *Graphics::newImage(love::image::ImageData *data) Image *Graphics::newImage(love::image::ImageData *data)
{ {
// Create the image. // Create the image.
@@ -440,7 +504,7 @@ ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
return new ParticleSystem(texture, size); return new ParticleSystem(texture, size);
} }
Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type) Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type, int fsaa)
{ {
if (texture_type == Canvas::TYPE_HDR && !Canvas::isHDRSupported()) if (texture_type == Canvas::TYPE_HDR && !Canvas::isHDRSupported())
throw Exception("HDR Canvases are not supported by your OpenGL implementation"); throw Exception("HDR Canvases are not supported by your OpenGL implementation");
@@ -453,7 +517,7 @@ Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_t
while (GL_NO_ERROR != glGetError()) while (GL_NO_ERROR != glGetError())
/* clear opengl error flag */; /* clear opengl error flag */;
Canvas *canvas = new Canvas(width, height, texture_type); Canvas *canvas = new Canvas(width, height, texture_type, fsaa);
GLenum err = canvas->getStatus(); GLenum err = canvas->getStatus();
// everything ok, return canvas (early out) // everything ok, return canvas (early out)
@@ -771,13 +835,6 @@ Graphics::PointStyle Graphics::getPointStyle() const
return POINT_ROUGH; return POINT_ROUGH;
} }
int Graphics::getMaxPointSize() const
{
GLint max;
glGetIntegerv(GL_POINT_SIZE_MAX, &max);
return (int)max;
}
void Graphics::print(const std::string &str, float x, float y , float angle, float sx, float sy, float ox, float oy, float kx, float ky) void Graphics::print(const std::string &str, float x, float y , float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
if (currentFont != nullptr) if (currentFont != nullptr)
@@ -1103,6 +1160,41 @@ std::string Graphics::getRendererInfo(Graphics::RendererInfo infotype) const
return std::string(infostr); return std::string(infostr);
} }
double Graphics::getSystemLimit(SystemLimit limittype) const
{
double limit = 0.0;
switch (limittype)
{
case Graphics::LIMIT_POINT_SIZE:
{
GLfloat limits[2];
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, limits);
limit = limits[1];
}
break;
case Graphics::LIMIT_TEXTURE_SIZE:
limit = (double) gl.getMaxTextureSize();
break;
case Graphics::LIMIT_MULTI_CANVAS:
limit = (double) gl.getMaxRenderTargets();
break;
case Graphics::LIMIT_CANVAS_FSAA:
if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object
|| GLAD_EXT_framebuffer_multisample)
{
GLint intlimit = 0;
glGetIntegerv(GL_MAX_SAMPLES, &intlimit);
limit = (double) intlimit;
}
break;
default:
break;
}
return limit;
}
void Graphics::push() void Graphics::push()
{ {
if (gl.matrices.transform.size() == matrixLimit) if (gl.matrices.transform.size() == matrixLimit)
@@ -115,6 +115,8 @@ public:
virtual bool setMode(int width, int height); virtual bool setMode(int width, int height);
virtual void unSetMode(); virtual void unSetMode();
void setDebug(bool enable);
/** /**
* Resets the current color, background color, * Resets the current color, background color,
* line style, and so forth. (This will be called * line style, and so forth. (This will be called
@@ -186,11 +188,6 @@ public:
*/ */
void discardStencil(); void discardStencil();
/**
* Gets the maximum supported width or height of Textures on this system.
**/
int getMaxTextureSize() const;
/** /**
* Creates an Image object with padding and/or optimization. * Creates an Image object with padding and/or optimization.
**/ **/
@@ -208,7 +205,7 @@ public:
ParticleSystem *newParticleSystem(Texture *texture, int size); ParticleSystem *newParticleSystem(Texture *texture, int size);
Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL); Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL, int fsaa = 0);
Shader *newShader(const Shader::ShaderSources &sources); Shader *newShader(const Shader::ShaderSources &sources);
@@ -337,12 +334,6 @@ public:
**/ **/
PointStyle getPointStyle() const; PointStyle getPointStyle() const;
/**
* Gets the maximum point size supported.
* This may vary from computer to computer.
**/
int getMaxPointSize() const;
/** /**
* Draws text at the specified coordinates, with rotation and * Draws text at the specified coordinates, with rotation and
* scaling along both axes. * scaling along both axes.
@@ -444,6 +435,11 @@ public:
**/ **/
std::string getRendererInfo(Graphics::RendererInfo infotype) const; std::string getRendererInfo(Graphics::RendererInfo infotype) const;
/**
* Gets the system-dependent numeric limit for the specified parameter.
**/
double getSystemLimit(SystemLimit limittype) const;
void push(); void push();
void pop(); void pop();
void rotate(float r); void rotate(float r);
@@ -91,7 +91,7 @@ love::image::CompressedData *Image::getCompressedData() const
return cdata; return cdata;
} }
void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const void Image::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
Matrix t; Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
@@ -99,7 +99,7 @@ void Image::draw(float x, float y, float angle, float sx, float sy, float ox, fl
drawv(t, vertices); drawv(t, vertices);
} }
void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
Matrix t; Matrix t;
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
@@ -107,7 +107,7 @@ void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy,
drawv(t, quad->getVertices()); drawv(t, quad->getVertices());
} }
void Image::predraw() const void Image::predraw()
{ {
bind(); bind();
@@ -121,7 +121,7 @@ void Image::predraw() const
} }
} }
void Image::postdraw() const void Image::postdraw()
{ {
if (width != paddedWidth || height != paddedHeight) if (width != paddedWidth || height != paddedHeight)
{ {
@@ -511,7 +511,7 @@ void Image::uploadDefaultTexture()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, px); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, px);
} }
void Image::drawv(const Matrix &t, const Vertex *v) const void Image::drawv(const Matrix &t, const Vertex *v)
{ {
predraw(); predraw();
+5 -5
View File
@@ -76,20 +76,20 @@ public:
/** /**
* @copydoc Drawable::draw() * @copydoc Drawable::draw()
**/ **/
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
/** /**
* @copydoc Texture::drawq() * @copydoc Texture::drawq()
**/ **/
void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
/** /**
* Call before using this Image's texture to draw. Binds the texture, * Call before using this Image's texture to draw. Binds the texture,
* globally scales texture coordinates if the Image has NPOT dimensions and * globally scales texture coordinates if the Image has NPOT dimensions and
* NPOT isn't supported, etc. * NPOT isn't supported, etc.
**/ **/
virtual void predraw() const; virtual void predraw();
virtual void postdraw() const; virtual void postdraw();
virtual GLuint getGLTexture() const; virtual GLuint getGLTexture() const;
@@ -136,7 +136,7 @@ private:
void uploadDefaultTexture(); void uploadDefaultTexture();
void drawv(const Matrix &t, const Vertex *v) const; void drawv(const Matrix &t, const Vertex *v);
// The ImageData from which the texture is created. May be null if // The ImageData from which the texture is created. May be null if
// Compressed image data was used to create the texture. // Compressed image data was used to create the texture.
@@ -288,7 +288,7 @@ bool Mesh::isWireframe() const
return wireframe; return wireframe;
} }
void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
const size_t pos_offset = offsetof(Vertex, x); const size_t pos_offset = offsetof(Vertex, x);
const size_t tex_offset = offsetof(Vertex, s); const size_t tex_offset = offsetof(Vertex, s);
+1 -1
View File
@@ -172,7 +172,7 @@ public:
bool isWireframe() const; bool isWireframe() const;
// Implements Drawable. // Implements Drawable.
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
static bool getConstant(const char *in, DrawMode &out); static bool getConstant(const char *in, DrawMode &out);
static bool getConstant(DrawMode in, const char *&out); static bool getConstant(DrawMode in, const char *&out);
@@ -43,6 +43,7 @@ OpenGL::OpenGL()
: contextInitialized(false) : contextInitialized(false)
, maxAnisotropy(1.0f) , maxAnisotropy(1.0f)
, maxTextureSize(0) , maxTextureSize(0)
, maxRenderTargets(0)
, vendor(VENDOR_UNKNOWN) , vendor(VENDOR_UNKNOWN)
, state() , state()
{ {
@@ -202,6 +203,19 @@ void OpenGL::initMaxValues()
maxAnisotropy = 1.0f; maxAnisotropy = 1.0f;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
if (Canvas::isSupported() && (GLAD_VERSION_2_0 || GLAD_ARB_draw_buffers))
{
int maxattachments = 0;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxattachments);
int maxdrawbuffers = 0;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxdrawbuffers);
maxRenderTargets = std::min(maxattachments, maxdrawbuffers);
}
else
maxRenderTargets = 0;
} }
void OpenGL::initMatrices() void OpenGL::initMatrices()
@@ -260,6 +274,18 @@ void OpenGL::prepareDraw()
glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, 0.0f); glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, 0.0f);
state.lastPseudoInstanceID = 0; state.lastPseudoInstanceID = 0;
} }
// We need to make sure antialiased Canvases are properly resolved
// before sampling from their textures in a shader.
// This is kind of a big hack. :(
const std::map<std::string, Object *> &r = shader->getBoundRetainables();
for (auto it = r.begin(); it != r.end(); ++it)
{
// Even bigger hack! D:
Canvas *canvas = dynamic_cast<Canvas *>(it->second);
if (canvas != nullptr)
canvas->resolveMSAA();
}
} }
if (GLAD_ES_VERSION_2_0 && shader) if (GLAD_ES_VERSION_2_0 && shader)
@@ -716,11 +742,77 @@ int OpenGL::getMaxTextureSize() const
return maxTextureSize; return maxTextureSize;
} }
int OpenGL::getMaxRenderTargets() const
{
return maxRenderTargets;
}
OpenGL::Vendor OpenGL::getVendor() const OpenGL::Vendor OpenGL::getVendor() const
{ {
return vendor; return vendor;
} }
const char *OpenGL::debugSeverityString(GLenum severity)
{
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH:
return "high";
case GL_DEBUG_SEVERITY_MEDIUM:
return "medium";
case GL_DEBUG_SEVERITY_LOW:
return "low";
default:
break;
}
return "unknown";
}
const char *OpenGL::debugSourceString(GLenum source)
{
switch (source)
{
case GL_DEBUG_SOURCE_API:
return "API";
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
return "window";
case GL_DEBUG_SOURCE_SHADER_COMPILER:
return "shader";
case GL_DEBUG_SOURCE_THIRD_PARTY:
return "external";
case GL_DEBUG_SOURCE_APPLICATION:
return "LOVE";
case GL_DEBUG_SOURCE_OTHER:
return "other";
default:
break;
}
return "unknown";
}
const char *OpenGL::debugTypeString(GLenum type)
{
switch (type)
{
case GL_DEBUG_TYPE_ERROR:
return "error";
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
return "deprecated behavior";
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
return "undefined behavior";
case GL_DEBUG_TYPE_PERFORMANCE:
return "performance";
case GL_DEBUG_TYPE_PORTABILITY:
return "portability";
case GL_DEBUG_TYPE_OTHER:
return "other";
default:
break;
}
return "unknown";
}
// OpenGL class instance singleton. // OpenGL class instance singleton.
OpenGL gl; OpenGL gl;
@@ -96,6 +96,11 @@ public:
Viewport(int _x, int _y, int _w, int _h) Viewport(int _x, int _y, int _w, int _h)
: x(_x), y(_y), w(_w), h(_h) : x(_x), y(_y), w(_w), h(_h)
{} {}
bool operator == (const Viewport &rhs) const
{
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
}
}; };
// Transformation matrix stacks. // Transformation matrix stacks.
@@ -271,11 +276,21 @@ public:
**/ **/
int getMaxTextureSize() const; int getMaxTextureSize() const;
/**
* Returns the maximum supported number of simultaneous render targets.
**/
int getMaxRenderTargets() const;
/** /**
* Get the GPU vendor of this OpenGL context. * Get the GPU vendor of this OpenGL context.
**/ **/
Vendor getVendor() const; Vendor getVendor() const;
// Get human-readable strings for debug info.
static const char *debugSeverityString(GLenum severity);
static const char *debugSourceString(GLenum source);
static const char *debugTypeString(GLenum type);
private: private:
void initVendor(); void initVendor();
@@ -290,6 +305,7 @@ private:
float maxAnisotropy; float maxAnisotropy;
int maxTextureSize; int maxTextureSize;
int maxRenderTargets;
Vendor vendor; Vendor vendor;
@@ -442,14 +442,14 @@ ParticleSystem::InsertMode ParticleSystem::getInsertMode() const
return insertMode; return insertMode;
} }
void ParticleSystem::setEmissionRate(int rate) void ParticleSystem::setEmissionRate(float rate)
{ {
if (rate < 0) if (rate < 0.0f)
throw love::Exception("Invalid emission rate"); throw love::Exception("Invalid emission rate");
emissionRate = rate; emissionRate = rate;
} }
int ParticleSystem::getEmissionRate() const float ParticleSystem::getEmissionRate() const
{ {
return emissionRate; return emissionRate;
} }
@@ -484,6 +484,7 @@ void ParticleSystem::getParticleLifetime(float *min, float *max) const
void ParticleSystem::setPosition(float x, float y) void ParticleSystem::setPosition(float x, float y)
{ {
position = love::Vector(x, y); position = love::Vector(x, y);
prevPosition = position;
} }
const love::Vector &ParticleSystem::getPosition() const const love::Vector &ParticleSystem::getPosition() const
@@ -491,6 +492,11 @@ const love::Vector &ParticleSystem::getPosition() const
return position; return position;
} }
void ParticleSystem::moveTo(float x, float y)
{
position = love::Vector(x, y);
}
void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y) void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y)
{ {
areaSpread = love::Vector(x, y); areaSpread = love::Vector(x, y);
@@ -790,7 +796,7 @@ bool ParticleSystem::isFull() const
return activeParticles == maxParticles; return activeParticles == maxParticles;
} }
void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
uint32 pCount = getCount(); uint32 pCount = getCount();
if (pCount == 0 || texture == nullptr || pMem == nullptr || particleVerts == nullptr) if (pCount == 0 || texture == nullptr || pMem == nullptr || particleVerts == nullptr)
@@ -132,12 +132,12 @@ public:
* Sets the emission rate. * Sets the emission rate.
* @param rate The amount of particles per second. * @param rate The amount of particles per second.
**/ **/
void setEmissionRate(int rate); void setEmissionRate(float rate);
/** /**
* Returns the number of particles created per second. * Returns the number of particles created per second.
**/ **/
int getEmissionRate() const; float getEmissionRate() const;
/** /**
* Sets the lifetime of the particle emitter (-1 means eternal) * Sets the lifetime of the particle emitter (-1 means eternal)
@@ -177,6 +177,15 @@ public:
**/ **/
const love::Vector &getPosition() const; const love::Vector &getPosition() const;
/**
* Moves the position of the center of the emitter.
* When update is called, newly spawned particles will appear in a line
* between the old emitter position and where the emitter was moved to,
* resulting in a smoother-feeling particle system if moveTo is called
* repeatedly.
**/
void moveTo(float x, float y);
/** /**
* Sets the emission area spread parameters and distribution type. The interpretation of * Sets the emission area spread parameters and distribution type. The interpretation of
* the parameters depends on the distribution type: * the parameters depends on the distribution type:
@@ -471,7 +480,7 @@ public:
* @param x The x-coordinate. * @param x The x-coordinate.
* @param y The y-coordinate. * @param y The y-coordinate.
**/ **/
virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
/** /**
* Updates the particle system. * Updates the particle system.
@@ -551,7 +560,7 @@ protected:
uint32 activeParticles; uint32 activeParticles;
// The emission rate (particles/sec). // The emission rate (particles/sec).
int emissionRate; float emissionRate;
// Used to determine when a particle should be emitted. // Used to determine when a particle should be emitted.
float emitCounter; float emitCounter;
@@ -75,6 +75,7 @@ Shader::Shader(const ShaderSources &sources)
, builtinUniforms() , builtinUniforms()
, vertexAttributes() , vertexAttributes()
, lastCanvas((Canvas *) -1) , lastCanvas((Canvas *) -1)
, lastViewport()
{ {
if (shaderSources.empty()) if (shaderSources.empty())
throw love::Exception("Cannot create shader: no source code!"); throw love::Exception("Cannot create shader: no source code!");
@@ -753,30 +754,42 @@ bool Shader::sendBuiltinMatrix(BuiltinExtern builtin, int size, const GLfloat *m
void Shader::checkSetScreenParams() void Shader::checkSetScreenParams()
{ {
if (lastCanvas == Canvas::current) OpenGL::Viewport view = gl.getViewport();
if (view == lastViewport && lastCanvas == Canvas::current)
return; return;
// In the shader, we do pixcoord.y = gl_FragCoord.y * params[0] + params[1]. // In the shader, we do pixcoord.y = gl_FragCoord.y * params.z + params.w.
// This lets us flip pixcoord.y when needed, to be consistent (Canvases // This lets us flip pixcoord.y when needed, to be consistent (Canvases
// have flipped y-values for pixel coordinates.) // have flipped y-values for pixel coordinates.)
GLfloat params[] = {0.0f, 0.0f}; GLfloat params[] = {
(GLfloat) view.w, (GLfloat) view.h,
0.0f, 0.0f,
};
if (Canvas::current != nullptr) if (Canvas::current != nullptr)
{ {
// gl_FragCoord.y is flipped in Canvases, so we un-flip: // gl_FragCoord.y is flipped in Canvases, so we un-flip:
// pixcoord.y = gl_FragCoord.y * -1.0 + height. // pixcoord.y = gl_FragCoord.y * -1.0 + height.
params[0] = -1.0f; params[2] = -1.0f;
params[1] = (float) Canvas::current->getHeight(); params[3] = (GLfloat) view.h;
} }
else else
{ {
// No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0. // No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0.
params[0] = 1.0f; params[2] = 1.0f;
params[1] = 0.0f; params[3] = 0.0f;
} }
sendBuiltinFloat(BUILTIN_SCREEN_PARAMS, 2, params, 1); sendBuiltinFloat(BUILTIN_SCREEN_SIZE, 4, params, 1);
lastCanvas = Canvas::current; lastCanvas = Canvas::current;
lastViewport = view;
}
const std::map<std::string, Object *> &Shader::getBoundRetainables() const
{
return boundRetainables;
} }
std::string Shader::getGLSLVersion() std::string Shader::getGLSLVersion()
@@ -829,7 +842,7 @@ StringMap<Shader::BuiltinExtern, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builti
{"ProjectionMatrix", Shader::BUILTIN_PROJECTION_MATRIX}, {"ProjectionMatrix", Shader::BUILTIN_PROJECTION_MATRIX},
{"TransformProjectionMatrix", Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX}, {"TransformProjectionMatrix", Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX},
{"love_PointSize", Shader::BUILTIN_POINT_SIZE}, {"love_PointSize", Shader::BUILTIN_POINT_SIZE},
{"love_ScreenParams", Shader::BUILTIN_SCREEN_PARAMS}, {"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE},
}; };
StringMap<Shader::BuiltinExtern, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries)); StringMap<Shader::BuiltinExtern, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries));
@@ -67,7 +67,7 @@ public:
BUILTIN_PROJECTION_MATRIX, BUILTIN_PROJECTION_MATRIX,
BUILTIN_TRANSFORM_PROJECTION_MATRIX, BUILTIN_TRANSFORM_PROJECTION_MATRIX,
BUILTIN_POINT_SIZE, BUILTIN_POINT_SIZE,
BUILTIN_SCREEN_PARAMS, BUILTIN_SCREEN_SIZE,
BUILTIN_MAX_ENUM BUILTIN_MAX_ENUM
}; };
@@ -152,6 +152,8 @@ public:
bool sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *m, int count); bool sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *m, int count);
void checkSetScreenParams(); void checkSetScreenParams();
const std::map<std::string, Object *> &getBoundRetainables() const;
static std::string getGLSLVersion(); static std::string getGLSLVersion();
static bool isSupported(); static bool isSupported();
@@ -227,6 +229,7 @@ private:
// Pointer to the active Canvas when the screen params were last checked. // Pointer to the active Canvas when the screen params were last checked.
Canvas *lastCanvas; Canvas *lastCanvas;
OpenGL::Viewport lastViewport;
// Max GPU texture units available for sent images // Max GPU texture units available for sent images
static GLint maxTexUnits; static GLint maxTexUnits;
@@ -263,7 +263,7 @@ int SpriteBatch::getBufferSize() const
return size; return size;
} }
void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{ {
const size_t vertex_offset = offsetof(Vertex, x); const size_t vertex_offset = offsetof(Vertex, x);
const size_t texel_offset = offsetof(Vertex, s); const size_t texel_offset = offsetof(Vertex, s);
@@ -109,7 +109,7 @@ public:
int getBufferSize() const; int getBufferSize() const;
// Implements Drawable. // Implements Drawable.
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const; void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
static bool getConstant(const char *in, UsageHint &out); static bool getConstant(const char *in, UsageHint &out);
static bool getConstant(UsageHint in, const char *&out); static bool getConstant(UsageHint in, const char *&out);
@@ -48,12 +48,12 @@ public:
* Any setup the texture might need to do before drawing, e.g. binding * Any setup the texture might need to do before drawing, e.g. binding
* the OpenGL texture for use. * the OpenGL texture for use.
**/ **/
virtual void predraw() const {} virtual void predraw() {}
/** /**
* Any cleanup the texture might need to do directly after drawing. * Any cleanup the texture might need to do directly after drawing.
**/ **/
virtual void postdraw() const {} virtual void postdraw() {}
}; // Texture }; // Texture
@@ -120,6 +120,13 @@ int w_Canvas_getType(lua_State *L)
return 1; return 1;
} }
int w_Canvas_getFSAA(lua_State *L)
{
Canvas *canvas = luax_checkcanvas(L, 1);
lua_pushinteger(L, canvas->getFSAA());
return 1;
}
static const luaL_Reg functions[] = static const luaL_Reg functions[] =
{ {
// From wrap_Texture. // From wrap_Texture.
@@ -136,6 +143,7 @@ static const luaL_Reg functions[] =
{ "getPixel", w_Canvas_getPixel }, { "getPixel", w_Canvas_getPixel },
{ "clear", w_Canvas_clear }, { "clear", w_Canvas_clear },
{ "getType", w_Canvas_getType }, { "getType", w_Canvas_getType },
{ "getFSAA", w_Canvas_getFSAA },
{ 0, 0 } { 0, 0 }
}; };
@@ -40,6 +40,7 @@ int w_Canvas_getImageData(lua_State *L);
int w_Canvas_getPixel(lua_State * L); int w_Canvas_getPixel(lua_State * L);
int w_Canvas_clear(lua_State *L); int w_Canvas_clear(lua_State *L);
int w_Canvas_getType(lua_State *L); int w_Canvas_getType(lua_State *L);
int w_Canvas_getFSAA(lua_State *L);
extern "C" int luaopen_canvas(lua_State *L); extern "C" int luaopen_canvas(lua_State *L);
} // opengl } // opengl
@@ -146,7 +146,7 @@ int w_setInvertedStencil(lua_State *L)
int w_getMaxTextureSize(lua_State *L) int w_getMaxTextureSize(lua_State *L)
{ {
lua_pushinteger(L, instance->getMaxTextureSize()); lua_pushinteger(L, instance->getSystemLimit(Graphics::LIMIT_TEXTURE_SIZE));
return 1; return 1;
} }
@@ -323,15 +323,16 @@ int w_newCanvas(lua_State *L)
int width = luaL_optint(L, 1, instance->getWidth()); int width = luaL_optint(L, 1, instance->getWidth());
int height = luaL_optint(L, 2, instance->getHeight()); int height = luaL_optint(L, 2, instance->getHeight());
const char *str = luaL_optstring(L, 3, "normal"); const char *str = luaL_optstring(L, 3, "normal");
int fsaa = luaL_optint(L, 4, 0);
Canvas::TextureType texture_type; Canvas::TextureType texture_type;
if (!Canvas::getConstant(str, texture_type)) if (!Canvas::getConstant(str, texture_type))
return luaL_error(L, "Invalid canvas type: %s", str); return luaL_error(L, "Invalid canvas type: %s", str);
Canvas *canvas = 0; Canvas *canvas = nullptr;
EXCEPT_GUARD(canvas = instance->newCanvas(width, height, texture_type);) EXCEPT_GUARD(canvas = instance->newCanvas(width, height, texture_type, fsaa);)
if (canvas == 0) if (canvas == nullptr)
return luaL_error(L, "Canvas not created, but no error thrown. I don't even..."); return luaL_error(L, "Canvas not created, but no error thrown. I don't even...");
luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, canvas); luax_pushtype(L, "Canvas", GRAPHICS_CANVAS_T, canvas);
@@ -830,7 +831,7 @@ int w_getPointStyle(lua_State *L)
int w_getMaxPointSize(lua_State *L) int w_getMaxPointSize(lua_State *L)
{ {
lua_pushnumber(L, instance->getMaxPointSize()); lua_pushnumber(L, instance->getSystemLimit(Graphics::LIMIT_POINT_SIZE));
return 1; return 1;
} }
@@ -1025,7 +1026,7 @@ int w_isSupported(lua_State *L)
supported = false; supported = false;
break; break;
case Graphics::SUPPORT_INSTANCING: case Graphics::SUPPORT_INSTANCING:
if (!GLAD_ARB_draw_instanced) if (!(GLAD_ARB_draw_instanced || (GLAD_ES_VERSION_2_0 && GLAD_EXT_draw_instanced)))
supported = false; supported = false;
break; break;
default: default:
@@ -1055,6 +1056,18 @@ int w_getRendererInfo(lua_State *L)
return 4; return 4;
} }
int w_getSystemLimit(lua_State *L)
{
const char *limitstr = luaL_checkstring(L, 1);
Graphics::SystemLimit limittype;
if (!Graphics::getConstant(limitstr, limittype))
return luaL_error(L, "Invalid system limit type: %s", limitstr);
lua_pushnumber(L, instance->getSystemLimit(limittype));
return 1;
}
int w_draw(lua_State *L) int w_draw(lua_State *L)
{ {
Drawable *drawable = nullptr; Drawable *drawable = nullptr;
@@ -1392,8 +1405,6 @@ static const luaL_Reg functions[] =
{ "setPointStyle", w_setPointStyle }, { "setPointStyle", w_setPointStyle },
{ "getPointSize", w_getPointSize }, { "getPointSize", w_getPointSize },
{ "getPointStyle", w_getPointStyle }, { "getPointStyle", w_getPointStyle },
{ "getMaxPointSize", w_getMaxPointSize },
{ "getMaxTextureSize", w_getMaxTextureSize },
{ "newScreenshot", w_newScreenshot }, { "newScreenshot", w_newScreenshot },
{ "setCanvas", w_setCanvas }, { "setCanvas", w_setCanvas },
{ "getCanvas", w_getCanvas }, { "getCanvas", w_getCanvas },
@@ -1404,6 +1415,7 @@ static const luaL_Reg functions[] =
{ "isSupported", w_isSupported }, { "isSupported", w_isSupported },
{ "getRendererInfo", w_getRendererInfo }, { "getRendererInfo", w_getRendererInfo },
{ "getSystemLimit", w_getSystemLimit },
{ "draw", w_draw }, { "draw", w_draw },
@@ -1439,6 +1451,7 @@ static const luaL_Reg functions[] =
// Deprecated since 0.9.1. // Deprecated since 0.9.1.
{ "getMaxImageSize", w_getMaxTextureSize }, { "getMaxImageSize", w_getMaxTextureSize },
{ "getMaxPointSize", w_getMaxPointSize },
{ 0, 0 } { 0, 0 }
}; };
@@ -93,6 +93,7 @@ int w_getShader(lua_State *L);
int w_setDefaultShaderCode(lua_State *L); int w_setDefaultShaderCode(lua_State *L);
int w_isSupported(lua_State *L); int w_isSupported(lua_State *L);
int w_getRendererInfo(lua_State *L); int w_getRendererInfo(lua_State *L);
int w_getSystemLimit(lua_State *L);
int w_draw(lua_State *L); int w_draw(lua_State *L);
int w_print(lua_State *L); int w_print(lua_State *L);
int w_printf(lua_State *L); int w_printf(lua_State *L);
@@ -127,7 +127,7 @@ int w_ParticleSystem_getInsertMode(lua_State *L)
int w_ParticleSystem_setEmissionRate(lua_State *L) int w_ParticleSystem_setEmissionRate(lua_State *L)
{ {
ParticleSystem *t = luax_checkparticlesystem(L, 1); ParticleSystem *t = luax_checkparticlesystem(L, 1);
int arg1 = luaL_checkint(L, 2); float arg1 = (float) luaL_checknumber(L, 2);
EXCEPT_GUARD(t->setEmissionRate(arg1);) EXCEPT_GUARD(t->setEmissionRate(arg1);)
return 0; return 0;
} }
@@ -135,7 +135,7 @@ int w_ParticleSystem_setEmissionRate(lua_State *L)
int w_ParticleSystem_getEmissionRate(lua_State *L) int w_ParticleSystem_getEmissionRate(lua_State *L)
{ {
ParticleSystem *t = luax_checkparticlesystem(L, 1); ParticleSystem *t = luax_checkparticlesystem(L, 1);
lua_pushinteger(L, t->getEmissionRate()); lua_pushnumber(L, t->getEmissionRate());
return 1; return 1;
} }
@@ -191,6 +191,15 @@ int w_ParticleSystem_getPosition(lua_State *L)
return 2; return 2;
} }
int w_ParticleSystem_moveTo(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
float arg1 = (float)luaL_checknumber(L, 2);
float arg2 = (float)luaL_checknumber(L, 3);
t->moveTo(arg1, arg2);
return 0;
}
int w_ParticleSystem_setAreaSpread(lua_State *L) int w_ParticleSystem_setAreaSpread(lua_State *L)
{ {
ParticleSystem *t = luax_checkparticlesystem(L, 1); ParticleSystem *t = luax_checkparticlesystem(L, 1);
@@ -649,6 +658,7 @@ static const luaL_Reg functions[] =
{ "getParticleLifetime", w_ParticleSystem_getParticleLifetime }, { "getParticleLifetime", w_ParticleSystem_getParticleLifetime },
{ "setPosition", w_ParticleSystem_setPosition }, { "setPosition", w_ParticleSystem_setPosition },
{ "getPosition", w_ParticleSystem_getPosition }, { "getPosition", w_ParticleSystem_getPosition },
{ "moveTo", w_ParticleSystem_moveTo },
{ "setAreaSpread", w_ParticleSystem_setAreaSpread }, { "setAreaSpread", w_ParticleSystem_setAreaSpread },
{ "getAreaSpread", w_ParticleSystem_getAreaSpread }, { "getAreaSpread", w_ParticleSystem_getAreaSpread },
{ "setDirection", w_ParticleSystem_setDirection }, { "setDirection", w_ParticleSystem_setDirection },
@@ -48,6 +48,7 @@ int w_ParticleSystem_setParticleLifetime(lua_State *L);
int w_ParticleSystem_getParticleLifetime(lua_State *L); int w_ParticleSystem_getParticleLifetime(lua_State *L);
int w_ParticleSystem_setPosition(lua_State *L); int w_ParticleSystem_setPosition(lua_State *L);
int w_ParticleSystem_getPosition(lua_State *L); int w_ParticleSystem_getPosition(lua_State *L);
int w_ParticleSystem_moveTo(lua_State *L);
int w_ParticleSystem_setAreaSpread(lua_State *L); int w_ParticleSystem_setAreaSpread(lua_State *L);
int w_ParticleSystem_getAreaSpread(lua_State *L); int w_ParticleSystem_getAreaSpread(lua_State *L);
int w_ParticleSystem_setDirection(lua_State *L); int w_ParticleSystem_setDirection(lua_State *L);
+12
View File
@@ -182,6 +182,15 @@ const char *love_codename()
return love::VERSION_CODENAME; return love::VERSION_CODENAME;
} }
static int w_love_getVersion(lua_State *L)
{
lua_pushinteger(L, love::VERSION_MAJOR);
lua_pushinteger(L, love::VERSION_MINOR);
lua_pushinteger(L, love::VERSION_REV);
lua_pushstring(L, love::VERSION_CODENAME);
return 4;
}
int luaopen_love(lua_State * L) int luaopen_love(lua_State * L)
{ {
love::luax_insistglobal(L, "love"); love::luax_insistglobal(L, "love");
@@ -215,6 +224,9 @@ int luaopen_love(lua_State * L)
lua_setfield(L, -2, "_version_compat"); lua_setfield(L, -2, "_version_compat");
lua_pushcfunction(L, w_love_getVersion);
lua_setfield(L, -2, "getVersion");
#ifdef LOVE_WINDOWS #ifdef LOVE_WINDOWS
lua_pushstring(L, "Windows"); lua_pushstring(L, "Windows");
#elif defined(LOVE_MACOSX) #elif defined(LOVE_MACOSX)
+29 -2
View File
@@ -257,6 +257,18 @@ bool Window::setContext(int fsaa, bool vsync)
context = SDL_GL_CreateContext(window); context = SDL_GL_CreateContext(window);
} }
if (!context)
{
int flags = 0;
SDL_GL_GetAttribute(SDL_GL_CONTEXT_FLAGS, &flags);
if (flags & SDL_GL_CONTEXT_DEBUG_FLAG)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
context = SDL_GL_CreateContext(window);
}
}
if (!context) if (!context)
{ {
displayError("Could not create OpenGL context", SDL_GetError()); displayError("Could not create OpenGL context", SDL_GetError());
@@ -299,6 +311,8 @@ void Window::setWindowGLAttributes(int fsaa) const
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0);
int contextprofile = 0;
bool tryES2 = false; bool tryES2 = false;
const char *driver = SDL_GetCurrentVideoDriver(); const char *driver = SDL_GetCurrentVideoDriver();
@@ -314,17 +328,30 @@ void Window::setWindowGLAttributes(int fsaa) const
if (tryES2) if (tryES2)
{ {
// Use OpenGL ES 2+. // Use OpenGL ES 2+.
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); contextprofile = SDL_GL_CONTEXT_PROFILE_ES;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
} }
else else
{ {
// Use desktop OpenGL. // Use desktop OpenGL.
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); contextprofile = 0;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); // default SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); // default
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
} }
// Do we want a debug context?
const char *debugenv = SDL_GetHint("LOVE_GRAPHICS_DEBUG");
if (debugenv && *debugenv == '1')
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
if (!tryES2)
contextprofile |= SDL_GL_CONTEXT_PROFILE_COMPATIBILITY;
}
else
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, contextprofile);
} }
void Window::updateSettings(const WindowSettings &newsettings) void Window::updateSettings(const WindowSettings &newsettings)
+10 -7
View File
@@ -179,6 +179,9 @@ function love.createhandlers()
touchmoved = function (id,x,y,p) touchmoved = function (id,x,y,p)
if love.touchmoved then return love.touchmoved(id,x,y,p) end if love.touchmoved then return love.touchmoved(id,x,y,p) end
end, end,
touchgestured = function (x,y,theta,dist,num)
if love.touchgestured then return love.touchgestured(x,y,theta,dist,num) end
end,
joystickpressed = function (j,b) joystickpressed = function (j,b)
if love.joystickpressed then return love.joystickpressed(j,b) end if love.joystickpressed then return love.joystickpressed(j,b) end
end, end,
@@ -354,6 +357,11 @@ function love.init()
c.console = true c.console = true
end end
-- Console hack
if c.console and love._openConsole then
love._openConsole()
end
-- Gets desired modules. -- Gets desired modules.
for k,v in ipairs{ for k,v in ipairs{
"android", "android",
@@ -383,11 +391,6 @@ function love.init()
love.createhandlers() love.createhandlers()
end end
-- Console hack
if c.console and love._openConsole then
love._openConsole()
end
-- Setup window here. -- Setup window here.
if c.window and c.modules.window then if c.window and c.modules.window then
assert(love.window.setMode(c.window.width, c.window.height, assert(love.window.setMode(c.window.width, c.window.height,
@@ -488,7 +491,7 @@ function love.run()
-- Process events. -- Process events.
if love.event then if love.event then
love.event.pump() love.event.pump()
for n,a,b,c,d in love.event.poll() do for n,a,b,c,d,e in love.event.poll() do
if n == "quit" then if n == "quit" then
if not love.quit or not love.quit() then if not love.quit or not love.quit() then
if love.audio then if love.audio then
@@ -497,7 +500,7 @@ function love.run()
return return
end end
end end
love.handlers[n](a,b,c,d) love.handlers[n](a,b,c,d,e)
end end
end end
+20 -11
View File
@@ -319,6 +319,15 @@ const unsigned char boot_lua[] =
0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x69, 0x64, 0x2c, 0x78, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x69, 0x64, 0x2c, 0x78,
0x2c, 0x79, 0x2c, 0x70, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x2c, 0x79, 0x2c, 0x70, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
0x09, 0x09, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x67, 0x65, 0x73, 0x74, 0x75, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x74, 0x68, 0x65, 0x74,
0x61, 0x2c, 0x64, 0x69, 0x73, 0x74, 0x2c, 0x6e, 0x75, 0x6d, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x67, 0x65,
0x73, 0x74, 0x75, 0x72, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x67, 0x65, 0x73, 0x74, 0x75, 0x72, 0x65,
0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x74, 0x68, 0x65, 0x74, 0x61, 0x2c, 0x64, 0x69, 0x73, 0x74, 0x2c, 0x6e,
0x75, 0x6d, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20,
0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63,
@@ -625,6 +634,13 @@ const unsigned char boot_lua[] =
0x6e, 0x0a, 0x6e, 0x0a,
0x09, 0x09, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x09, 0x09, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x68, 0x61, 0x63, 0x6b, 0x0a,
0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20,
0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20,
0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c,
0x65, 0x28, 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, 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, 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, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73,
@@ -658,13 +674,6 @@ const unsigned char boot_lua[] =
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x68, 0x61, 0x6e, 0x64, 0x6c,
0x65, 0x72, 0x73, 0x28, 0x29, 0x0a, 0x65, 0x72, 0x73, 0x28, 0x29, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x2d, 0x2d, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x68, 0x61, 0x63, 0x6b, 0x0a,
0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20,
0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x20,
0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x6f, 0x6c,
0x65, 0x28, 0x29, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x2d, 0x2d, 0x20, 0x53, 0x65, 0x74, 0x75, 0x70, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x68, 0x09, 0x2d, 0x2d, 0x20, 0x53, 0x65, 0x74, 0x75, 0x70, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x68,
0x65, 0x72, 0x65, 0x2e, 0x0a, 0x65, 0x72, 0x65, 0x2e, 0x0a,
0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63,
@@ -863,9 +872,9 @@ const unsigned char boot_lua[] =
0x65, 0x6e, 0x0a, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70,
0x28, 0x29, 0x0a, 0x28, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x2c, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x20, 0x69, 0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x2c, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x2c, 0x65,
0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c, 0x6c, 0x28, 0x20, 0x69, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c,
0x29, 0x20, 0x64, 0x6f, 0x0a, 0x6c, 0x28, 0x29, 0x20, 0x64, 0x6f, 0x0a,
0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x75, 0x69, 0x74, 0x22, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x75, 0x69, 0x74, 0x22,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x71, 0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x71,
@@ -880,7 +889,7 @@ const unsigned char boot_lua[] =
0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b, 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x5b,
0x6e, 0x5d, 0x28, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x29, 0x0a, 0x6e, 0x5d, 0x28, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x2c, 0x64, 0x2c, 0x65, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x2d, 0x2d, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x64, 0x74, 0x2c, 0x20, 0x61, 0x73, 0x09, 0x09, 0x2d, 0x2d, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x64, 0x74, 0x2c, 0x20, 0x61, 0x73,
+4 -4
View File
@@ -1310,7 +1310,7 @@ do
#define TransformProjectionMatrix gl_ModelViewProjectionMatrix #define TransformProjectionMatrix gl_ModelViewProjectionMatrix
#define NormalMatrix gl_NormalMatrix #define NormalMatrix gl_NormalMatrix
uniform sampler2D _tex0_; uniform sampler2D _tex0_;
uniform vec2 love_ScreenParams;]] uniform vec4 love_ScreenSize;]]
GLSLES.UNIFORMS = [[ GLSLES.UNIFORMS = [[
uniform mat4 TransformMatrix; uniform mat4 TransformMatrix;
@@ -1319,7 +1319,7 @@ uniform mat4 TransformProjectionMatrix;
// uniform mat4 NormalMatrix; // uniform mat4 NormalMatrix;
uniform float love_PointSize; uniform float love_PointSize;
uniform sampler2D _tex0_; uniform sampler2D _tex0_;
uniform vec2 love_ScreenParams;]] uniform vec4 love_ScreenSize;]]
GLSL.VERTEX = { GLSL.VERTEX = {
HEADER = [[ HEADER = [[
@@ -1390,7 +1390,7 @@ void main() {
float dummy = texture2D(_tex0_, vec2(.5)).r; float dummy = texture2D(_tex0_, vec2(.5)).r;
// See Shader::checkSetScreenParams in Shader.cpp. // See Shader::checkSetScreenParams in Shader.cpp.
vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenParams[0]) + love_ScreenParams[1]); vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w);
gl_FragColor = effect(VaryingColor, _tex0_, VaryingTexCoord.st, pixelcoord); gl_FragColor = effect(VaryingColor, _tex0_, VaryingTexCoord.st, pixelcoord);
}]], }]],
@@ -1401,7 +1401,7 @@ void main() {
float dummy = texture2D(_tex0_, vec2(.5)).r; float dummy = texture2D(_tex0_, vec2(.5)).r;
// See Shader::checkSetScreenParams in Shader.cpp. // See Shader::checkSetScreenParams in Shader.cpp.
vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenParams[0]) + love_ScreenParams[1]); vec2 pixelcoord = vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w);
effects(VaryingColor, _tex0_, VaryingTexCoord.st, pixelcoord); effects(VaryingColor, _tex0_, VaryingTexCoord.st, pixelcoord);
}]], }]],
+10 -10
View File
@@ -6299,8 +6299,8 @@ const unsigned char graphics_lua[] =
0x69, 0x78, 0x20, 0x67, 0x6c, 0x5f, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x0a, 0x69, 0x78, 0x20, 0x67, 0x6c, 0x5f, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x0a,
0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20,
0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x3b, 0x0a, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x3b, 0x0a,
0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f,
0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3b, 0x5d, 0x5d, 0x0a, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x53, 0x69, 0x7a, 0x65, 0x3b, 0x5d, 0x5d, 0x0a,
0x09, 0x47, 0x4c, 0x53, 0x4c, 0x45, 0x53, 0x2e, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x20, 0x3d, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x45, 0x53, 0x2e, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x20, 0x3d,
0x20, 0x5b, 0x5b, 0x0a, 0x20, 0x5b, 0x5b, 0x0a,
0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73,
@@ -6316,8 +6316,8 @@ const unsigned char graphics_lua[] =
0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x3b, 0x0a, 0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x3b, 0x0a,
0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20,
0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x3b, 0x0a, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x3b, 0x0a,
0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f,
0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3b, 0x5d, 0x5d, 0x0a, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x53, 0x69, 0x7a, 0x65, 0x3b, 0x5d, 0x5d, 0x0a,
0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x20, 0x3d, 0x20, 0x7b, 0x0a,
0x09, 0x09, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x09, 0x09, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x0a,
@@ -6429,9 +6429,9 @@ const unsigned char graphics_lua[] =
0x09, 0x76, 0x65, 0x63, 0x32, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, 0x09, 0x76, 0x65, 0x63, 0x32, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d,
0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64,
0x2e, 0x78, 0x2c, 0x20, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x2e, 0x78, 0x2c, 0x20, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e,
0x79, 0x20, 0x2a, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x79, 0x20, 0x2a, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x53, 0x69, 0x7a,
0x61, 0x6d, 0x73, 0x5b, 0x30, 0x5d, 0x29, 0x20, 0x2b, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x2e, 0x7a, 0x29, 0x20, 0x2b, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e,
0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x5b, 0x31, 0x5d, 0x29, 0x3b, 0x0a, 0x53, 0x69, 0x7a, 0x65, 0x2e, 0x77, 0x29, 0x3b, 0x0a,
0x09, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x65, 0x66, 0x09, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x65, 0x66,
0x66, 0x65, 0x63, 0x74, 0x28, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x66, 0x65, 0x63, 0x74, 0x28, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2c,
0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65,
@@ -6454,9 +6454,9 @@ const unsigned char graphics_lua[] =
0x09, 0x76, 0x65, 0x63, 0x32, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, 0x09, 0x76, 0x65, 0x63, 0x32, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d,
0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64,
0x2e, 0x78, 0x2c, 0x20, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x2e, 0x78, 0x2c, 0x20, 0x28, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e,
0x79, 0x20, 0x2a, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x79, 0x20, 0x2a, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x53, 0x69, 0x7a,
0x61, 0x6d, 0x73, 0x5b, 0x30, 0x5d, 0x29, 0x20, 0x2b, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x2e, 0x7a, 0x29, 0x20, 0x2b, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e,
0x65, 0x65, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x5b, 0x31, 0x5d, 0x29, 0x3b, 0x0a, 0x53, 0x69, 0x7a, 0x65, 0x2e, 0x77, 0x29, 0x3b, 0x0a,
0x09, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x28, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x09, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x28, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f,
0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69,
0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x73, 0x74, 0x2c, 0x20, 0x70, 0x69, 0x78, 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x73, 0x74, 0x2c, 0x20, 0x70, 0x69, 0x78,