mirror of
https://github.com/love2d/love-android.git
synced 2026-08-12 08:31:04 +02:00
updated to changeset 80f0adedfaa5 of love-android (including newest mobile-common changes)
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
#ifndef LUA_WRAP_H
|
||||
#define LUA_WRAP_H
|
||||
|
||||
#define LUA_COMPAT_ALL
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
@@ -10,3 +13,5 @@
|
||||
|
||||
extern int luax_typerror(lua_State *L, int narg, const char *type);
|
||||
#endif
|
||||
|
||||
#endif // LUA_WRAP_H
|
||||
|
||||
@@ -61,11 +61,13 @@ Pool::Pool()
|
||||
// Make all sources available initially.
|
||||
for (int i = 0; i < totalSources; i++)
|
||||
{
|
||||
#ifdef AL_SOFT_direct_channels
|
||||
if (hasext)
|
||||
{
|
||||
// Bypass virtualization of speakers for multi-channel sources in OpenAL Soft.
|
||||
alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
available.push(sources[i]);
|
||||
}
|
||||
|
||||
@@ -176,6 +176,7 @@ StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
|
||||
{ "dxt", Graphics::SUPPORT_DXT },
|
||||
{ "bc5", Graphics::SUPPORT_BC5 },
|
||||
{ "instancing", Graphics::SUPPORT_INSTANCING },
|
||||
{ "srgb", Graphics::SUPPORT_SRGB },
|
||||
};
|
||||
|
||||
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));
|
||||
|
||||
@@ -95,6 +95,7 @@ public:
|
||||
SUPPORT_DXT,
|
||||
SUPPORT_BC5,
|
||||
SUPPORT_INSTANCING,
|
||||
SUPPORT_SRGB,
|
||||
SUPPORT_MAX_ENUM
|
||||
};
|
||||
|
||||
@@ -135,7 +136,7 @@ public:
|
||||
* @param width The viewport width.
|
||||
* @param height The viewport height.
|
||||
**/
|
||||
virtual bool setMode(int width, int height) = 0;
|
||||
virtual bool setMode(int width, int height, bool &sRGB) = 0;
|
||||
|
||||
/**
|
||||
* Un-sets the current graphics display mode (uninitializing objects if
|
||||
|
||||
@@ -109,6 +109,16 @@ bool Texture::getConstant(WrapMode in, const char *&out)
|
||||
return wrapModes.find(in, out);
|
||||
}
|
||||
|
||||
bool Texture::getConstant(const char *in, Format &out)
|
||||
{
|
||||
return formats.find(in, out);
|
||||
}
|
||||
|
||||
bool Texture::getConstant(Format in, const char *&out)
|
||||
{
|
||||
return formats.find(in, out);
|
||||
}
|
||||
|
||||
StringMap<Texture::FilterMode, Texture::FILTER_MAX_ENUM>::Entry Texture::filterModeEntries[] =
|
||||
{
|
||||
{ "linear", Texture::FILTER_LINEAR },
|
||||
@@ -125,6 +135,15 @@ StringMap<Texture::WrapMode, Texture::WRAP_MAX_ENUM>::Entry Texture::wrapModeEnt
|
||||
|
||||
StringMap<Texture::WrapMode, Texture::WRAP_MAX_ENUM> Texture::wrapModes(Texture::wrapModeEntries, sizeof(Texture::wrapModeEntries));
|
||||
|
||||
StringMap<Texture::Format, Texture::FORMAT_MAX_ENUM>::Entry Texture::formatEntries[] =
|
||||
{
|
||||
{"normal", Texture::FORMAT_NORMAL},
|
||||
{"hdr", Texture::FORMAT_HDR},
|
||||
{"srgb", Texture::FORMAT_SRGB},
|
||||
};
|
||||
|
||||
StringMap<Texture::Format, Texture::FORMAT_MAX_ENUM> Texture::formats(Texture::formatEntries, sizeof(Texture::formatEntries));
|
||||
|
||||
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -55,6 +55,14 @@ public:
|
||||
FILTER_MAX_ENUM
|
||||
};
|
||||
|
||||
enum Format
|
||||
{
|
||||
FORMAT_NORMAL,
|
||||
FORMAT_HDR,
|
||||
FORMAT_SRGB,
|
||||
FORMAT_MAX_ENUM
|
||||
};
|
||||
|
||||
struct Filter
|
||||
{
|
||||
Filter();
|
||||
@@ -111,6 +119,9 @@ public:
|
||||
static bool getConstant(const char *in, WrapMode &out);
|
||||
static bool getConstant(WrapMode in, const char *&out);
|
||||
|
||||
static bool getConstant(const char *in, Format &out);
|
||||
static bool getConstant(Format in, const char *&out);
|
||||
|
||||
protected:
|
||||
|
||||
int width;
|
||||
@@ -132,6 +143,9 @@ private:
|
||||
static StringMap<WrapMode, WRAP_MAX_ENUM>::Entry wrapModeEntries[];
|
||||
static StringMap<WrapMode, WRAP_MAX_ENUM> wrapModes;
|
||||
|
||||
static StringMap<Format, FORMAT_MAX_ENUM>::Entry formatEntries[];
|
||||
static StringMap<Format, FORMAT_MAX_ENUM> formats;
|
||||
|
||||
}; // Texture
|
||||
|
||||
} // graphics
|
||||
|
||||
@@ -389,7 +389,7 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT
|
||||
}
|
||||
};
|
||||
|
||||
FramebufferStrategy *strategy = NULL;
|
||||
FramebufferStrategy *strategy = nullptr;
|
||||
|
||||
FramebufferStrategy strategyNone;
|
||||
|
||||
@@ -401,8 +401,9 @@ FramebufferStrategyPackedEXT strategyPackedEXT;
|
||||
|
||||
FramebufferStrategyEXT strategyEXT;
|
||||
|
||||
Canvas *Canvas::current = NULL;
|
||||
Canvas *Canvas::current = nullptr;
|
||||
OpenGL::Viewport Canvas::systemViewport = OpenGL::Viewport();
|
||||
bool Canvas::screenHasSRGB = false;
|
||||
|
||||
static void getStrategy()
|
||||
{
|
||||
@@ -421,16 +422,13 @@ static void getStrategy()
|
||||
}
|
||||
}
|
||||
|
||||
static int maxFBOColorAttachments = 0;
|
||||
static int maxDrawBuffers = 0;
|
||||
|
||||
Canvas::Canvas(int width, int height, TextureType texture_type, int fsaa)
|
||||
Canvas::Canvas(int width, int height, Texture::Format format, int fsaa)
|
||||
: fbo(0)
|
||||
, resolve_fbo(0)
|
||||
, texture(0)
|
||||
, fsaa_buffer(0)
|
||||
, depth_stencil(0)
|
||||
, texture_type(texture_type)
|
||||
, format(format)
|
||||
, fsaa_samples(fsaa)
|
||||
, fsaa_dirty(false)
|
||||
{
|
||||
@@ -534,15 +532,19 @@ bool Canvas::loadVolatile()
|
||||
|
||||
GLint internalformat;
|
||||
GLenum textype;
|
||||
switch (texture_type)
|
||||
switch (format)
|
||||
{
|
||||
case TYPE_HDR:
|
||||
case Texture::FORMAT_HDR:
|
||||
internalformat = GL_RGBA16F;
|
||||
textype = GL_FLOAT;
|
||||
break;
|
||||
case TYPE_NORMAL:
|
||||
case Texture::FORMAT_SRGB:
|
||||
internalformat = GL_SRGB_ALPHA;
|
||||
textype = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case Texture::FORMAT_NORMAL:
|
||||
default:
|
||||
internalformat = GL_RGBA8;
|
||||
internalformat = GL_RGBA;
|
||||
textype = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
|
||||
@@ -682,20 +684,30 @@ void Canvas::setupGrab()
|
||||
if (current == this)
|
||||
return;
|
||||
|
||||
// cleanup after previous fbo
|
||||
if (current != NULL)
|
||||
current->stopGrab();
|
||||
// cleanup after previous Canvas
|
||||
if (current != nullptr)
|
||||
{
|
||||
systemViewport = current->systemViewport;
|
||||
current->stopGrab(true);
|
||||
}
|
||||
else
|
||||
systemViewport = gl.getViewport();
|
||||
|
||||
// indicate we are using this Canvas.
|
||||
current = this;
|
||||
|
||||
// bind the framebuffer object.
|
||||
systemViewport = gl.getViewport();
|
||||
strategy->bindFBO(fbo);
|
||||
gl.setViewport(OpenGL::Viewport(0, 0, width, height));
|
||||
|
||||
// Set up orthographic view (no depth)
|
||||
gl.matrices.projection.push(Matrix::ortho(0.0, width, 0.0, height));
|
||||
|
||||
// indicate we are using this fbo
|
||||
current = this;
|
||||
// Make sure the correct sRGB setting is used when drawing to the canvas.
|
||||
if (format == FORMAT_SRGB)
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
else if (screenHasSRGB)
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
|
||||
if (fsaa_buffer != 0)
|
||||
fsaa_dirty = true;
|
||||
@@ -712,7 +724,7 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
|
||||
if (!isMultiCanvasSupported())
|
||||
throw love::Exception("Multi-canvas rendering is not supported on this system.");
|
||||
|
||||
if (canvases.size()+1 > size_t(maxDrawBuffers) || canvases.size()+1 > size_t(maxFBOColorAttachments))
|
||||
if ((int) canvases.size() + 1 > gl.getMaxRenderTargets())
|
||||
throw love::Exception("This system can't simultaniously render to %d canvases.", canvases.size()+1);
|
||||
|
||||
if (fsaa_samples != 0)
|
||||
@@ -724,8 +736,8 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
|
||||
if (canvases[i]->getWidth() != width || canvases[i]->getHeight() != height)
|
||||
throw love::Exception("All canvas arguments must have the same dimensions.");
|
||||
|
||||
if (canvases[i]->getTextureType() != texture_type)
|
||||
throw love::Exception("All canvas arguments must have the same texture type.");
|
||||
if (canvases[i]->getTextureFormat() != format)
|
||||
throw love::Exception("All canvas arguments must have the same texture format.");
|
||||
|
||||
if (canvases[i]->getFSAA() != 0)
|
||||
throw love::Exception("Multi-canvas rendering is not supported with FSAA.");
|
||||
@@ -769,7 +781,7 @@ void Canvas::startGrab()
|
||||
attachedCanvases.clear();
|
||||
}
|
||||
|
||||
void Canvas::stopGrab()
|
||||
void Canvas::stopGrab(bool switchingToOtherCanvas)
|
||||
{
|
||||
// i am not grabbing. leave me alone
|
||||
if (current != this)
|
||||
@@ -782,13 +794,25 @@ void Canvas::stopGrab()
|
||||
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 2, attachments);
|
||||
}
|
||||
|
||||
// bind default
|
||||
strategy->bindFBO(gl.getDefaultFBO());
|
||||
if (switchingToOtherCanvas)
|
||||
{
|
||||
if (format == FORMAT_SRGB)
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
else
|
||||
{
|
||||
// bind the default framebuffer.
|
||||
strategy->bindFBO(gl.getDefaultFBO());
|
||||
current = nullptr;
|
||||
gl.setViewport(systemViewport);
|
||||
|
||||
if (format == FORMAT_SRGB && !screenHasSRGB)
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
else if (format != FORMAT_SRGB && screenHasSRGB)
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
|
||||
gl.matrices.projection.pop();
|
||||
|
||||
current = nullptr;
|
||||
|
||||
gl.setViewport(systemViewport);
|
||||
}
|
||||
|
||||
void Canvas::clear(Color c)
|
||||
@@ -959,6 +983,18 @@ bool Canvas::isHDRSupported()
|
||||
return GLAD_VERSION_3_0 || (isSupported() && GLAD_ARB_texture_float);
|
||||
}
|
||||
|
||||
bool Canvas::isSRGBSupported()
|
||||
{
|
||||
if (GLAD_VERSION_3_0)
|
||||
return true;
|
||||
|
||||
if (!isSupported())
|
||||
return false;
|
||||
|
||||
return (GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
|
||||
&& GLAD_EXT_texture_sRGB;
|
||||
}
|
||||
|
||||
bool Canvas::isMultiCanvasSupported()
|
||||
{
|
||||
// system must support at least 4 simultanious active canvases.
|
||||
@@ -971,23 +1007,6 @@ void Canvas::bindDefaultCanvas()
|
||||
current->stopGrab();
|
||||
}
|
||||
|
||||
bool Canvas::getConstant(const char *in, Canvas::TextureType &out)
|
||||
{
|
||||
return textureTypes.find(in, out);
|
||||
}
|
||||
|
||||
bool Canvas::getConstant(Canvas::TextureType in, const char *&out)
|
||||
{
|
||||
return textureTypes.find(in, out);
|
||||
}
|
||||
|
||||
StringMap<Canvas::TextureType, Canvas::TYPE_MAX_ENUM>::Entry Canvas::textureTypeEntries[] =
|
||||
{
|
||||
{"normal", Canvas::TYPE_NORMAL},
|
||||
{"hdr", Canvas::TYPE_HDR},
|
||||
};
|
||||
StringMap<Canvas::TextureType, Canvas::TYPE_MAX_ENUM> Canvas::textureTypes(Canvas::textureTypeEntries, sizeof(Canvas::textureTypeEntries));
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -39,14 +39,7 @@ class Canvas : public Texture
|
||||
{
|
||||
public:
|
||||
|
||||
enum TextureType
|
||||
{
|
||||
TYPE_NORMAL,
|
||||
TYPE_HDR,
|
||||
TYPE_MAX_ENUM
|
||||
};
|
||||
|
||||
Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL, int fsaa = 0);
|
||||
Canvas(int width, int height, Texture::Format format = Texture::FORMAT_NORMAL, int fsaa = 0);
|
||||
virtual ~Canvas();
|
||||
|
||||
// Implements Volatile.
|
||||
@@ -69,7 +62,7 @@ public:
|
||||
**/
|
||||
void startGrab(const std::vector<Canvas *> &canvases);
|
||||
void startGrab();
|
||||
void stopGrab();
|
||||
void stopGrab(bool switchingToOtherCanvas = false);
|
||||
|
||||
void clear(Color c);
|
||||
|
||||
@@ -92,9 +85,9 @@ public:
|
||||
return status;
|
||||
}
|
||||
|
||||
inline TextureType getTextureType() const
|
||||
inline Texture::Format getTextureFormat() const
|
||||
{
|
||||
return texture_type;
|
||||
return format;
|
||||
}
|
||||
|
||||
inline int getFSAA() const
|
||||
@@ -106,17 +99,18 @@ public:
|
||||
|
||||
static bool isSupported();
|
||||
static bool isHDRSupported();
|
||||
static bool isSRGBSupported();
|
||||
static bool isMultiCanvasSupported();
|
||||
|
||||
static bool getConstant(const char *in, TextureType &out);
|
||||
static bool getConstant(TextureType in, const char *&out);
|
||||
|
||||
static Canvas *current;
|
||||
static void bindDefaultCanvas();
|
||||
|
||||
// The viewport dimensions of the system (default) framebuffer.
|
||||
static OpenGL::Viewport systemViewport;
|
||||
|
||||
// Whether the main screen should have linear -> sRGB conversions enabled.
|
||||
static bool screenHasSRGB;
|
||||
|
||||
private:
|
||||
|
||||
bool createFSAAFBO(GLenum internalformat);
|
||||
@@ -128,7 +122,7 @@ private:
|
||||
GLuint fsaa_buffer;
|
||||
GLuint depth_stencil;
|
||||
|
||||
TextureType texture_type;
|
||||
Format format;
|
||||
|
||||
GLenum status;
|
||||
|
||||
@@ -140,9 +134,7 @@ private:
|
||||
void setupGrab();
|
||||
void drawv(const Matrix &t, const Vertex *v);
|
||||
|
||||
static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[];
|
||||
static StringMap<TextureType, TYPE_MAX_ENUM> textureTypes;
|
||||
};
|
||||
}; // Canvas
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
|
||||
@@ -56,8 +56,13 @@ Graphics::Graphics()
|
||||
{
|
||||
currentWindow = love::window::sdl::Window::createSingleton();
|
||||
|
||||
int w, h;
|
||||
love::window::WindowSettings wsettings;
|
||||
|
||||
currentWindow->getWindow(w, h, wsettings);
|
||||
|
||||
if (currentWindow->isCreated())
|
||||
setMode(currentWindow->getWidth(), currentWindow->getHeight());
|
||||
setMode(w, h, wsettings.sRGB);
|
||||
}
|
||||
|
||||
Graphics::~Graphics()
|
||||
@@ -104,6 +109,8 @@ DisplayState Graphics::saveState()
|
||||
for (int i = 0; i < 4; i++)
|
||||
s.colorMask[i] = colorMask[i];
|
||||
|
||||
wireframe = isWireframe();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -121,6 +128,7 @@ void Graphics::restoreState(const DisplayState &s)
|
||||
else
|
||||
setScissor();
|
||||
setColorMask(s.colorMask[0], s.colorMask[1], s.colorMask[2], s.colorMask[3]);
|
||||
setWireframe(s.wireframe);
|
||||
}
|
||||
|
||||
void Graphics::setViewportSize(int width, int height)
|
||||
@@ -151,7 +159,7 @@ void Graphics::setViewportSize(int width, int height)
|
||||
c->startGrab(c->getAttachedCanvases());
|
||||
}
|
||||
|
||||
bool Graphics::setMode(int width, int height)
|
||||
bool Graphics::setMode(int width, int height, bool &sRGB)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
@@ -181,9 +189,6 @@ bool Graphics::setMode(int width, int height)
|
||||
// Enable blending
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
// "Normal" blending
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Enable all color component writes.
|
||||
setColorMask(true, true, true, true);
|
||||
|
||||
@@ -228,6 +233,19 @@ bool Graphics::setMode(int width, int height)
|
||||
Shader::defaultShader->attach();
|
||||
}
|
||||
|
||||
// Set whether drawing converts input from linear -> sRGB colorspace.
|
||||
if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
|
||||
{
|
||||
if (sRGB)
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
else
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
else
|
||||
sRGB = false;
|
||||
|
||||
Canvas::screenHasSRGB = sRGB;
|
||||
|
||||
bool enabledebug = false;
|
||||
|
||||
if (GLAD_VERSION_3_0)
|
||||
@@ -238,6 +256,8 @@ bool Graphics::setMode(int width, int height)
|
||||
enabledebug = (flags & GL_CONTEXT_FLAG_DEBUG_BIT) != 0;
|
||||
}
|
||||
|
||||
// FIXME: workaround for KHR_debug being supported but function pointers
|
||||
// resolving to null on Ouya.
|
||||
if (!GLAD_ES_VERSION_2_0)
|
||||
setDebug(enabledebug);
|
||||
|
||||
@@ -313,6 +333,9 @@ void Graphics::setDebug(bool enable)
|
||||
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);
|
||||
|
||||
if (GLAD_VERSION_4_3 || GLAD_KHR_debug)
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
|
||||
::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n");
|
||||
}
|
||||
|
||||
@@ -431,10 +454,10 @@ void Graphics::discardStencil()
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
Image *Graphics::newImage(love::image::ImageData *data)
|
||||
Image *Graphics::newImage(love::image::ImageData *data, Texture::Format format)
|
||||
{
|
||||
// Create the image.
|
||||
Image *image = new Image(data);
|
||||
Image *image = new Image(data, format);
|
||||
|
||||
if (!isCreated())
|
||||
return image;
|
||||
@@ -458,10 +481,10 @@ Image *Graphics::newImage(love::image::ImageData *data)
|
||||
return image;
|
||||
}
|
||||
|
||||
Image *Graphics::newImage(love::image::CompressedData *cdata)
|
||||
Image *Graphics::newImage(love::image::CompressedData *cdata, Texture::Format format)
|
||||
{
|
||||
// Create the image.
|
||||
Image *image = new Image(cdata);
|
||||
Image *image = new Image(cdata, format);
|
||||
|
||||
if (!isCreated())
|
||||
return image;
|
||||
@@ -505,11 +528,14 @@ ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
|
||||
return new ParticleSystem(texture, size);
|
||||
}
|
||||
|
||||
Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type, int fsaa)
|
||||
Canvas *Graphics::newCanvas(int width, int height, Texture::Format format, int fsaa)
|
||||
{
|
||||
if (texture_type == Canvas::TYPE_HDR && !Canvas::isHDRSupported())
|
||||
if (format == Texture::FORMAT_HDR && !Canvas::isHDRSupported())
|
||||
throw Exception("HDR Canvases are not supported by your OpenGL implementation");
|
||||
|
||||
if (format == Texture::FORMAT_SRGB && !Canvas::isSRGBSupported())
|
||||
throw Exception("sRGB Canvases are not supported by your OpenGL implementation");
|
||||
|
||||
if (width > gl.getMaxTextureSize())
|
||||
throw Exception("Cannot create canvas: width of %d pixels is too large for this system.", width);
|
||||
else if (height > gl.getMaxTextureSize())
|
||||
@@ -518,7 +544,7 @@ Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_t
|
||||
while (GL_NO_ERROR != glGetError())
|
||||
/* clear opengl error flag */;
|
||||
|
||||
Canvas *canvas = new Canvas(width, height, texture_type, fsaa);
|
||||
Canvas *canvas = new Canvas(width, height, format, fsaa);
|
||||
GLenum err = canvas->getStatus();
|
||||
|
||||
// everything ok, return canvas (early out)
|
||||
@@ -630,22 +656,16 @@ const bool *Graphics::getColorMask() const
|
||||
|
||||
void Graphics::setBlendMode(Graphics::BlendMode mode)
|
||||
{
|
||||
const int gl_1_4 = GLAD_VERSION_1_4;
|
||||
|
||||
GLenum func = GL_FUNC_ADD;
|
||||
GLenum src_rgb = GL_ONE;
|
||||
GLenum src_a = GL_ONE;
|
||||
GLenum dst_rgb = GL_ZERO;
|
||||
GLenum dst_a = GL_ZERO;
|
||||
OpenGL::BlendState state = {GL_ONE, GL_ONE, GL_ZERO, GL_ZERO, GL_FUNC_ADD};
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case BLEND_ALPHA:
|
||||
if (gl_1_4 || GLAD_ES_VERSION_2_0 || GLAD_EXT_blend_func_separate)
|
||||
if (GLAD_ES_VERSION_2_0 || GLAD_VERSION_1_4 || GLAD_EXT_blend_func_separate)
|
||||
{
|
||||
src_rgb = GL_SRC_ALPHA;
|
||||
src_a = GL_ONE;
|
||||
dst_rgb = dst_a = GL_ONE_MINUS_SRC_ALPHA;
|
||||
state.srcRGB = GL_SRC_ALPHA;
|
||||
state.srcA = GL_ONE;
|
||||
state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -653,100 +673,56 @@ void Graphics::setBlendMode(Graphics::BlendMode mode)
|
||||
// This will most likely only be used for the Microsoft software renderer and
|
||||
// since it's still stuck with OpenGL 1.1, the only expected difference is a
|
||||
// different alpha value when reading back the default framebuffer (newScreenshot).
|
||||
src_rgb = src_a = GL_SRC_ALPHA;
|
||||
dst_rgb = dst_a = GL_ONE_MINUS_SRC_ALPHA;
|
||||
state.srcRGB = state.srcA = GL_SRC_ALPHA;
|
||||
state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
break;
|
||||
case BLEND_MULTIPLICATIVE:
|
||||
src_rgb = src_a = GL_DST_COLOR;
|
||||
dst_rgb = dst_a = GL_ZERO;
|
||||
state.srcRGB = state.srcA = GL_DST_COLOR;
|
||||
state.dstRGB = state.dstA = GL_ZERO;
|
||||
break;
|
||||
case BLEND_PREMULTIPLIED:
|
||||
src_rgb = src_a = GL_ONE;
|
||||
dst_rgb = dst_a = GL_ONE_MINUS_SRC_ALPHA;
|
||||
state.srcRGB = state.srcA = GL_ONE;
|
||||
state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA;
|
||||
break;
|
||||
case BLEND_SUBTRACTIVE:
|
||||
func = GL_FUNC_REVERSE_SUBTRACT;
|
||||
state.func = GL_FUNC_REVERSE_SUBTRACT;
|
||||
case BLEND_ADDITIVE:
|
||||
src_rgb = src_a = GL_SRC_ALPHA;
|
||||
dst_rgb = dst_a = GL_ONE;
|
||||
state.srcRGB = state.srcA = GL_SRC_ALPHA;
|
||||
state.dstRGB = state.dstA = GL_ONE;
|
||||
break;
|
||||
case BLEND_REPLACE:
|
||||
default:
|
||||
src_rgb = src_a = GL_ONE;
|
||||
dst_rgb = dst_a = GL_ZERO;
|
||||
state.srcRGB = state.srcA = GL_ONE;
|
||||
state.dstRGB = state.dstA = GL_ZERO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gl_1_4 || GLAD_ES_VERSION_2_0)
|
||||
glBlendEquation(func);
|
||||
else if (GLAD_EXT_blend_minmax && GLAD_EXT_blend_subtract)
|
||||
glBlendEquationEXT(func);
|
||||
else
|
||||
{
|
||||
if (func == GL_FUNC_REVERSE_SUBTRACT)
|
||||
throw Exception("This graphics card does not support the subtractive blend mode!");
|
||||
// GL_FUNC_ADD is the default even without access to glBlendEquation, so that'll still work.
|
||||
}
|
||||
|
||||
if (src_rgb == src_a && dst_rgb == dst_a)
|
||||
glBlendFunc(src_rgb, dst_rgb);
|
||||
else
|
||||
{
|
||||
if (gl_1_4 || GLAD_ES_VERSION_2_0)
|
||||
glBlendFuncSeparate(src_rgb, dst_rgb, src_a, dst_a);
|
||||
else if (GLAD_EXT_blend_func_separate)
|
||||
glBlendFuncSeparateEXT(src_rgb, dst_rgb, src_a, dst_a);
|
||||
else
|
||||
throw Exception("This graphics card does not support separated rgb and alpha blend functions!");
|
||||
}
|
||||
gl.setBlendState(state);
|
||||
}
|
||||
|
||||
Graphics::BlendMode Graphics::getBlendMode() const
|
||||
{
|
||||
const int gl_1_4 = GLAD_VERSION_1_4;
|
||||
OpenGL::BlendState state = gl.getBlendState();
|
||||
|
||||
GLint src_rgb, src_a, dst_rgb, dst_a;
|
||||
GLint equation = GL_FUNC_ADD;
|
||||
|
||||
if (gl_1_4 || GLAD_ES_VERSION_2_0 || GLAD_EXT_blend_func_separate)
|
||||
{
|
||||
glGetIntegerv(GL_BLEND_SRC_RGB, &src_rgb);
|
||||
glGetIntegerv(GL_BLEND_SRC_ALPHA, &src_a);
|
||||
glGetIntegerv(GL_BLEND_DST_RGB, &dst_rgb);
|
||||
glGetIntegerv(GL_BLEND_DST_ALPHA, &dst_a);
|
||||
}
|
||||
else
|
||||
{
|
||||
glGetIntegerv(GL_BLEND_SRC, &src_rgb);
|
||||
glGetIntegerv(GL_BLEND_DST, &dst_rgb);
|
||||
src_a = src_rgb;
|
||||
dst_a = dst_rgb;
|
||||
}
|
||||
|
||||
if (GLAD_ES_VERSION_2_0)
|
||||
glGetIntegerv(GL_BLEND_EQUATION_RGB, &equation);
|
||||
else if (gl_1_4 || (GLAD_EXT_blend_minmax && GLAD_EXT_blend_subtract))
|
||||
glGetIntegerv(GL_BLEND_EQUATION, &equation);
|
||||
|
||||
if (equation == GL_FUNC_REVERSE_SUBTRACT) // && src == GL_SRC_ALPHA && dst == GL_ONE
|
||||
if (state.func == GL_FUNC_REVERSE_SUBTRACT) // && src == GL_SRC_ALPHA && dst == GL_ONE
|
||||
return BLEND_SUBTRACTIVE;
|
||||
// Everything else has equation == GL_FUNC_ADD.
|
||||
else if (src_rgb == src_a && dst_rgb == dst_a)
|
||||
else if (state.srcRGB == state.srcA && state.dstRGB == state.dstA)
|
||||
{
|
||||
if (src_rgb == GL_SRC_ALPHA && dst_rgb == GL_ONE)
|
||||
if (state.srcRGB == GL_SRC_ALPHA && state.dstRGB == GL_ONE)
|
||||
return BLEND_ADDITIVE;
|
||||
else if (src_rgb == GL_SRC_ALPHA && dst_rgb == GL_ONE_MINUS_SRC_ALPHA)
|
||||
else if (state.srcRGB == GL_SRC_ALPHA && state.dstRGB == GL_ONE_MINUS_SRC_ALPHA)
|
||||
return BLEND_ALPHA; // alpha blend mode fallback for very old OpenGL versions.
|
||||
else if (src_rgb == GL_DST_COLOR && dst_rgb == GL_ZERO)
|
||||
else if (state.srcRGB == GL_DST_COLOR && state.dstRGB == GL_ZERO)
|
||||
return BLEND_MULTIPLICATIVE;
|
||||
else if (src_rgb == GL_ONE && dst_rgb == GL_ONE_MINUS_SRC_ALPHA)
|
||||
else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ONE_MINUS_SRC_ALPHA)
|
||||
return BLEND_PREMULTIPLIED;
|
||||
else if (src_rgb == GL_ONE && dst_rgb == GL_ZERO)
|
||||
else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ZERO)
|
||||
return BLEND_REPLACE;
|
||||
}
|
||||
else if (src_rgb == GL_SRC_ALPHA && src_a == GL_ONE &&
|
||||
dst_rgb == GL_ONE_MINUS_SRC_ALPHA && dst_a == GL_ONE_MINUS_SRC_ALPHA)
|
||||
else if (state.srcRGB == GL_SRC_ALPHA && state.srcA == GL_ONE &&
|
||||
state.dstRGB == GL_ONE_MINUS_SRC_ALPHA && state.dstA == GL_ONE_MINUS_SRC_ALPHA)
|
||||
return BLEND_ALPHA;
|
||||
|
||||
throw Exception("Unknown blend mode");
|
||||
@@ -836,6 +812,21 @@ Graphics::PointStyle Graphics::getPointStyle() const
|
||||
return POINT_ROUGH;
|
||||
}
|
||||
|
||||
void Graphics::setWireframe(bool enable)
|
||||
{
|
||||
// Not supported in OpenGL ES.
|
||||
if (GLAD_ES_VERSION_2_0)
|
||||
return;
|
||||
|
||||
wireframe = enable;
|
||||
glPolygonMode(GL_FRONT_AND_BACK, enable ? GL_LINE : GL_FILL);
|
||||
}
|
||||
|
||||
bool Graphics::isWireframe() const
|
||||
{
|
||||
return wireframe;
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -81,6 +81,8 @@ struct DisplayState
|
||||
// Color mask.
|
||||
bool colorMask[4];
|
||||
|
||||
bool wireframe;
|
||||
|
||||
// Default values.
|
||||
DisplayState()
|
||||
{
|
||||
@@ -93,6 +95,7 @@ struct DisplayState
|
||||
pointStyle = Graphics::POINT_SMOOTH;
|
||||
scissor = false;
|
||||
colorMask[0] = colorMask[1] = colorMask[2] = colorMask[3] = true;
|
||||
wireframe = false;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -112,7 +115,7 @@ public:
|
||||
void restoreState(const DisplayState &s);
|
||||
|
||||
virtual void setViewportSize(int width, int height);
|
||||
virtual bool setMode(int width, int height);
|
||||
virtual bool setMode(int width, int height, bool &sRGB);
|
||||
virtual void unSetMode();
|
||||
|
||||
void setDebug(bool enable);
|
||||
@@ -191,8 +194,8 @@ public:
|
||||
/**
|
||||
* Creates an Image object with padding and/or optimization.
|
||||
**/
|
||||
Image *newImage(love::image::ImageData *data);
|
||||
Image *newImage(love::image::CompressedData *cdata);
|
||||
Image *newImage(love::image::ImageData *data, Texture::Format format = Texture::FORMAT_NORMAL);
|
||||
Image *newImage(love::image::CompressedData *cdata, Texture::Format format = Texture::FORMAT_NORMAL);
|
||||
|
||||
Quad *newQuad(Quad::Viewport v, float sw, float sh);
|
||||
|
||||
@@ -205,7 +208,7 @@ public:
|
||||
|
||||
ParticleSystem *newParticleSystem(Texture *texture, int size);
|
||||
|
||||
Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL, int fsaa = 0);
|
||||
Canvas *newCanvas(int width, int height, Texture::Format format = Texture::FORMAT_NORMAL, int fsaa = 0);
|
||||
|
||||
Shader *newShader(const Shader::ShaderSources &sources);
|
||||
|
||||
@@ -334,6 +337,19 @@ public:
|
||||
**/
|
||||
PointStyle getPointStyle() const;
|
||||
|
||||
/**
|
||||
* Sets whether graphics will be drawn as wireframe lines instead of filled
|
||||
* triangles (has no effect for drawn points.)
|
||||
* This should only be used as a debugging tool. The wireframe lines do not
|
||||
* behave the same as regular love.graphics lines.
|
||||
**/
|
||||
void setWireframe(bool enable);
|
||||
|
||||
/**
|
||||
* Gets whether wireframe drawing mode is enabled.
|
||||
**/
|
||||
bool isWireframe() const;
|
||||
|
||||
/**
|
||||
* Draws text at the specified coordinates, with rotation and
|
||||
* scaling along both axes.
|
||||
@@ -459,6 +475,7 @@ private:
|
||||
float lineWidth;
|
||||
size_t matrixLimit;
|
||||
bool colorMask[4];
|
||||
bool wireframe;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
@@ -36,7 +36,7 @@ float Image::maxMipmapSharpness = 0.0f;
|
||||
Texture::FilterMode Image::defaultMipmapFilter = Texture::FILTER_NONE;
|
||||
float Image::defaultMipmapSharpness = 0.0f;
|
||||
|
||||
Image::Image(love::image::ImageData *data)
|
||||
Image::Image(love::image::ImageData *data, Texture::Format format)
|
||||
: data(data)
|
||||
, cdata(nullptr)
|
||||
, paddedWidth(width)
|
||||
@@ -45,6 +45,7 @@ Image::Image(love::image::ImageData *data)
|
||||
, mipmapSharpness(defaultMipmapSharpness)
|
||||
, mipmapsCreated(false)
|
||||
, compressed(false)
|
||||
, format(format)
|
||||
, usingDefaultTexture(false)
|
||||
{
|
||||
width = data->getWidth();
|
||||
@@ -54,7 +55,7 @@ Image::Image(love::image::ImageData *data)
|
||||
preload();
|
||||
}
|
||||
|
||||
Image::Image(love::image::CompressedData *cdata)
|
||||
Image::Image(love::image::CompressedData *cdata, Texture::Format format)
|
||||
: data(nullptr)
|
||||
, cdata(cdata)
|
||||
, paddedWidth(width)
|
||||
@@ -63,6 +64,7 @@ Image::Image(love::image::CompressedData *cdata)
|
||||
, mipmapSharpness(defaultMipmapSharpness)
|
||||
, mipmapsCreated(false)
|
||||
, compressed(true)
|
||||
, format(format)
|
||||
, usingDefaultTexture(false)
|
||||
{
|
||||
width = cdata->getWidth(0);
|
||||
@@ -328,6 +330,9 @@ void Image::unload()
|
||||
|
||||
bool Image::loadVolatile()
|
||||
{
|
||||
if (format == FORMAT_SRGB && !hasSRGBSupport())
|
||||
throw love::Exception("sRGB images are not supported on this system.");
|
||||
|
||||
if (isCompressed() && cdata && !hasCompressedTextureSupport(cdata->getFormat()))
|
||||
{
|
||||
const char *str;
|
||||
@@ -400,9 +405,10 @@ void Image::uploadTexturePadded()
|
||||
}
|
||||
else if (data)
|
||||
{
|
||||
GLenum iformat = (format == FORMAT_SRGB) ? GL_SRGB_ALPHA : GL_RGBA;
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGBA,
|
||||
iformat,
|
||||
(GLsizei)paddedWidth,
|
||||
(GLsizei)paddedHeight,
|
||||
0,
|
||||
@@ -437,9 +443,10 @@ void Image::uploadTexture()
|
||||
}
|
||||
else if (data)
|
||||
{
|
||||
GLenum iformat = (format == FORMAT_SRGB) ? GL_SRGB_ALPHA : GL_RGBA;
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGBA,
|
||||
iformat,
|
||||
(GLsizei)width,
|
||||
(GLsizei)height,
|
||||
0,
|
||||
@@ -497,6 +504,11 @@ bool Image::refresh()
|
||||
return true;
|
||||
}
|
||||
|
||||
Texture::Format Image::getFormat() const
|
||||
{
|
||||
return format;
|
||||
}
|
||||
|
||||
void Image::uploadDefaultTexture()
|
||||
{
|
||||
usingDefaultTexture = true;
|
||||
@@ -561,16 +573,27 @@ bool Image::isCompressed() const
|
||||
return compressed;
|
||||
}
|
||||
|
||||
GLenum Image::getCompressedFormat(image::CompressedData::Format format) const
|
||||
GLenum Image::getCompressedFormat(image::CompressedData::Format cformat) const
|
||||
{
|
||||
switch (format)
|
||||
bool srgb = format == FORMAT_SRGB;
|
||||
|
||||
switch (cformat)
|
||||
{
|
||||
case image::CompressedData::FORMAT_DXT1:
|
||||
return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||
if (srgb)
|
||||
return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
|
||||
else
|
||||
return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||
case image::CompressedData::FORMAT_DXT3:
|
||||
return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
if (srgb)
|
||||
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
|
||||
else
|
||||
return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
case image::CompressedData::FORMAT_DXT5:
|
||||
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
if (srgb)
|
||||
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
|
||||
else
|
||||
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
case image::CompressedData::FORMAT_BC4:
|
||||
return GL_COMPRESSED_RED_RGTC1;
|
||||
case image::CompressedData::FORMAT_BC4s:
|
||||
@@ -580,7 +603,10 @@ GLenum Image::getCompressedFormat(image::CompressedData::Format format) const
|
||||
case image::CompressedData::FORMAT_BC5s:
|
||||
return GL_COMPRESSED_SIGNED_RG_RGTC2;
|
||||
default:
|
||||
return GL_RGBA;
|
||||
if (srgb)
|
||||
return GL_SRGB_ALPHA;
|
||||
else
|
||||
return GL_RGBA;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,6 +650,11 @@ bool Image::hasCompressedTextureSupport(image::CompressedData::Format format)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Image::hasSRGBSupport()
|
||||
{
|
||||
return GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB || GLAD_EXT_sRGB;
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -56,14 +56,14 @@ public:
|
||||
*
|
||||
* @param data The data from which to load the image.
|
||||
**/
|
||||
Image(love::image::ImageData *data);
|
||||
Image(love::image::ImageData *data, Texture::Format format = Texture::FORMAT_NORMAL);
|
||||
|
||||
/**
|
||||
* Creates a new Image with compressed image data.
|
||||
*
|
||||
* @param cdata The compressed data from which to load the image.
|
||||
**/
|
||||
Image(love::image::CompressedData *cdata);
|
||||
Image(love::image::CompressedData *cdata, Texture::Format format = Texture::FORMAT_NORMAL);
|
||||
|
||||
/**
|
||||
* Destructor. Deletes the hardware texture and other resources.
|
||||
@@ -120,6 +120,8 @@ public:
|
||||
**/
|
||||
bool refresh();
|
||||
|
||||
Texture::Format getFormat() const;
|
||||
|
||||
static void setDefaultMipmapSharpness(float sharpness);
|
||||
static float getDefaultMipmapSharpness();
|
||||
static void setDefaultMipmapFilter(FilterMode f);
|
||||
@@ -132,6 +134,8 @@ public:
|
||||
|
||||
static bool hasCompressedTextureSupport(image::CompressedData::Format format);
|
||||
|
||||
static bool hasSRGBSupport();
|
||||
|
||||
private:
|
||||
|
||||
void uploadDefaultTexture();
|
||||
@@ -161,6 +165,9 @@ private:
|
||||
// Whether this Image is using a compressed texture.
|
||||
bool compressed;
|
||||
|
||||
// The format to interpret the texture's data as.
|
||||
Texture::Format format;
|
||||
|
||||
// True if the image wasn't able to be properly created and it had to fall
|
||||
// back to a default texture.
|
||||
bool usingDefaultTexture;
|
||||
@@ -179,7 +186,7 @@ private:
|
||||
static FilterMode defaultMipmapFilter;
|
||||
static float defaultMipmapSharpness;
|
||||
|
||||
GLenum getCompressedFormat(image::CompressedData::Format format) const;
|
||||
GLenum getCompressedFormat(image::CompressedData::Format cformat) const;
|
||||
|
||||
}; // Image
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ Mesh::Mesh(const std::vector<Vertex> &verts, Mesh::DrawMode mode)
|
||||
, range_max(-1)
|
||||
, texture(nullptr)
|
||||
, colors_enabled(false)
|
||||
, wireframe(false)
|
||||
{
|
||||
setVertices(verts);
|
||||
}
|
||||
@@ -59,7 +58,6 @@ Mesh::Mesh(int vertexcount, Mesh::DrawMode mode)
|
||||
, range_max(-1)
|
||||
, texture(nullptr)
|
||||
, colors_enabled(false)
|
||||
, wireframe(false)
|
||||
{
|
||||
if (vertexcount < 1)
|
||||
throw love::Exception("Invalid number of vertices.");
|
||||
@@ -278,16 +276,6 @@ bool Mesh::hasVertexColors() const
|
||||
return colors_enabled;
|
||||
}
|
||||
|
||||
void Mesh::setWireframe(bool enable)
|
||||
{
|
||||
wireframe = enable;
|
||||
}
|
||||
|
||||
bool Mesh::isWireframe() const
|
||||
{
|
||||
return wireframe;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -326,9 +314,6 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
|
||||
gl.setVertexAttribArray(OpenGL::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, sizeof(Vertex), vbo->getPointer(color_offset));
|
||||
}
|
||||
|
||||
if (wireframe && GLAD_VERSION_1_0)
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
|
||||
GLenum mode = getGLDrawMode(draw_mode);
|
||||
|
||||
gl.prepareDraw();
|
||||
@@ -377,9 +362,6 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
|
||||
gl.disableVertexAttribArray(OpenGL::ATTRIB_POS);
|
||||
gl.disableVertexAttribArray(OpenGL::ATTRIB_TEXCOORD);
|
||||
|
||||
if (wireframe && GLAD_VERSION_1_0)
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
if (hasVertexColors())
|
||||
{
|
||||
gl.disableVertexAttribArray(OpenGL::ATTRIB_COLOR);
|
||||
|
||||
@@ -162,15 +162,6 @@ public:
|
||||
void setVertexColors(bool enable);
|
||||
bool hasVertexColors() const;
|
||||
|
||||
/**
|
||||
* Sets whether the Mesh will be drawn as wireframe lines instead of filled
|
||||
* triangles (has no effect for DRAW_MODE_POINTS.)
|
||||
* This should only be used as a debugging tool. The wireframe lines do not
|
||||
* behave the same as regular love.graphics lines.
|
||||
**/
|
||||
void setWireframe(bool enable);
|
||||
bool isWireframe() const;
|
||||
|
||||
// Implements Drawable.
|
||||
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
|
||||
|
||||
@@ -201,8 +192,6 @@ private:
|
||||
// Whether the per-vertex colors are used when drawing.
|
||||
bool colors_enabled;
|
||||
|
||||
bool wireframe;
|
||||
|
||||
static StringMap<DrawMode, DRAW_MODE_MAX_ENUM>::Entry drawModeEntries[];
|
||||
static StringMap<DrawMode, DRAW_MODE_MAX_ENUM> drawModes;
|
||||
|
||||
|
||||
@@ -127,6 +127,9 @@ bool OpenGL::initContext()
|
||||
if (Canvas::isSupported())
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint *) &state.defaultFBO);
|
||||
|
||||
BlendState blend = {GL_ONE, GL_ONE, GL_ZERO, GL_ZERO, GL_FUNC_ADD};
|
||||
setBlendState(blend);
|
||||
|
||||
initMaxValues();
|
||||
createDefaultTexture();
|
||||
|
||||
@@ -492,6 +495,40 @@ OpenGL::Viewport OpenGL::getScissor() const
|
||||
return state.scissor;
|
||||
}
|
||||
|
||||
void OpenGL::setBlendState(const BlendState &blend)
|
||||
{
|
||||
if (GLAD_ES_VERSION_2_0 || GLAD_VERSION_1_4)
|
||||
glBlendEquation(blend.func);
|
||||
else if (GLAD_EXT_blend_minmax && GLAD_EXT_blend_subtract)
|
||||
glBlendEquationEXT(blend.func);
|
||||
else
|
||||
{
|
||||
if (blend.func == GL_FUNC_REVERSE_SUBTRACT)
|
||||
throw love::Exception("This graphics card does not support the subtractive blend mode!");
|
||||
// GL_FUNC_ADD is the default even without access to glBlendEquation, so that'll still work.
|
||||
}
|
||||
|
||||
if (blend.srcRGB == blend.srcA && blend.dstRGB == blend.dstA)
|
||||
glBlendFunc(blend.srcRGB, blend.dstRGB);
|
||||
else
|
||||
{
|
||||
if (GLAD_ES_VERSION_2_0 || GLAD_VERSION_1_4)
|
||||
glBlendFuncSeparate(blend.srcRGB, blend.dstRGB, blend.srcA, blend.dstA);
|
||||
else if (GLAD_EXT_blend_func_separate)
|
||||
glBlendFuncSeparateEXT(blend.srcRGB, blend.dstRGB, blend.srcA, blend.dstA);
|
||||
else
|
||||
throw love::Exception("This graphics card does not support separated rgb and alpha blend functions!");
|
||||
}
|
||||
|
||||
state.blend = blend;
|
||||
}
|
||||
|
||||
OpenGL::BlendState OpenGL::getBlendState() const
|
||||
{
|
||||
return state.blend;
|
||||
}
|
||||
|
||||
|
||||
void OpenGL::setPointSize(float size)
|
||||
{
|
||||
if (GLAD_VERSION_1_0)
|
||||
|
||||
@@ -103,6 +103,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct BlendState
|
||||
{
|
||||
GLenum srcRGB, srcA;
|
||||
GLenum dstRGB, dstA;
|
||||
GLenum func;
|
||||
};
|
||||
|
||||
// Transformation matrix stacks.
|
||||
struct
|
||||
{
|
||||
@@ -202,6 +209,17 @@ public:
|
||||
**/
|
||||
Viewport getScissor() const;
|
||||
|
||||
/**
|
||||
* Sets blending functionality.
|
||||
* Note: This does not globally enable or disable blending.
|
||||
**/
|
||||
void setBlendState(const BlendState &blend);
|
||||
|
||||
/**
|
||||
* Gets the currently set blending functionality.
|
||||
**/
|
||||
BlendState getBlendState() const;
|
||||
|
||||
/**
|
||||
* Sets the global point size.
|
||||
**/
|
||||
@@ -332,6 +350,8 @@ private:
|
||||
|
||||
GLuint defaultFBO;
|
||||
|
||||
BlendState blend;
|
||||
|
||||
// The last ID value used for pseudo-instancing.
|
||||
int lastPseudoInstanceID;
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ ParticleSystem::ParticleSystem(Texture *texture, uint32 size)
|
||||
, spinVariation(0)
|
||||
, offsetX(float(texture->getWidth())*0.5f)
|
||||
, offsetY(float(texture->getHeight())*0.5f)
|
||||
, relativeRotation(false)
|
||||
{
|
||||
if (size == 0 || size > MAX_PARTICLES)
|
||||
throw love::Exception("Invalid ParticleSystem size.");
|
||||
@@ -146,6 +147,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p)
|
||||
, offsetX(p.offsetX)
|
||||
, offsetY(p.offsetY)
|
||||
, colors(p.colors)
|
||||
, relativeRotation(p.relativeRotation)
|
||||
{
|
||||
setBufferSize(maxParticles);
|
||||
|
||||
@@ -170,7 +172,7 @@ void ParticleSystem::createBuffers(size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
pFree = pMem = new particle[size];
|
||||
pFree = pMem = new Particle[size];
|
||||
particleVerts = new love::Vertex[size * 4];
|
||||
ibo = new VertexIndex(size);
|
||||
maxParticles = (uint32) size;
|
||||
@@ -222,7 +224,7 @@ void ParticleSystem::addParticle(float t)
|
||||
return;
|
||||
|
||||
// Gets a free particle and updates the allocation pointer.
|
||||
particle *p = pFree++;
|
||||
Particle *p = pFree++;
|
||||
initParticle(p, t);
|
||||
|
||||
switch (insertMode)
|
||||
@@ -242,7 +244,7 @@ void ParticleSystem::addParticle(float t)
|
||||
activeParticles++;
|
||||
}
|
||||
|
||||
void ParticleSystem::initParticle(particle *p, float t)
|
||||
void ParticleSystem::initParticle(Particle *p, float t)
|
||||
{
|
||||
float min,max;
|
||||
|
||||
@@ -308,10 +310,14 @@ void ParticleSystem::initParticle(particle *p, float t)
|
||||
p->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
|
||||
p->rotation = (float) rng.random(min, max);
|
||||
|
||||
p->angle = p->rotation;
|
||||
if (relativeRotation)
|
||||
p->angle += atan2f(p->speed.y, p->speed.x);
|
||||
|
||||
p->color = colors[0];
|
||||
}
|
||||
|
||||
void ParticleSystem::insertTop(particle *p)
|
||||
void ParticleSystem::insertTop(Particle *p)
|
||||
{
|
||||
if (pHead == nullptr)
|
||||
{
|
||||
@@ -327,7 +333,7 @@ void ParticleSystem::insertTop(particle *p)
|
||||
pTail = p;
|
||||
}
|
||||
|
||||
void ParticleSystem::insertBottom(particle *p)
|
||||
void ParticleSystem::insertBottom(Particle *p)
|
||||
{
|
||||
if (pTail == nullptr)
|
||||
{
|
||||
@@ -343,7 +349,7 @@ void ParticleSystem::insertBottom(particle *p)
|
||||
pHead = p;
|
||||
}
|
||||
|
||||
void ParticleSystem::insertRandom(particle *p)
|
||||
void ParticleSystem::insertRandom(Particle *p)
|
||||
{
|
||||
// Nonuniform, but 64-bit is so large nobody will notice. Hopefully.
|
||||
uint64 pos = rng.rand() % ((int64) activeParticles + 1);
|
||||
@@ -351,7 +357,7 @@ void ParticleSystem::insertRandom(particle *p)
|
||||
// Special case where the particle gets inserted before the head.
|
||||
if (pos == activeParticles)
|
||||
{
|
||||
particle *pA = pHead;
|
||||
Particle *pA = pHead;
|
||||
if (pA)
|
||||
pA->prev = p;
|
||||
p->prev = nullptr;
|
||||
@@ -361,8 +367,8 @@ void ParticleSystem::insertRandom(particle *p)
|
||||
}
|
||||
|
||||
// Inserts the particle after the randomly selected particle.
|
||||
particle *pA = pMem + pos;
|
||||
particle *pB = pA->next;
|
||||
Particle *pA = pMem + pos;
|
||||
Particle *pB = pA->next;
|
||||
pA->next = p;
|
||||
if (pB)
|
||||
pB->prev = p;
|
||||
@@ -372,12 +378,12 @@ void ParticleSystem::insertRandom(particle *p)
|
||||
p->next = pB;
|
||||
}
|
||||
|
||||
ParticleSystem::particle *ParticleSystem::removeParticle(particle *p)
|
||||
ParticleSystem::Particle *ParticleSystem::removeParticle(Particle *p)
|
||||
{
|
||||
// The linked list is updated in this function and old pointers may be
|
||||
// invalidated. The returned pointer will inform the caller of the new
|
||||
// pointer to the next particle.
|
||||
particle *pNext = nullptr;
|
||||
Particle *pNext = nullptr;
|
||||
|
||||
// Removes the particle from the linked list.
|
||||
if (p->prev)
|
||||
@@ -725,6 +731,16 @@ std::vector<Color> ParticleSystem::getColor() const
|
||||
return ncolors;
|
||||
}
|
||||
|
||||
void ParticleSystem::setRelativeRotation(bool enable)
|
||||
{
|
||||
relativeRotation = enable;
|
||||
}
|
||||
|
||||
bool ParticleSystem::hasRelativeRotation() const
|
||||
{
|
||||
return relativeRotation;
|
||||
}
|
||||
|
||||
uint32 ParticleSystem::getCount() const
|
||||
{
|
||||
return activeParticles;
|
||||
@@ -812,13 +828,13 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
|
||||
|
||||
const Vertex *textureVerts = texture->getVertices();
|
||||
Vertex *pVerts = particleVerts;
|
||||
particle *p = pHead;
|
||||
Particle *p = pHead;
|
||||
|
||||
// set the vertex data for each particle (transformation, texcoords, color)
|
||||
while (p)
|
||||
{
|
||||
// particle vertices are image vertices transformed by particle information
|
||||
t.setTransformation(p->position[0], p->position[1], p->rotation, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f);
|
||||
t.setTransformation(p->position[0], p->position[1], p->angle, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f);
|
||||
t.transform(pVerts, textureVerts, 4);
|
||||
|
||||
// set the texture coordinate and color data for particle vertices
|
||||
@@ -871,7 +887,7 @@ void ParticleSystem::update(float dt)
|
||||
return;
|
||||
|
||||
// Traverse all particles and update.
|
||||
particle *p = pHead;
|
||||
Particle *p = pHead;
|
||||
|
||||
while (p)
|
||||
{
|
||||
@@ -916,7 +932,12 @@ void ParticleSystem::update(float dt)
|
||||
const float t = 1.0f - p->life / p->lifetime;
|
||||
|
||||
// Rotate.
|
||||
p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t)*dt;
|
||||
p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t) * dt;
|
||||
|
||||
p->angle = p->rotation;
|
||||
|
||||
if (relativeRotation)
|
||||
p->angle += atan2f(p->speed.y, p->speed.x);
|
||||
|
||||
// Change size according to given intervals:
|
||||
// i = 0 1 2 3 n-1
|
||||
|
||||
@@ -422,6 +422,12 @@ public:
|
||||
**/
|
||||
std::vector<Color> getColor() const;
|
||||
|
||||
/**
|
||||
* sets whether particle angles & rotations are relative to their velocities.
|
||||
**/
|
||||
void setRelativeRotation(bool enable);
|
||||
bool hasRelativeRotation() const;
|
||||
|
||||
/**
|
||||
* Returns the amount of particles that are currently active in the system.
|
||||
**/
|
||||
@@ -495,11 +501,12 @@ public:
|
||||
static bool getConstant(InsertMode in, const char *&out);
|
||||
|
||||
protected:
|
||||
|
||||
// Represents a single particle.
|
||||
struct particle
|
||||
struct Particle
|
||||
{
|
||||
particle *prev;
|
||||
particle *next;
|
||||
Particle *prev;
|
||||
Particle *next;
|
||||
|
||||
float lifetime;
|
||||
float life;
|
||||
@@ -519,7 +526,8 @@ protected:
|
||||
float sizeOffset;
|
||||
float sizeIntervalSize;
|
||||
|
||||
float rotation;
|
||||
float rotation; // Amount of rotation applied to the final angle.
|
||||
float angle;
|
||||
float spinStart;
|
||||
float spinEnd;
|
||||
|
||||
@@ -527,16 +535,16 @@ protected:
|
||||
};
|
||||
|
||||
// Pointer to the beginning of the allocated memory.
|
||||
particle *pMem;
|
||||
Particle *pMem;
|
||||
|
||||
// Pointer to a free particle.
|
||||
particle *pFree;
|
||||
Particle *pFree;
|
||||
|
||||
// Pointer to the start of the linked list.
|
||||
particle *pHead;
|
||||
Particle *pHead;
|
||||
|
||||
// Pointer to the end of the linked list.
|
||||
particle *pTail;
|
||||
Particle *pTail;
|
||||
|
||||
// array of transformed vertex data for all particles, for drawing
|
||||
Vertex *particleVerts;
|
||||
@@ -621,17 +629,19 @@ protected:
|
||||
// Color.
|
||||
std::vector<Colorf> colors;
|
||||
|
||||
bool relativeRotation;
|
||||
|
||||
void createBuffers(size_t size);
|
||||
void deleteBuffers();
|
||||
|
||||
void addParticle(float t);
|
||||
particle *removeParticle(particle *p);
|
||||
Particle *removeParticle(Particle *p);
|
||||
|
||||
// Called by addParticle.
|
||||
void initParticle(particle *p, float t);
|
||||
void insertTop(particle *p);
|
||||
void insertBottom(particle *p);
|
||||
void insertRandom(particle *p);
|
||||
void initParticle(Particle *p, float t);
|
||||
void insertTop(Particle *p);
|
||||
void insertBottom(Particle *p);
|
||||
void insertRandom(Particle *p);
|
||||
|
||||
static StringMap<AreaSpreadDistribution, DISTRIBUTION_MAX_ENUM>::Entry distributionsEntries[];
|
||||
static StringMap<AreaSpreadDistribution, DISTRIBUTION_MAX_ENUM> distributions;
|
||||
|
||||
@@ -105,6 +105,8 @@ 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;
|
||||
|
||||
Vertex sprite[4];
|
||||
|
||||
// Needed for colors.
|
||||
memcpy(sprite, texture->getVertices(), sizeof(Vertex) * 4);
|
||||
|
||||
@@ -131,6 +133,8 @@ 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;
|
||||
|
||||
Vertex sprite[4];
|
||||
|
||||
// Needed for colors.
|
||||
memcpy(sprite, quad->getVertices(), sizeof(Vertex) * 4);
|
||||
|
||||
|
||||
@@ -135,8 +135,6 @@ private:
|
||||
// The next free element.
|
||||
int next;
|
||||
|
||||
Vertex sprite[4];
|
||||
|
||||
// Current color. This color, if present, will be applied to the next
|
||||
// added sprite.
|
||||
Color *color;
|
||||
|
||||
@@ -110,12 +110,14 @@ int w_Canvas_clear(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Canvas_getType(lua_State *L)
|
||||
int w_Canvas_getFormat(lua_State *L)
|
||||
{
|
||||
Canvas *canvas = luax_checkcanvas(L, 1);
|
||||
Canvas::TextureType type = canvas->getTextureType();
|
||||
Texture::Format format = canvas->getTextureFormat();
|
||||
const char *str;
|
||||
Canvas::getConstant(type, str);
|
||||
if (!Texture::getConstant(format, str))
|
||||
return luaL_error(L, "Unknown texture format.");
|
||||
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
}
|
||||
@@ -142,8 +144,11 @@ static const luaL_Reg functions[] =
|
||||
{ "getImageData", w_Canvas_getImageData },
|
||||
{ "getPixel", w_Canvas_getPixel },
|
||||
{ "clear", w_Canvas_clear },
|
||||
{ "getType", w_Canvas_getType },
|
||||
{ "getFormat", w_Canvas_getFormat },
|
||||
{ "getFSAA", w_Canvas_getFSAA },
|
||||
|
||||
// Deprecated since 0.9.1.
|
||||
{ "getType", w_Canvas_getFormat },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ int w_Canvas_renderTo(lua_State *L);
|
||||
int w_Canvas_getImageData(lua_State *L);
|
||||
int w_Canvas_getPixel(lua_State * L);
|
||||
int w_Canvas_clear(lua_State *L);
|
||||
int w_Canvas_getType(lua_State *L);
|
||||
int w_Canvas_getFormat(lua_State *L);
|
||||
int w_Canvas_getFSAA(lua_State *L);
|
||||
extern "C" int luaopen_canvas(lua_State *L);
|
||||
|
||||
|
||||
@@ -152,8 +152,17 @@ int w_getMaxTextureSize(lua_State *L)
|
||||
|
||||
int w_newImage(lua_State *L)
|
||||
{
|
||||
love::image::ImageData *data = 0;
|
||||
love::image::CompressedData *cdata = 0;
|
||||
love::image::ImageData *data = nullptr;
|
||||
love::image::CompressedData *cdata = nullptr;
|
||||
|
||||
Texture::Format format = Texture::FORMAT_NORMAL;
|
||||
const char *fstr = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2);
|
||||
|
||||
if (fstr != nullptr && !Texture::getConstant(fstr, format))
|
||||
return luaL_error(L, "Invalid texture format: %s", fstr);
|
||||
|
||||
if (format == Texture::FORMAT_HDR) // For now...
|
||||
return luaL_error(L, "HDR images are not supported.");
|
||||
|
||||
// Convert to FileData, if necessary.
|
||||
if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
|
||||
@@ -185,15 +194,15 @@ int w_newImage(lua_State *L)
|
||||
return luaL_error(L, "Error creating image.");
|
||||
|
||||
// Create the image.
|
||||
Image *image = 0;
|
||||
Image *image = nullptr;
|
||||
EXCEPT_GUARD(
|
||||
if (cdata)
|
||||
image = instance->newImage(cdata);
|
||||
image = instance->newImage(cdata, format);
|
||||
else if (data)
|
||||
image = instance->newImage(data);
|
||||
image = instance->newImage(data, format);
|
||||
)
|
||||
|
||||
if (image == 0)
|
||||
if (image == nullptr)
|
||||
return luaL_error(L, "Could not load image.");
|
||||
|
||||
// Push the type.
|
||||
@@ -325,12 +334,12 @@ int w_newCanvas(lua_State *L)
|
||||
const char *str = luaL_optstring(L, 3, "normal");
|
||||
int fsaa = luaL_optint(L, 4, 0);
|
||||
|
||||
Canvas::TextureType texture_type;
|
||||
if (!Canvas::getConstant(str, texture_type))
|
||||
return luaL_error(L, "Invalid canvas type: %s", str);
|
||||
Texture::Format format;
|
||||
if (!Texture::getConstant(str, format))
|
||||
return luaL_error(L, "Invalid texture format: %s", str);
|
||||
|
||||
Canvas *canvas = nullptr;
|
||||
EXCEPT_GUARD(canvas = instance->newCanvas(width, height, texture_type, fsaa);)
|
||||
EXCEPT_GUARD(canvas = instance->newCanvas(width, height, format, fsaa);)
|
||||
|
||||
if (canvas == nullptr)
|
||||
return luaL_error(L, "Canvas not created, but no error thrown. I don't even...");
|
||||
@@ -835,6 +844,18 @@ int w_getMaxPointSize(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_setWireframe(lua_State *L)
|
||||
{
|
||||
instance->setWireframe(luax_toboolean(L, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_isWireframe(lua_State *L)
|
||||
{
|
||||
luax_pushboolean(L, instance->isWireframe());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_newScreenshot(lua_State *L)
|
||||
{
|
||||
love::image::Image *image = luax_getmodule<love::image::Image>(L, "image", MODULE_IMAGE_T);
|
||||
@@ -1029,6 +1050,10 @@ int w_isSupported(lua_State *L)
|
||||
if (!(GLAD_ARB_draw_instanced || (GLAD_ES_VERSION_2_0 && GLAD_EXT_draw_instanced)))
|
||||
supported = false;
|
||||
break;
|
||||
case Graphics::SUPPORT_SRGB:
|
||||
if (!Canvas::isSRGBSupported())
|
||||
supported = false;
|
||||
break;
|
||||
default:
|
||||
supported = false;
|
||||
}
|
||||
@@ -1405,6 +1430,8 @@ static const luaL_Reg functions[] =
|
||||
{ "setPointStyle", w_setPointStyle },
|
||||
{ "getPointSize", w_getPointSize },
|
||||
{ "getPointStyle", w_getPointStyle },
|
||||
{ "setWireframe", w_setWireframe },
|
||||
{ "isWireframe", w_isWireframe },
|
||||
{ "newScreenshot", w_newScreenshot },
|
||||
{ "setCanvas", w_setCanvas },
|
||||
{ "getCanvas", w_getCanvas },
|
||||
|
||||
@@ -85,6 +85,8 @@ int w_setPointStyle(lua_State *L);
|
||||
int w_getPointSize(lua_State *L);
|
||||
int w_getPointStyle(lua_State *L);
|
||||
int w_getMaxPointSize(lua_State *L);
|
||||
int w_setWireframe(lua_State *L);
|
||||
int w_isWireframe(lua_State *L);
|
||||
int w_newScreenshot(lua_State *L);
|
||||
int w_setCanvas(lua_State *L);
|
||||
int w_getCanvas(lua_State *L);
|
||||
|
||||
@@ -361,20 +361,6 @@ int w_Mesh_hasVertexColors(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Mesh_setWireframe(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
t->setWireframe(luax_toboolean(L, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_isWireframe(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
luax_pushboolean(L, t->isWireframe());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "setVertex", w_Mesh_setVertex },
|
||||
@@ -394,8 +380,6 @@ static const luaL_Reg functions[] =
|
||||
{ "getDrawRange", w_Mesh_getDrawRange },
|
||||
{ "setVertexColors", w_Mesh_setVertexColors },
|
||||
{ "hasVertexColors", w_Mesh_hasVertexColors },
|
||||
{ "setWireframe", w_Mesh_setWireframe },
|
||||
{ "isWireframe", w_Mesh_isWireframe },
|
||||
|
||||
// Deprecated since 0.9.1.
|
||||
{ "setImage", w_Mesh_setTexture },
|
||||
|
||||
@@ -51,8 +51,6 @@ int w_Mesh_setDrawRange(lua_State *L);
|
||||
int w_Mesh_getDrawRange(lua_State *L);
|
||||
int w_Mesh_setVertexColors(lua_State *L);
|
||||
int w_Mesh_hasVertexColors(lua_State *L);
|
||||
int w_Mesh_setWireframe(lua_State *L);
|
||||
int w_Mesh_isWireframe(lua_State *L);
|
||||
|
||||
extern "C" int luaopen_mesh(lua_State *L);
|
||||
|
||||
|
||||
@@ -569,6 +569,20 @@ int w_ParticleSystem_getColors(lua_State *L)
|
||||
return colors.size();
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setRelativeRotation(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
t->setRelativeRotation(luax_toboolean(L, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_hasRelativeRotation(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
luax_pushboolean(L, t->hasRelativeRotation());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getCount(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
@@ -687,6 +701,8 @@ static const luaL_Reg functions[] =
|
||||
{ "getColors", w_ParticleSystem_getColors },
|
||||
{ "setOffset", w_ParticleSystem_setOffset },
|
||||
{ "getOffset", w_ParticleSystem_getOffset },
|
||||
{ "setRelativeRotation", w_ParticleSystem_setRelativeRotation },
|
||||
{ "hasRelativeRotation", w_ParticleSystem_hasRelativeRotation },
|
||||
{ "getCount", w_ParticleSystem_getCount },
|
||||
{ "start", w_ParticleSystem_start },
|
||||
{ "stop", w_ParticleSystem_stop },
|
||||
|
||||
@@ -77,6 +77,8 @@ int w_ParticleSystem_setColors(lua_State *L);
|
||||
int w_ParticleSystem_getColors(lua_State *L);
|
||||
int w_ParticleSystem_setOffset(lua_State *L);
|
||||
int w_ParticleSystem_getOffset(lua_State *L);
|
||||
int w_ParticleSystem_setRelativeRotation(lua_State *L);
|
||||
int w_ParticleSystem_hasRelativeRotation(lua_State *L);
|
||||
int w_ParticleSystem_getCount(lua_State *L);
|
||||
int w_ParticleSystem_start(lua_State *L);
|
||||
int w_ParticleSystem_stop(lua_State *L);
|
||||
|
||||
@@ -193,5 +193,35 @@ bool Math::isConvex(const std::vector<Vertex> &polygon)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* http://en.wikipedia.org/wiki/SRGB#The_reverse_transformation
|
||||
**/
|
||||
float Math::gammaToLinear(float c) const
|
||||
{
|
||||
if (c > 1.0)
|
||||
return 1.0;
|
||||
else if (c < 0.0)
|
||||
return 0.0;
|
||||
else if (c <= 0.04045)
|
||||
return c / 12.92;
|
||||
else
|
||||
return powf((c + 0.055) / 1.055, 2.4);
|
||||
}
|
||||
|
||||
/**
|
||||
* http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29
|
||||
**/
|
||||
float Math::linearToGamma(float c) const
|
||||
{
|
||||
if (c > 1.0)
|
||||
return 1.0;
|
||||
else if (c < 0.0)
|
||||
return 0.0;
|
||||
else if (c < 0.0031308)
|
||||
return c * 12.92;
|
||||
else
|
||||
return 1.055 * powf(c, 0.41666) - 0.055;
|
||||
}
|
||||
|
||||
} // math
|
||||
} // love
|
||||
|
||||
@@ -53,26 +53,6 @@ public:
|
||||
virtual ~Math()
|
||||
{}
|
||||
|
||||
inline void setRandomSeed(RandomGenerator::Seed seed)
|
||||
{
|
||||
rng.setSeed(seed);
|
||||
}
|
||||
|
||||
inline void setRandomSeed(uint32 low, uint32 high)
|
||||
{
|
||||
rng.setSeed(low, high);
|
||||
}
|
||||
|
||||
inline RandomGenerator::Seed getRandomSeed() const
|
||||
{
|
||||
return rng.getSeed();
|
||||
}
|
||||
|
||||
inline void getRandomSeed(uint32 &low, uint32 &high) const
|
||||
{
|
||||
rng.getSeed(low, high);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc RandomGenerator::random()
|
||||
**/
|
||||
@@ -105,6 +85,26 @@ public:
|
||||
return rng.randomNormal(stddev);
|
||||
}
|
||||
|
||||
inline void setRandomSeed(RandomGenerator::Seed seed)
|
||||
{
|
||||
rng.setSeed(seed);
|
||||
}
|
||||
|
||||
inline RandomGenerator::Seed getRandomSeed() const
|
||||
{
|
||||
return rng.getSeed();
|
||||
}
|
||||
|
||||
inline void setRandomState(const std::string &statestr)
|
||||
{
|
||||
rng.setState(statestr);
|
||||
}
|
||||
|
||||
inline std::string getRandomState() const
|
||||
{
|
||||
return rng.getState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new random number generator.
|
||||
**/
|
||||
@@ -136,6 +136,16 @@ public:
|
||||
**/
|
||||
bool isConvex(const std::vector<Vertex> &polygon);
|
||||
|
||||
/**
|
||||
* Converts a value from the sRGB (gamma) colorspace to linear RGB.
|
||||
**/
|
||||
float gammaToLinear(float c) const;
|
||||
|
||||
/**
|
||||
* Converts a value from linear RGB to the sRGB (gamma) colorspace.
|
||||
**/
|
||||
float linearToGamma(float c) const;
|
||||
|
||||
/**
|
||||
* Calculate Simplex noise for the specified coordinate(s).
|
||||
*
|
||||
|
||||
@@ -20,8 +20,13 @@
|
||||
|
||||
#include "RandomGenerator.h"
|
||||
|
||||
// STL
|
||||
// C++
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
// C
|
||||
#include <cstdlib>
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -36,25 +41,10 @@ RandomGenerator::RandomGenerator()
|
||||
{
|
||||
// because it is too big for some compilers to handle ... if you know what
|
||||
// i mean
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
seed.b32.a = 0x0139408D;
|
||||
seed.b32.b = 0xCBBF7A44;
|
||||
#else
|
||||
seed.b32.b = 0x0139408D;
|
||||
seed.b32.a = 0xCBBF7A44;
|
||||
#endif
|
||||
|
||||
rng_state = seed;
|
||||
}
|
||||
|
||||
void RandomGenerator::setSeed(RandomGenerator::Seed newseed)
|
||||
{
|
||||
// 0 xor 0 is still 0, so Xorshift can't generate new numbers.
|
||||
if (newseed.b64 == 0)
|
||||
throw love::Exception("Invalid random seed.");
|
||||
|
||||
seed = newseed;
|
||||
rng_state = seed;
|
||||
Seed newseed;
|
||||
newseed.b32.low = 0xCBBF7A44;
|
||||
newseed.b32.high = 0x0139408D;
|
||||
setSeed(newseed);
|
||||
}
|
||||
|
||||
uint64 RandomGenerator::rand()
|
||||
@@ -83,5 +73,71 @@ double RandomGenerator::randomNormal(double stddev)
|
||||
return r * sin(phi) * stddev;
|
||||
}
|
||||
|
||||
void RandomGenerator::setSeed(RandomGenerator::Seed newseed)
|
||||
{
|
||||
// 0 xor 0 is still 0, so Xorshift can't generate new numbers.
|
||||
if (newseed.b64 == 0)
|
||||
throw love::Exception("Invalid random seed.");
|
||||
|
||||
seed = newseed;
|
||||
rng_state = seed;
|
||||
}
|
||||
|
||||
RandomGenerator::Seed RandomGenerator::getSeed() const
|
||||
{
|
||||
return seed;
|
||||
}
|
||||
|
||||
void RandomGenerator::setState(const std::string &statestr)
|
||||
{
|
||||
// For this implementation we'll accept a hex string representing the
|
||||
// 64-bit state integer xorshift uses.
|
||||
|
||||
Seed state = {};
|
||||
|
||||
// Hex string must start with 0x.
|
||||
if (statestr.find("0x") != 0 || statestr.size() < 3)
|
||||
throw love::Exception("Invalid random state.");
|
||||
|
||||
// standardized strtoull (or 64 bit integer support for stringstream)
|
||||
// requires C++11's standard library, which we can't use yet.
|
||||
// I use strtol like this not because it's the best solution, but because
|
||||
// it's "good enough".
|
||||
|
||||
// Convert the hex string to the state integer character-by-character.
|
||||
for (size_t i = 2; i < statestr.size(); i++)
|
||||
{
|
||||
char hex[2] = {statestr[i], 0};
|
||||
char *end = nullptr;
|
||||
|
||||
// Convert the current hex character to a number.
|
||||
int nibble = strtol(hex, &end, 16);
|
||||
|
||||
// Check if strtol failed to convert it.
|
||||
if (end != nullptr && *end != 0)
|
||||
throw love::Exception("Invalid random state.");
|
||||
|
||||
state.b64 = (state.b64 << 4) + nibble;
|
||||
}
|
||||
|
||||
rng_state = state;
|
||||
}
|
||||
|
||||
std::string RandomGenerator::getState() const
|
||||
{
|
||||
// For this implementation we'll return a hex string representing the 64-bit
|
||||
// state integer xorshift uses.
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "0x";
|
||||
|
||||
// Again with the stringstream not dealing with 64 bit integers...
|
||||
ss << std::setfill('0') << std::setw(8) << std::hex << rng_state.b32.high;
|
||||
ss << std::setfill('0') << std::setw(8) << std::hex << rng_state.b32.low;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // math
|
||||
} // love
|
||||
|
||||
@@ -28,8 +28,9 @@
|
||||
#include "common/int.h"
|
||||
#include "common/Object.h"
|
||||
|
||||
// STL
|
||||
// C++
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -45,54 +46,19 @@ public:
|
||||
uint64 b64;
|
||||
struct
|
||||
{
|
||||
uint32 a;
|
||||
uint32 b;
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
uint32 high;
|
||||
uint32 low;
|
||||
#else
|
||||
uint32 low;
|
||||
uint32 high;
|
||||
#endif
|
||||
} b32;
|
||||
};
|
||||
|
||||
RandomGenerator();
|
||||
virtual ~RandomGenerator() {}
|
||||
|
||||
/**
|
||||
* Set pseudo-random seed.
|
||||
* It's up to the implementation how to use this.
|
||||
**/
|
||||
void setSeed(Seed seed);
|
||||
|
||||
/**
|
||||
* Separately set the low and high bits of the pseudo-random seed.
|
||||
**/
|
||||
inline void setSeed(uint32 low, uint32 high)
|
||||
{
|
||||
Seed newseed;
|
||||
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
newseed.b32.a = high;
|
||||
newseed.b32.b = low;
|
||||
#else
|
||||
newseed.b32.b = high;
|
||||
newseed.b32.a = low;
|
||||
#endif
|
||||
|
||||
setSeed(newseed);
|
||||
}
|
||||
|
||||
inline Seed getSeed() const
|
||||
{
|
||||
return seed;
|
||||
}
|
||||
|
||||
inline void getSeed(uint32 &low, uint32 &high) const
|
||||
{
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
high = seed.b32.a;
|
||||
low = seed.b32.b;
|
||||
#else
|
||||
high = seed.b32.b;
|
||||
low = seed.b32.a;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Return uniformly distributed pseudo random integer.
|
||||
*
|
||||
@@ -138,6 +104,28 @@ public:
|
||||
**/
|
||||
double randomNormal(double stddev);
|
||||
|
||||
/**
|
||||
* Set pseudo-random seed.
|
||||
* It's up to the implementation how to use this.
|
||||
**/
|
||||
void setSeed(Seed seed);
|
||||
|
||||
/**
|
||||
* Get the previously set pseudo-random seed.
|
||||
**/
|
||||
Seed getSeed() const;
|
||||
|
||||
/**
|
||||
* Set the internal implementation-dependent state value based on a string.
|
||||
**/
|
||||
void setState(const std::string &statestr);
|
||||
|
||||
/**
|
||||
* Get a string representation of the implementation-dependent internal
|
||||
* state value.
|
||||
**/
|
||||
std::string getState() const;
|
||||
|
||||
private:
|
||||
|
||||
Seed seed;
|
||||
|
||||
@@ -32,21 +32,6 @@ namespace love
|
||||
namespace math
|
||||
{
|
||||
|
||||
int w_setRandomSeed(lua_State *L)
|
||||
{
|
||||
EXCEPT_GUARD(Math::instance.setRandomSeed(luax_checkrandomseed(L, 1));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getRandomSeed(lua_State *L)
|
||||
{
|
||||
uint32 low = 0, high = 0;
|
||||
Math::instance.getRandomSeed(low, high);
|
||||
lua_pushnumber(L, (lua_Number) low);
|
||||
lua_pushnumber(L, (lua_Number) high);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_random(lua_State *L)
|
||||
{
|
||||
return luax_getrandom(L, 1, Math::instance.random());
|
||||
@@ -62,6 +47,32 @@ int w_randomNormal(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_setRandomSeed(lua_State *L)
|
||||
{
|
||||
EXCEPT_GUARD(Math::instance.setRandomSeed(luax_checkrandomseed(L, 1));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getRandomSeed(lua_State *L)
|
||||
{
|
||||
RandomGenerator::Seed s = Math::instance.getRandomSeed();
|
||||
lua_pushnumber(L, (lua_Number) s.b32.low);
|
||||
lua_pushnumber(L, (lua_Number) s.b32.high);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_setRandomState(lua_State *L)
|
||||
{
|
||||
EXCEPT_GUARD(Math::instance.setRandomState(luax_checkstring(L, 1));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getRandomState(lua_State *L)
|
||||
{
|
||||
luax_pushstring(L, Math::instance.getRandomState());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_newRandomGenerator(lua_State *L)
|
||||
{
|
||||
RandomGenerator::Seed s;
|
||||
@@ -238,6 +249,70 @@ int w_isConvex(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getGammaArgs(lua_State *L, float color[4])
|
||||
{
|
||||
int numcomponents = 0;
|
||||
|
||||
if (lua_istable(L, 1))
|
||||
{
|
||||
int n = lua_objlen(L, 1);
|
||||
for (int i = 1; i <= n && i <= 4; i++)
|
||||
{
|
||||
lua_rawgeti(L, 1, i);
|
||||
color[i - 1] = (float) luaL_checknumber(L, -1) / 255.0;
|
||||
numcomponents++;
|
||||
}
|
||||
|
||||
lua_pop(L, numcomponents);
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = lua_gettop(L);
|
||||
for (int i = 1; i <= n && i <= 4; i++)
|
||||
{
|
||||
color[i - 1] = (float) luaL_checknumber(L, i) / 255.0;
|
||||
numcomponents++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numcomponents == 0)
|
||||
luaL_checknumber(L, 1);
|
||||
|
||||
return numcomponents;
|
||||
}
|
||||
|
||||
int w_gammaToLinear(lua_State *L)
|
||||
{
|
||||
float color[4];
|
||||
int numcomponents = getGammaArgs(L, color);
|
||||
|
||||
for (int i = 0; i < numcomponents; i++)
|
||||
{
|
||||
// Alpha should always be linear.
|
||||
if (i < 3)
|
||||
color[i] = Math::instance.gammaToLinear(color[i]);
|
||||
lua_pushnumber(L, color[i] * 255);
|
||||
}
|
||||
|
||||
return numcomponents;
|
||||
}
|
||||
|
||||
int w_linearToGamma(lua_State *L)
|
||||
{
|
||||
float color[4];
|
||||
int numcomponents = getGammaArgs(L, color);
|
||||
|
||||
for (int i = 0; i < numcomponents; i++)
|
||||
{
|
||||
// Alpha should always be linear.
|
||||
if (i < 3)
|
||||
color[i] = Math::instance.linearToGamma(color[i]);
|
||||
lua_pushnumber(L, color[i] * 255);
|
||||
}
|
||||
|
||||
return numcomponents;
|
||||
}
|
||||
|
||||
int w_noise(lua_State *L)
|
||||
{
|
||||
float w, x, y, z;
|
||||
@@ -277,14 +352,18 @@ int w_noise(lua_State *L)
|
||||
// List of functions to wrap.
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "setRandomSeed", w_setRandomSeed },
|
||||
{ "getRandomSeed", w_getRandomSeed },
|
||||
{ "random", w_random },
|
||||
{ "randomNormal", w_randomNormal },
|
||||
{ "setRandomSeed", w_setRandomSeed },
|
||||
{ "getRandomSeed", w_getRandomSeed },
|
||||
{ "setRandomState", w_setRandomState },
|
||||
{ "getRandomState", w_getRandomState },
|
||||
{ "newRandomGenerator", w_newRandomGenerator },
|
||||
{ "newBezierCurve", w_newBezierCurve },
|
||||
{ "triangulate", w_triangulate },
|
||||
{ "isConvex", w_isConvex },
|
||||
{ "gammaToLinear", w_gammaToLinear },
|
||||
{ "linearToGamma", w_linearToGamma },
|
||||
{ "noise", w_noise },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
@@ -30,14 +30,18 @@ namespace love
|
||||
namespace math
|
||||
{
|
||||
|
||||
int w_setRandomSeed(lua_State *L);
|
||||
int w_getRandomSeed(lua_State *L);
|
||||
int w_random(lua_State *L);
|
||||
int w_randomNormal(lua_State *L);
|
||||
int w_setRandomSeed(lua_State *L);
|
||||
int w_getRandomSeed(lua_State *L);
|
||||
int w_setRandomState(lua_State *L);
|
||||
int w_getRandomState(lua_State *L);
|
||||
int w_newRandomGenerator(lua_State *L);
|
||||
int w_newBezierCurve(lua_State *L);
|
||||
int w_triangulate(lua_State *L);
|
||||
int w_isConvex(lua_State *L);
|
||||
int w_gammaToLinear(lua_State *L);
|
||||
int w_linearToGamma(lua_State *L);
|
||||
int w_noise(lua_State *L);
|
||||
extern "C" LOVE_EXPORT int luaopen_love_math(lua_State *L);
|
||||
|
||||
|
||||
@@ -47,16 +47,8 @@ RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx)
|
||||
|
||||
if (!lua_isnoneornil(L, idx + 1))
|
||||
{
|
||||
uint32 low = checkrandomseed_part<uint32>(L, idx);
|
||||
uint32 high = checkrandomseed_part<uint32>(L, idx + 1);
|
||||
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
s.b32.a = high;
|
||||
s.b32.b = low;
|
||||
#else
|
||||
s.b32.b = high;
|
||||
s.b32.a = low;
|
||||
#endif
|
||||
s.b32.low = checkrandomseed_part<uint32>(L, idx);
|
||||
s.b32.high = checkrandomseed_part<uint32>(L, idx + 1);
|
||||
}
|
||||
else
|
||||
s.b64 = checkrandomseed_part<uint64>(L, idx);
|
||||
@@ -95,25 +87,6 @@ RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx)
|
||||
return luax_checktype<RandomGenerator>(L, idx, "RandomGenerator", MATH_RANDOM_GENERATOR_T);
|
||||
}
|
||||
|
||||
int w_RandomGenerator_setSeed(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
EXCEPT_GUARD(rng->setSeed(luax_checkrandomseed(L, 2));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_getSeed(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
|
||||
uint32 low = 0, high = 0;
|
||||
rng->getSeed(low, high);
|
||||
|
||||
lua_pushnumber(L, (lua_Number) low);
|
||||
lua_pushnumber(L, (lua_Number) high);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_random(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
@@ -132,12 +105,44 @@ int w_RandomGenerator_randomNormal(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_setSeed(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
EXCEPT_GUARD(rng->setSeed(luax_checkrandomseed(L, 2));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_getSeed(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
RandomGenerator::Seed s = rng->getSeed();
|
||||
lua_pushnumber(L, (lua_Number) s.b32.low);
|
||||
lua_pushnumber(L, (lua_Number) s.b32.high);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_setState(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
EXCEPT_GUARD(rng->setState(luax_checkstring(L, 2));)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_getState(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
luax_pushstring(L, rng->getState());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "setSeed", w_RandomGenerator_setSeed },
|
||||
{ "getSeed", w_RandomGenerator_getSeed },
|
||||
{ "random", w_RandomGenerator_random },
|
||||
{ "randomNormal", w_RandomGenerator_randomNormal },
|
||||
{ "setSeed", w_RandomGenerator_setSeed },
|
||||
{ "getSeed", w_RandomGenerator_getSeed },
|
||||
{ "setState", w_RandomGenerator_setState },
|
||||
{ "getState", w_RandomGenerator_getState },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -36,10 +36,12 @@ RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx);
|
||||
int luax_getrandom(lua_State *L, int startidx, double r);
|
||||
|
||||
RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx);
|
||||
int w_RandomGenerator_setSeed(lua_State *L);
|
||||
int w_RandomGenerator_getSeed(lua_State *L);
|
||||
int w_RandomGenerator_random(lua_State *L);
|
||||
int w_RandomGenerator_randomNormal(lua_State *L);
|
||||
int w_RandomGenerator_setSeed(lua_State *L);
|
||||
int w_RandomGenerator_getSeed(lua_State *L);
|
||||
int w_RandomGenerator_setState(lua_State *L);
|
||||
int w_RandomGenerator_getState(lua_State *L);
|
||||
extern "C" int luaopen_randomgenerator(lua_State *L);
|
||||
|
||||
} // math
|
||||
|
||||
@@ -50,6 +50,7 @@ WindowSettings::WindowSettings()
|
||||
, centered(true)
|
||||
, display(0)
|
||||
, highdpi(false)
|
||||
, sRGB(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -86,6 +87,7 @@ StringMap<Window::Setting, Window::SETTING_MAX_ENUM>::Entry Window::settingEntri
|
||||
{"centered", SETTING_CENTERED},
|
||||
{"display", SETTING_DISPLAY},
|
||||
{"highdpi", SETTING_HIGHDPI},
|
||||
{"srgb", SETTING_SRGB},
|
||||
};
|
||||
|
||||
StringMap<Window::Setting, Window::SETTING_MAX_ENUM> Window::settings(Window::settingEntries, sizeof(Window::settingEntries));
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
SETTING_CENTERED,
|
||||
SETTING_DISPLAY,
|
||||
SETTING_HIGHDPI,
|
||||
SETTING_SRGB,
|
||||
SETTING_MAX_ENUM
|
||||
};
|
||||
|
||||
@@ -157,6 +158,7 @@ struct WindowSettings
|
||||
bool centered; // = true
|
||||
int display; // = 0
|
||||
bool highdpi; // false
|
||||
bool sRGB; // false
|
||||
|
||||
}; // WindowSettings
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
|
||||
f.minwidth = std::max(f.minwidth, 1);
|
||||
f.minheight = std::max(f.minheight, 1);
|
||||
|
||||
f.display = std::min(std::max(f.display, 0), getDisplayCount());
|
||||
f.display = std::min(std::max(f.display, 0), getDisplayCount() - 1);
|
||||
|
||||
// Use the desktop resolution if a width or height of 0 is specified.
|
||||
if (width == 0 || height == 0)
|
||||
@@ -161,7 +161,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
|
||||
if (!window)
|
||||
{
|
||||
// In Windows and Linux, some GL attributes are set on window creation.
|
||||
setWindowGLAttributes(f.fsaa);
|
||||
setWindowGLAttributes(f.fsaa, f.sRGB);
|
||||
|
||||
const char *title = windowTitle.c_str();
|
||||
int pos = f.centered ? centeredpos : uncenteredpos;
|
||||
@@ -197,7 +197,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
|
||||
|
||||
SDL_RaiseWindow(window);
|
||||
|
||||
if (!setContext(f.fsaa, f.vsync))
|
||||
if (!setContext(f.fsaa, f.vsync, f.sRGB))
|
||||
{
|
||||
created = false;
|
||||
return false;
|
||||
@@ -216,7 +216,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
|
||||
SDL_GL_GetDrawableSize(window, &width, &height);
|
||||
#endif
|
||||
|
||||
if (!gfx->setMode(width, height))
|
||||
if (!gfx->setMode(width, height, curMode.settings.sRGB))
|
||||
displayError("Could not set graphics mode", "Unsupported OpenGL version?");
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ bool Window::onWindowResize(int width, int height)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Window::setContext(int fsaa, bool vsync)
|
||||
bool Window::setContext(int fsaa, bool vsync, bool sRGB)
|
||||
{
|
||||
// We would normally only need to recreate the context if FSAA changes or
|
||||
// SDL_GL_MakeCurrent is unsuccessful, but in Windows MakeCurrent can
|
||||
@@ -249,7 +249,7 @@ bool Window::setContext(int fsaa, bool vsync)
|
||||
}
|
||||
|
||||
// Make sure the proper attributes are set.
|
||||
setWindowGLAttributes(fsaa);
|
||||
setWindowGLAttributes(fsaa, sRGB);
|
||||
|
||||
context = SDL_GL_CreateContext(window);
|
||||
|
||||
@@ -301,7 +301,7 @@ bool Window::setContext(int fsaa, bool vsync)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window::setWindowGLAttributes(int fsaa) const
|
||||
void Window::setWindowGLAttributes(int fsaa, bool /* sRGB */) const
|
||||
{
|
||||
// Set GL window attributes.
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
@@ -315,6 +315,15 @@ void Window::setWindowGLAttributes(int fsaa) const
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0);
|
||||
|
||||
/* FIXME: Enable this code but make sure to try to re-create the window and
|
||||
* context with this disabled, if creation fails with it enabled.
|
||||
* We can leave this out for now because in practice the framebuffer will
|
||||
* already be sRGB-capable (on desktops at least.)
|
||||
#if SDL_VERSION_ATLEAST(2,0,1)
|
||||
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, sRGB ? 1 : 0);
|
||||
#endif
|
||||
*/
|
||||
|
||||
int contextprofile = 0;
|
||||
|
||||
bool tryES2 = false;
|
||||
@@ -410,6 +419,8 @@ void Window::updateSettings(const WindowSettings &newsettings)
|
||||
else
|
||||
#endif
|
||||
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
|
||||
|
||||
curMode.settings.sRGB = newsettings.sRGB;
|
||||
}
|
||||
|
||||
void Window::displayError(const std::string &title, const std::string &text) const
|
||||
|
||||
@@ -90,8 +90,8 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
bool setContext(int fsaa, bool vsync);
|
||||
void setWindowGLAttributes(int fsaa) const;
|
||||
bool setContext(int fsaa, bool vsync, bool sRGB);
|
||||
void setWindowGLAttributes(int fsaa, bool sRGB) const;
|
||||
|
||||
// Update the saved window settings based on the window's actual state.
|
||||
void updateSettings(const WindowSettings &newsettings);
|
||||
|
||||
@@ -96,6 +96,7 @@ 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);
|
||||
settings.highdpi = luax_boolflag(L, 3, settingName(Window::SETTING_HIGHDPI), false);
|
||||
settings.sRGB = luax_boolflag(L, 3, settingName(Window::SETTING_SRGB), false);
|
||||
|
||||
// Display index is 1-based in Lua and 0-based internally.
|
||||
settings.display--;
|
||||
@@ -151,6 +152,9 @@ 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));
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
@@ -313,6 +313,7 @@ function love.init()
|
||||
resizable = false,
|
||||
centered = true,
|
||||
highdpi = false,
|
||||
srgb = false,
|
||||
},
|
||||
modules = {
|
||||
event = true,
|
||||
@@ -404,6 +405,7 @@ function love.init()
|
||||
centered = c.window.centered,
|
||||
display = c.window.display,
|
||||
highdpi = c.window.highdpi,
|
||||
srgb = c.window.srgb,
|
||||
}), "Could not set window mode")
|
||||
love.window.setTitle(c.window.title or c.title)
|
||||
if c.window.icon then
|
||||
|
||||
@@ -570,6 +570,7 @@ 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,
|
||||
@@ -705,6 +706,8 @@ 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, 0x7d, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73,
|
||||
0x65, 0x74, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a,
|
||||
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x54,
|
||||
|
||||
Reference in New Issue
Block a user