Merge branch '12.0-development' into GraphicsBuffer

This commit is contained in:
Alex Szpakowski
2020-05-23 20:29:38 -03:00
21 changed files with 745 additions and 766 deletions
+21 -1
View File
@@ -3,7 +3,7 @@ on: [push, pull_request]
jobs:
linux-os:
runs-on: ubuntu-latest
runs-on: ubuntu-16.04
steps:
- name: Update APT
run: sudo apt-get update
@@ -20,6 +20,26 @@ jobs:
run: mkdir build && cd build && ../configure
- name: Build
run: cd build && make -j2
- name: Prepare appimagetool
run: |
cd build &&
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O appimagetool &&
chmod +x appimagetool &&
sudo apt install -y appstream
- name: Clone love-appimages
uses: actions/checkout@v2
with:
path: build/love-appimages
repository: pfirsich/love-appimages
- name: Build AppImage
run: |
cd build &&
python3 love-appimages/build.py .. AppDir --builddir build --appimage love.AppImage
- name: Artifact
uses: actions/upload-artifact@v2-preview
with:
name: love.AppImage
path: build/love.AppImage
windows-os:
runs-on: windows-latest
strategy:
@@ -1873,7 +1873,6 @@
FA620A301AA2F8DB005DB4C2 /* wrap_Texture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Texture.cpp; sourceTree = "<group>"; };
FA620A311AA2F8DB005DB4C2 /* wrap_Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Texture.h; sourceTree = "<group>"; };
FA620A391AA305F6005DB4C2 /* types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types.cpp; sourceTree = "<group>"; };
FA665DC321C34C900074BBD6 /* wrap_GraphicsShader.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = wrap_GraphicsShader.lua; sourceTree = "<group>"; };
FA6A2B641F5F7B6B0074C308 /* wrap_Data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Data.h; sourceTree = "<group>"; };
FA6A2B651F5F7B6B0074C308 /* wrap_Data.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Data.cpp; sourceTree = "<group>"; };
FA6A2B681F5F7F560074C308 /* DataView.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DataView.cpp; sourceTree = "<group>"; };
@@ -2862,7 +2861,6 @@
FADF54391E3DAFF700012CC0 /* wrap_Graphics.cpp */,
FADF543A1E3DAFF700012CC0 /* wrap_Graphics.h */,
FADF54371E3DAFBA00012CC0 /* wrap_Graphics.lua */,
FA665DC321C34C900074BBD6 /* wrap_GraphicsShader.lua */,
FADF54281E3DAADA00012CC0 /* wrap_Mesh.cpp */,
FADF54291E3DAADA00012CC0 /* wrap_Mesh.h */,
FADF541E1E3DA52C00012CC0 /* wrap_ParticleSystem.cpp */,
+73 -36
View File
@@ -104,8 +104,6 @@ bool isDebugEnabled()
love::Type Graphics::type("graphics", &Module::type);
Graphics::DefaultShaderCode Graphics::defaultShaderCode[Shader::STANDARD_MAX_ENUM][Shader::LANGUAGE_MAX_ENUM][2];
Graphics::Graphics()
: width(0)
, height(0)
@@ -216,13 +214,8 @@ love::graphics::ParticleSystem *Graphics::newParticleSystem(Texture *texture, in
return new ParticleSystem(texture, size);
}
ShaderStage *Graphics::newShaderStage(ShaderStage::StageType stage, const std::string &optsource)
ShaderStage *Graphics::newShaderStage(ShaderStage::StageType stage, const std::string &source, const Shader::SourceInfo &info)
{
if (stage == ShaderStage::STAGE_MAX_ENUM)
throw love::Exception("Invalid shader stage.");
const std::string &source = optsource.empty() ? getCurrentDefaultShaderCode().source[stage] : optsource;
ShaderStage *s = nullptr;
std::string cachekey;
@@ -243,7 +236,8 @@ ShaderStage *Graphics::newShaderStage(ShaderStage::StageType stage, const std::s
if (s == nullptr)
{
s = newShaderStageInternal(stage, cachekey, source, getRenderer() == RENDERER_OPENGLES);
std::string glsl = Shader::createShaderStageCode(this, stage, source, info);
s = newShaderStageInternal(stage, cachekey, glsl, getRenderer() == RENDERER_OPENGLES);
if (!cachekey.empty())
cachedShaderStages[stage][cachekey] = s;
}
@@ -251,15 +245,48 @@ ShaderStage *Graphics::newShaderStage(ShaderStage::StageType stage, const std::s
return s;
}
Shader *Graphics::newShader(const std::string &vertex, const std::string &pixel)
Shader *Graphics::newShader(const std::vector<std::string> &stagessource)
{
if (vertex.empty() && pixel.empty())
throw love::Exception("Error creating shader: no source code!");
StrongRef<ShaderStage> stages[ShaderStage::STAGE_MAX_ENUM] = {};
StrongRef<ShaderStage> vertexstage(newShaderStage(ShaderStage::STAGE_VERTEX, vertex), Acquire::NORETAIN);
StrongRef<ShaderStage> pixelstage(newShaderStage(ShaderStage::STAGE_PIXEL, pixel), Acquire::NORETAIN);
bool validstages[ShaderStage::STAGE_MAX_ENUM] = {};
validstages[ShaderStage::STAGE_VERTEX] = true;
validstages[ShaderStage::STAGE_PIXEL] = true;
return newShaderInternal(vertexstage.get(), pixelstage.get());
for (const std::string &source : stagessource)
{
Shader::SourceInfo info = Shader::getSourceInfo(source);
bool isanystage = false;
for (int i = 0; i < ShaderStage::STAGE_MAX_ENUM; i++)
{
if (!validstages[i])
continue;
if (info.isStage[i])
{
isanystage = true;
stages[i].set(newShaderStage((ShaderStage::StageType) i, source, info), Acquire::NORETAIN);
}
}
if (!isanystage)
throw love::Exception("Could not parse shader code (missing 'position' or 'effect' function?)");
}
for (int i = 0; i < ShaderStage::STAGE_MAX_ENUM; i++)
{
auto stype = (ShaderStage::StageType) i;
if (validstages[i] && stages[i].get() == nullptr)
{
const std::string &source = Shader::getDefaultCode(Shader::STANDARD_DEFAULT, stype);
Shader::SourceInfo info = Shader::getSourceInfo(source);
stages[i].set(newShaderStage(stype, source, info), Acquire::NORETAIN);
}
}
return newShaderInternal(stages[ShaderStage::STAGE_VERTEX], stages[ShaderStage::STAGE_PIXEL]);
}
Buffer *Graphics::newBuffer(const Buffer::Settings &settings, DataFormat format, const void *data, size_t size, size_t arraylength)
@@ -293,26 +320,44 @@ void Graphics::cleanupCachedShaderStage(ShaderStage::StageType type, const std::
cachedShaderStages[type].erase(hashkey);
}
bool Graphics::validateShader(bool gles, const std::string &vertex, const std::string &pixel, std::string &err)
bool Graphics::validateShader(bool gles, const std::vector<std::string> &stagessource, std::string &err)
{
if (vertex.empty() && pixel.empty())
{
err = "Error validating shader: no source code!";
return false;
}
StrongRef<ShaderStage> stages[ShaderStage::STAGE_MAX_ENUM] = {};
StrongRef<ShaderStage> vertexstage;
StrongRef<ShaderStage> pixelstage;
bool validstages[ShaderStage::STAGE_MAX_ENUM] = {};
validstages[ShaderStage::STAGE_VERTEX] = true;
validstages[ShaderStage::STAGE_PIXEL] = true;
// Don't use cached shader stages, since the gles flag may not match the
// current renderer.
if (!vertex.empty())
vertexstage.set(new ShaderStageForValidation(this, ShaderStage::STAGE_VERTEX, vertex, gles), Acquire::NORETAIN);
for (const std::string &source : stagessource)
{
Shader::SourceInfo info = Shader::getSourceInfo(source);
bool isanystage = false;
if (!pixel.empty())
pixelstage.set(new ShaderStageForValidation(this, ShaderStage::STAGE_PIXEL, pixel, gles), Acquire::NORETAIN);
for (int i = 0; i < ShaderStage::STAGE_MAX_ENUM; i++)
{
auto stype = (ShaderStage::StageType) i;
return Shader::validate(vertexstage.get(), pixelstage.get(), err);
if (!validstages[i])
continue;
if (info.isStage[i])
{
isanystage = true;
std::string glsl = Shader::createShaderStageCode(this, stype, source, info);
stages[i].set(new ShaderStageForValidation(this, stype, glsl, gles), Acquire::NORETAIN);
}
}
if (!isanystage)
{
err = "Could not parse shader code (missing 'position' or 'effect' function?)";
return false;
}
}
return Shader::validate(stages[ShaderStage::STAGE_VERTEX], stages[ShaderStage::STAGE_PIXEL], err);
}
int Graphics::getWidth() const
@@ -1742,14 +1787,6 @@ Vector2 Graphics::inverseTransformPoint(Vector2 point)
return p;
}
const Graphics::DefaultShaderCode &Graphics::getCurrentDefaultShaderCode() const
{
int languageindex = (int) getShaderLanguageTarget();
int gammaindex = isGammaCorrect() ? 1 : 0;
return defaultShaderCode[Shader::STANDARD_DEFAULT][languageindex][gammaindex];
}
/**
* Constants.
**/
+3 -14
View File
@@ -415,11 +415,6 @@ public:
}
};
struct DefaultShaderCode
{
std::string source[ShaderStage::STAGE_MAX_ENUM];
};
Graphics();
virtual ~Graphics();
@@ -436,8 +431,7 @@ public:
SpriteBatch *newSpriteBatch(Texture *texture, int size, BufferUsage usage);
ParticleSystem *newParticleSystem(Texture *texture, int size);
ShaderStage *newShaderStage(ShaderStage::StageType stage, const std::string &source);
Shader *newShader(const std::string &vertex, const std::string &pixel);
Shader *newShader(const std::vector<std::string> &stagessource);
virtual Buffer *newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength) = 0;
virtual Buffer *newBuffer(const Buffer::Settings &settings, DataFormat format, const void *data, size_t size, size_t arraylength);
@@ -448,7 +442,7 @@ public:
Text *newText(Font *font, const std::vector<Font::ColoredString> &text = {});
bool validateShader(bool gles, const std::string &vertex, const std::string &pixel, std::string &err);
bool validateShader(bool gles, const std::vector<std::string> &stages, std::string &err);
/**
* Resets the current color, background color, line style, and so forth.
@@ -827,9 +821,6 @@ public:
static void flushBatchedDrawsGlobal();
virtual Shader::Language getShaderLanguageTarget() const = 0;
const DefaultShaderCode &getCurrentDefaultShaderCode() const;
void cleanupCachedShaderStage(ShaderStage::StageType type, const std::string &cachekey);
template <typename T>
@@ -869,9 +860,6 @@ public:
static bool getConstant(StackType in, const char *&out);
static std::vector<std::string> getConstants(StackType);
// Default shader code (a shader is always required internally.)
static DefaultShaderCode defaultShaderCode[Shader::STANDARD_MAX_ENUM][Shader::LANGUAGE_MAX_ENUM][2];
protected:
struct DisplayState
@@ -945,6 +933,7 @@ protected:
{}
};
ShaderStage *newShaderStage(ShaderStage::StageType stage, const std::string &source, const Shader::SourceInfo &info);
virtual ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) = 0;
virtual Shader *newShaderInternal(ShaderStage *vertex, ShaderStage *pixel) = 0;
virtual StreamBuffer *newStreamBuffer(BufferType type, size_t size) = 0;
+511 -22
View File
@@ -28,12 +28,402 @@
// C++
#include <string>
#include <regex>
#include <sstream>
namespace love
{
namespace graphics
{
namespace glsl
{
static const char global_syntax[] = R"(
#if !defined(GL_ES) && __VERSION__ < 140
#define lowp
#define mediump
#define highp
#endif
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
#define LOVE_HIGHP_OR_MEDIUMP highp
#else
#define LOVE_HIGHP_OR_MEDIUMP mediump
#endif
#define number float
#define Image sampler2D
#define ArrayImage sampler2DArray
#define CubeImage samplerCube
#define VolumeImage sampler3D
#if __VERSION__ >= 300 && !defined(LOVE_GLSL1_ON_GLSL3)
#define DepthImage sampler2DShadow
#define DepthArrayImage sampler2DArrayShadow
#define DepthCubeImage samplerCubeShadow
#endif
#define extern uniform
#ifdef GL_EXT_texture_array
#extension GL_EXT_texture_array : enable
#endif
#ifdef GL_OES_texture_3D
#extension GL_OES_texture_3D : enable
#endif
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif
)";
static const char global_uniforms[] = R"(
// According to the GLSL ES 1.0 spec, uniform precision must match between stages,
// but we can't guarantee that highp is always supported in fragment shaders...
// We *really* don't want to use mediump for these in vertex shaders though.
uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13];
// These are initialized in love_initializeBuiltinUniforms below. GLSL ES can't
// do it as an initializer.
LOVE_HIGHP_OR_MEDIUMP mat4 TransformMatrix;
LOVE_HIGHP_OR_MEDIUMP mat4 ProjectionMatrix;
LOVE_HIGHP_OR_MEDIUMP mat3 NormalMatrix;
LOVE_HIGHP_OR_MEDIUMP vec4 love_ScreenSize;
LOVE_HIGHP_OR_MEDIUMP vec4 ConstantColor;
#define TransformProjectionMatrix (ProjectionMatrix * TransformMatrix)
// Alternate names
#define ViewSpaceFromLocal TransformMatrix
#define ClipSpaceFromView ProjectionMatrix
#define ClipSpaceFromLocal TransformProjectionMatrix
#define ViewNormalFromLocal NormalMatrix
void love_initializeBuiltinUniforms() {
TransformMatrix = mat4(
love_UniformsPerDraw[0],
love_UniformsPerDraw[1],
love_UniformsPerDraw[2],
love_UniformsPerDraw[3]
);
ProjectionMatrix = mat4(
love_UniformsPerDraw[4],
love_UniformsPerDraw[5],
love_UniformsPerDraw[6],
love_UniformsPerDraw[7]
);
NormalMatrix = mat3(
love_UniformsPerDraw[8].xyz,
love_UniformsPerDraw[9].xyz,
love_UniformsPerDraw[10].xyz
);
love_ScreenSize = love_UniformsPerDraw[11];
ConstantColor = love_UniformsPerDraw[12];
}
)";
static const char global_functions[] = R"(
#ifdef GL_ES
#if __VERSION__ >= 300 || defined(GL_EXT_texture_array)
precision lowp sampler2DArray;
#endif
#if __VERSION__ >= 300 || defined(GL_OES_texture_3D)
precision lowp sampler3D;
#endif
#if __VERSION__ >= 300
precision lowp sampler2DShadow;
precision lowp samplerCubeShadow;
precision lowp sampler2DArrayShadow;
#endif
#endif
#if __VERSION__ >= 130 && !defined(LOVE_GLSL1_ON_GLSL3)
#define Texel texture
#else
#if __VERSION__ >= 130
#define texture2D Texel
#define texture3D Texel
#define textureCube Texel
#define texture2DArray Texel
#define love_texture2D texture
#define love_texture3D texture
#define love_textureCube texture
#define love_texture2DArray texture
#else
#define love_texture2D texture2D
#define love_texture3D texture3D
#define love_textureCube textureCube
#define love_texture2DArray texture2DArray
#endif
vec4 Texel(sampler2D s, vec2 c) { return love_texture2D(s, c); }
vec4 Texel(samplerCube s, vec3 c) { return love_textureCube(s, c); }
#if __VERSION__ > 100 || defined(GL_OES_texture_3D)
vec4 Texel(sampler3D s, vec3 c) { return love_texture3D(s, c); }
#endif
#if __VERSION__ >= 130 || defined(GL_EXT_texture_array)
vec4 Texel(sampler2DArray s, vec3 c) { return love_texture2DArray(s, c); }
#endif
#ifdef PIXEL
vec4 Texel(sampler2D s, vec2 c, float b) { return love_texture2D(s, c, b); }
vec4 Texel(samplerCube s, vec3 c, float b) { return love_textureCube(s, c, b); }
#if __VERSION__ > 100 || defined(GL_OES_texture_3D)
vec4 Texel(sampler3D s, vec3 c, float b) { return love_texture3D(s, c, b); }
#endif
#if __VERSION__ >= 130 || defined(GL_EXT_texture_array)
vec4 Texel(sampler2DArray s, vec3 c, float b) { return love_texture2DArray(s, c, b); }
#endif
#endif
#define texture love_texture
#endif
float gammaToLinearPrecise(float c) {
return c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4);
}
vec3 gammaToLinearPrecise(vec3 c) {
bvec3 leq = lessThanEqual(c, vec3(0.04045));
c.r = leq.r ? c.r / 12.92 : pow((c.r + 0.055) / 1.055, 2.4);
c.g = leq.g ? c.g / 12.92 : pow((c.g + 0.055) / 1.055, 2.4);
c.b = leq.b ? c.b / 12.92 : pow((c.b + 0.055) / 1.055, 2.4);
return c;
}
vec4 gammaToLinearPrecise(vec4 c) { return vec4(gammaToLinearPrecise(c.rgb), c.a); }
float linearToGammaPrecise(float c) {
return c < 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1.0 / 2.4) - 0.055;
}
vec3 linearToGammaPrecise(vec3 c) {
bvec3 lt = lessThanEqual(c, vec3(0.0031308));
c.r = lt.r ? c.r * 12.92 : 1.055 * pow(c.r, 1.0 / 2.4) - 0.055;
c.g = lt.g ? c.g * 12.92 : 1.055 * pow(c.g, 1.0 / 2.4) - 0.055;
c.b = lt.b ? c.b * 12.92 : 1.055 * pow(c.b, 1.0 / 2.4) - 0.055;
return c;
}
vec4 linearToGammaPrecise(vec4 c) { return vec4(linearToGammaPrecise(c.rgb), c.a); }
// http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
mediump float gammaToLinearFast(mediump float c) { return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878); }
mediump vec3 gammaToLinearFast(mediump vec3 c) { return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878); }
mediump vec4 gammaToLinearFast(mediump vec4 c) { return vec4(gammaToLinearFast(c.rgb), c.a); }
mediump float linearToGammaFast(mediump float c) { return max(1.055 * pow(max(c, 0.0), 0.41666666) - 0.055, 0.0); }
mediump vec3 linearToGammaFast(mediump vec3 c) { return max(1.055 * pow(max(c, vec3(0.0)), vec3(0.41666666)) - 0.055, vec3(0.0)); }
mediump vec4 linearToGammaFast(mediump vec4 c) { return vec4(linearToGammaFast(c.rgb), c.a); }
#define gammaToLinear gammaToLinearFast
#define linearToGamma linearToGammaFast
#ifdef LOVE_GAMMA_CORRECT
#define gammaCorrectColor gammaToLinear
#define unGammaCorrectColor linearToGamma
#define gammaCorrectColorPrecise gammaToLinearPrecise
#define unGammaCorrectColorPrecise linearToGammaPrecise
#define gammaCorrectColorFast gammaToLinearFast
#define unGammaCorrectColorFast linearToGammaFast
#else
#define gammaCorrectColor
#define unGammaCorrectColor
#define gammaCorrectColorPrecise
#define unGammaCorrectColorPrecise
#define gammaCorrectColorFast
#define unGammaCorrectColorFast
#endif
)";
static const char vertex_header[] = R"(
#define love_Position gl_Position
#if __VERSION__ >= 130
#define attribute in
#define varying out
#ifndef LOVE_GLSL1_ON_GLSL3
#define love_VertexID gl_VertexID
#define love_InstanceID gl_InstanceID
#endif
#endif
#ifdef GL_ES
uniform mediump float love_PointSize;
#endif
)";
static const char vertex_functions[] = R"(
void setPointSize() {
#ifdef GL_ES
gl_PointSize = love_PointSize;
#endif
}
)";
static const char vertex_main[] = R"(
attribute vec4 VertexPosition;
attribute vec4 VertexTexCoord;
attribute vec4 VertexColor;
varying vec4 VaryingTexCoord;
varying vec4 VaryingColor;
vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition);
void main() {
love_initializeBuiltinUniforms();
VaryingTexCoord = VertexTexCoord;
VaryingColor = gammaCorrectColor(VertexColor) * ConstantColor;
setPointSize();
love_Position = position(ClipSpaceFromLocal, VertexPosition);
}
)";
static const char pixel_header[] = R"(
#ifdef GL_ES
precision mediump float;
#endif
#define love_MaxRenderTargets gl_MaxDrawBuffers
#if __VERSION__ >= 130
#define varying in
// Some drivers seem to make the pixel shader do more work when multiple
// pixel shader outputs are defined, even when only one is actually used.
// TODO: We should use reflection or something instead of this, to determine
// how many outputs are actually used in the shader code.
#ifdef LOVE_MULTI_RENDER_TARGETS
layout(location = 0) out vec4 love_RenderTargets[love_MaxRenderTargets];
#define love_PixelColor love_RenderTargets[0]
#else
layout(location = 0) out vec4 love_PixelColor;
#endif
#else
#ifdef LOVE_MULTI_RENDER_TARGETS
#define love_RenderTargets gl_FragData
#endif
#define love_PixelColor gl_FragColor
#endif
// Legacy
#define love_MaxCanvases love_MaxRenderTargets
#define love_Canvases love_RenderTargets
#ifdef LOVE_MULTI_RENDER_TARGETS
#define LOVE_MULTI_CANVASES 1
#endif
// See Shader::updateScreenParams in Shader.cpp.
#define love_PixelCoord (vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w))
)";
static const char pixel_functions[] = R"(
uniform sampler2D love_VideoYChannel;
uniform sampler2D love_VideoCbChannel;
uniform sampler2D love_VideoCrChannel;
vec4 VideoTexel(vec2 texcoords) {
vec3 yuv;
yuv[0] = Texel(love_VideoYChannel, texcoords).r;
yuv[1] = Texel(love_VideoCbChannel, texcoords).r;
yuv[2] = Texel(love_VideoCrChannel, texcoords).r;
yuv += vec3(-0.0627451017, -0.501960814, -0.501960814);
vec4 color;
color.r = dot(yuv, vec3(1.164, 0.000, 1.596));
color.g = dot(yuv, vec3(1.164, -0.391, -0.813));
color.b = dot(yuv, vec3(1.164, 2.018, 0.000));
color.a = 1.0;
return gammaCorrectColor(color);
}
)";
static const char pixel_main[] = R"(
uniform sampler2D MainTex;
varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
varying mediump vec4 VaryingColor;
vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord);
void main() {
love_initializeBuiltinUniforms();
love_PixelColor = effect(VaryingColor, MainTex, VaryingTexCoord.st, love_PixelCoord);
}
)";
static const char pixel_main_custom[] = R"(
varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
varying mediump vec4 VaryingColor;
void effect();
void main() {
love_initializeBuiltinUniforms();
effect();
}
)";
struct StageInfo
{
const char *name;
const char *header;
const char *functions;
const char *main;
const char *main_custom;
};
static const StageInfo stageInfo[] =
{
{ "VERTEX", vertex_header, vertex_functions, vertex_main, vertex_main },
{ "PIXEL", pixel_header, pixel_functions, pixel_main, pixel_main_custom },
};
static_assert((sizeof(stageInfo) / sizeof(StageInfo)) == ShaderStage::STAGE_MAX_ENUM, "Stages array size must match ShaderStage enum.");
struct Version
{
std::string glsl;
std::string glsles;
};
// Indexed by Shader::Version
static const Version versions[] =
{
{ "#version 120", "#version 100" },
{ "#version 330 core", "#version 300 es" },
{ "#version 430 core", "#version 310 es" },
};
static Shader::Language getTargetLanguage(const std::string &src)
{
std::regex r("^\\s*#pragma language (\\w+)");
std::smatch m;
std::string langstr = std::regex_search(src, m, r) ? m[0] : std::string("glsl1");
Shader::Language lang = Shader::LANGUAGE_MAX_ENUM;
Shader::getConstant(langstr.c_str(), lang);
return lang;
}
static bool isVertexCode(const std::string &src)
{
std::regex r("vec4\\s+position\\s*\\(");
std::smatch m;
return std::regex_search(src, m, r);
}
static bool isPixelCode(const std::string &src, bool &custompixel, bool &mrt)
{
custompixel = false;
mrt = false;
std::smatch m;
if (std::regex_search(src, m, std::regex("vec4\\s+effect\\s*\\(")))
return true;
if (std::regex_search(src, m, std::regex("void\\s+effect\\s*\\(")))
{
custompixel = true;
if (src.find("love_RenderTargets") != std::string::npos || src.find("love_Canvases") != std::string::npos)
mrt = true;
return true;
}
return false;
}
} // glsl
static_assert(sizeof(Shader::BuiltinUniformData) == sizeof(float) * 4 * 13, "Update the array in wrap_GraphicsShader.lua if this changes.");
love::Type Shader::type("Shader", &Object::type);
@@ -41,6 +431,59 @@ love::Type Shader::type("Shader", &Object::type);
Shader *Shader::current = nullptr;
Shader *Shader::standardShaders[Shader::STANDARD_MAX_ENUM] = {nullptr};
Shader::SourceInfo Shader::getSourceInfo(const std::string &src)
{
SourceInfo info = {};
info.language = glsl::getTargetLanguage(src);
info.isStage[ShaderStage::STAGE_VERTEX] = glsl::isVertexCode(src);
info.isStage[ShaderStage::STAGE_PIXEL] = glsl::isPixelCode(src, info.customPixelFunction, info.usesMRT);
return info;
}
std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStage::StageType stage, const std::string &code, const Shader::SourceInfo &info)
{
if (info.language == Shader::LANGUAGE_MAX_ENUM)
throw love::Exception("Invalid shader language");
const auto &features = gfx->getCapabilities().features;
if (info.language == LANGUAGE_GLSL3 && !features[Graphics::FEATURE_GLSL3])
throw love::Exception("GLSL 3 shaders are not supported on this system.");
if (info.language == LANGUAGE_GLSL4 && !features[Graphics::FEATURE_GLSL4])
throw love::Exception("GLSL 4 shaders are not supported on this system.");
bool gles = gfx->getRenderer() == Graphics::RENDERER_OPENGLES;
bool glsl1on3 = info.language == LANGUAGE_GLSL1 && features[Graphics::FEATURE_GLSL3];
Language lang = info.language;
if (glsl1on3)
lang = LANGUAGE_GLSL3;
glsl::StageInfo stageinfo = glsl::stageInfo[stage];
std::stringstream ss;
ss << (gles ? glsl::versions[lang].glsles : glsl::versions[lang].glsl) << "\n";
ss << "#define " << stageinfo.name << " " << stageinfo.name << "\n";
if (glsl1on3)
ss << "#define LOVE_GLSL1_ON_GLSL3 1\n";
if (isGammaCorrect())
ss << "#define LOVE_GAMMA_CORRECT 1\n";
if (info.usesMRT)
ss << "#define LOVE_MULTI_RENDER_TARGETS 1";
ss << glsl::global_syntax;
ss << stageinfo.header;
ss << glsl::global_uniforms;
ss << glsl::global_functions;
ss << stageinfo.functions;
ss << (info.customPixelFunction ? stageinfo.main_custom : stageinfo.main);
ss << ((!gles && (lang == Shader::LANGUAGE_GLSL1 || glsl1on3)) ? "#line 0\n" : "#line 1\n");
ss << code;
return ss.str();
}
Shader::Shader(ShaderStage *vertex, ShaderStage *pixel)
: stages()
{
@@ -157,6 +600,74 @@ void Shader::deinitialize()
glslang::FinalizeProcess();
}
static const std::string defaultVertex = R"(
vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition)
{
return clipSpaceFromLocal * localPosition;
}
)";
static const std::string defaultStandardPixel = R"(
vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord)
{
return Texel(tex, texcoord) * vcolor;
}
)";
static const std::string defaultVideoPixel = R"(
void effect()
{
love_PixelColor = VideoTexel(VaryingTexCoord.xy) * VaryingColor;
}
)";
static const std::string defaultArrayPixel = R"(
uniform ArrayImage MainTex;
void effect()
{
love_PixelColor = Texel(MainTex, VaryingTexCoord.xyz) * VaryingColor;
}
)";
const std::string &Shader::getDefaultCode(StandardShader shader, ShaderStage::StageType stage)
{
if (stage == ShaderStage::STAGE_VERTEX)
return defaultVertex;
static std::string nocode = "";
switch (shader)
{
case STANDARD_DEFAULT: return defaultStandardPixel;
case STANDARD_VIDEO: return defaultVideoPixel;
case STANDARD_ARRAY: return defaultArrayPixel;
case STANDARD_MAX_ENUM: return nocode;
}
return nocode;
}
static StringMap<Shader::Language, Shader::LANGUAGE_MAX_ENUM>::Entry languageEntries[] =
{
{ "glsl1", Shader::LANGUAGE_GLSL1 },
{ "glsl3", Shader::LANGUAGE_GLSL3 },
{ "glsl4", Shader::LANGUAGE_GLSL4 },
};
static StringMap<Shader::Language, Shader::LANGUAGE_MAX_ENUM> languages(languageEntries, sizeof(languageEntries));
static StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry builtinNameEntries[] =
{
{ "MainTex", Shader::BUILTIN_TEXTURE_MAIN },
{ "love_VideoYChannel", Shader::BUILTIN_TEXTURE_VIDEO_Y },
{ "love_VideoCbChannel", Shader::BUILTIN_TEXTURE_VIDEO_CB },
{ "love_VideoCrChannel", Shader::BUILTIN_TEXTURE_VIDEO_CR },
{ "love_UniformsPerDraw", Shader::BUILTIN_UNIFORMS_PER_DRAW },
{ "love_PointSize", Shader::BUILTIN_POINT_SIZE },
};
static StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> builtinNames(builtinNameEntries, sizeof(builtinNameEntries));
bool Shader::getConstant(const char *in, Language &out)
{
return languages.find(in, out);
@@ -177,27 +688,5 @@ bool Shader::getConstant(BuiltinUniform in, const char *&out)
return builtinNames.find(in, out);
}
StringMap<Shader::Language, Shader::LANGUAGE_MAX_ENUM>::Entry Shader::languageEntries[] =
{
{ "glsl1", LANGUAGE_GLSL1 },
{ "essl1", LANGUAGE_ESSL1 },
{ "glsl3", LANGUAGE_GLSL3 },
{ "essl3", LANGUAGE_ESSL3 },
};
StringMap<Shader::Language, Shader::LANGUAGE_MAX_ENUM> Shader::languages(Shader::languageEntries, sizeof(Shader::languageEntries));
StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builtinNameEntries[] =
{
{ "MainTex", BUILTIN_TEXTURE_MAIN },
{ "love_VideoYChannel", BUILTIN_TEXTURE_VIDEO_Y },
{ "love_VideoCbChannel", BUILTIN_TEXTURE_VIDEO_CB },
{ "love_VideoCrChannel", BUILTIN_TEXTURE_VIDEO_CR },
{ "love_UniformsPerDraw", BUILTIN_UNIFORMS_PER_DRAW },
{ "love_PointSize", BUILTIN_POINT_SIZE },
};
StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries));
} // graphics
} // love
+14 -11
View File
@@ -50,9 +50,8 @@ public:
enum Language
{
LANGUAGE_GLSL1,
LANGUAGE_ESSL1,
LANGUAGE_GLSL3,
LANGUAGE_ESSL3,
LANGUAGE_GLSL4,
LANGUAGE_MAX_ENUM
};
@@ -89,6 +88,14 @@ public:
STANDARD_MAX_ENUM
};
struct SourceInfo
{
Language language;
bool isStage[ShaderStage::STAGE_MAX_ENUM];
bool customPixelFunction;
bool usesMRT;
};
struct MatrixSize
{
short columns;
@@ -187,11 +194,16 @@ public:
void checkMainTextureType(TextureType textype, bool isDepthSampler) const;
void checkMainTexture(Texture *texture) const;
static SourceInfo getSourceInfo(const std::string &src);
static std::string createShaderStageCode(Graphics *gfx, ShaderStage::StageType stage, const std::string &code, const SourceInfo &info);
static bool validate(ShaderStage *vertex, ShaderStage *pixel, std::string &err);
static bool initialize();
static void deinitialize();
static const std::string &getDefaultCode(StandardShader shader, ShaderStage::StageType stage);
static bool getConstant(const char *in, Language &out);
static bool getConstant(Language in, const char *&out);
@@ -202,15 +214,6 @@ protected:
StrongRef<ShaderStage> stages[ShaderStage::STAGE_MAX_ENUM];
private:
static StringMap<Language, LANGUAGE_MAX_ENUM>::Entry languageEntries[];
static StringMap<Language, LANGUAGE_MAX_ENUM> languages;
// Names for the built-in uniform variables.
static StringMap<BuiltinUniform, BUILTIN_MAX_ENUM>::Entry builtinNameEntries[];
static StringMap<BuiltinUniform, BUILTIN_MAX_ENUM> builtinNames;
}; // Shader
} // graphics
+7
View File
@@ -202,6 +202,13 @@ bool ShaderStage::getConstant(StageType in, const char *&out)
return stageNames.find(in, out);
}
const char *ShaderStage::getConstant(StageType in)
{
const char *name = nullptr;
getConstant(in, name);
return name;
}
StringMap<ShaderStage::StageType, ShaderStage::STAGE_MAX_ENUM>::Entry ShaderStage::stageNameEntries[] =
{
{ "vertex", STAGE_VERTEX },
+2
View File
@@ -44,6 +44,7 @@ class ShaderStage : public love::Object, public Volatile, public Resource
{
public:
// Order is used for stages array in ShaderStage.cpp
enum StageType
{
STAGE_VERTEX,
@@ -61,6 +62,7 @@ public:
static bool getConstant(const char *in, StageType &out);
static bool getConstant(StageType in, const char *&out);
static const char *getConstant(StageType in);
protected:
+2
View File
@@ -194,6 +194,8 @@ Texture::Texture(const Settings &settings, const Slices *slices)
love::image::ImageDataBase *slice = slices->get(0, 0);
format = slice->getFormat();
if (sRGB)
format = getSRGBPixelFormat(format);
pixelWidth = slice->getWidth();
pixelHeight = slice->getHeight();
+6 -17
View File
@@ -252,12 +252,11 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
// Restore the graphics state.
restoreState(states.back());
int gammacorrect = isGammaCorrect() ? 1 : 0;
Shader::Language target = getShaderLanguageTarget();
// We always need a default shader.
for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++)
{
auto stype = (Shader::StandardShader) i;
if (i == Shader::STANDARD_ARRAY && !capabilities.textureTypes[TEXTURE_2D_ARRAY])
continue;
@@ -267,8 +266,10 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
{
if (!Shader::standardShaders[i])
{
const auto &code = defaultShaderCode[i][target][gammacorrect];
Shader::standardShaders[i] = love::graphics::Graphics::newShader(code.source[ShaderStage::STAGE_VERTEX], code.source[ShaderStage::STAGE_PIXEL]);
std::vector<std::string> stages;
stages.push_back(Shader::getDefaultCode(stype, ShaderStage::STAGE_VERTEX));
stages.push_back(Shader::getDefaultCode(stype, ShaderStage::STAGE_PIXEL));
Shader::standardShaders[i] = newShader(stages);
}
}
catch (love::Exception &)
@@ -1501,18 +1502,6 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, boo
return supported.value;
}
Shader::Language Graphics::getShaderLanguageTarget() const
{
if (gl.isCoreProfile())
return Shader::LANGUAGE_GLSL3;
else if (GLAD_ES_VERSION_3_0)
return Shader::LANGUAGE_ESSL3;
else if (GLAD_ES_VERSION_2_0)
return Shader::LANGUAGE_ESSL1;
else
return Shader::LANGUAGE_GLSL1;
}
} // opengl
} // graphics
} // love
-2
View File
@@ -106,8 +106,6 @@ public:
Renderer getRenderer() const override;
RendererInfo getRendererInfo() const override;
Shader::Language getShaderLanguageTarget() const override;
// Internal use.
void cleanupRenderTexture(love::graphics::Texture *texture);
+8 -3
View File
@@ -1061,7 +1061,7 @@ void OpenGL::setTextureUnit(int textureunit)
state.curTextureUnit = textureunit;
}
void OpenGL::bindTextureToUnit(TextureType target, GLuint texture, int textureunit, bool restoreprev)
void OpenGL::bindTextureToUnit(TextureType target, GLuint texture, int textureunit, bool restoreprev, bool bindforedit)
{
if (texture != state.boundTextures[target][textureunit])
{
@@ -1077,9 +1077,14 @@ void OpenGL::bindTextureToUnit(TextureType target, GLuint texture, int textureun
else
state.curTextureUnit = textureunit;
}
else if (bindforedit && !restoreprev && textureunit != state.curTextureUnit)
{
glActiveTexture(GL_TEXTURE0 + textureunit);
state.curTextureUnit = textureunit;
}
}
void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev)
void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev, bool bindforedit)
{
TextureType textype = TEXTURE_2D;
GLuint handle = 0;
@@ -1101,7 +1106,7 @@ void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restorepr
handle = getDefaultTexture(textype);
}
bindTextureToUnit(textype, handle, textureunit, restoreprev);
bindTextureToUnit(textype, handle, textureunit, restoreprev, bindforedit);
}
void OpenGL::deleteTexture(GLuint texture)
+3 -2
View File
@@ -318,9 +318,10 @@ public:
*
* @param textureunit Index in the range of [0, maxtextureunits-1]
* @param restoreprev Restore previously bound texture unit when done.
* @param bindforedit If false, the active texture unit may be left alone.
**/
void bindTextureToUnit(TextureType target, GLuint texture, int textureunit, bool restoreprev);
void bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev);
void bindTextureToUnit(TextureType target, GLuint texture, int textureunit, bool restoreprev, bool bindforedit = true);
void bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev, bool bindforedit = true);
/**
* Helper for deleting an OpenGL texture.
+2 -2
View File
@@ -440,7 +440,7 @@ void Shader::attach()
{
const TextureUnit &unit = textureUnits[i];
if (unit.active)
gl.bindTextureToUnit(unit.type, unit.texture, i, false);
gl.bindTextureToUnit(unit.type, unit.texture, i, false, false);
}
// send any pending uniforms to the shader program.
@@ -637,7 +637,7 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
int texunit = info->ints[i];
if (shaderactive)
gl.bindTextureToUnit(info->textureType, gltex, texunit, false);
gl.bindTextureToUnit(info->textureType, gltex, texunit, false, false);
// Store texture id so it can be re-bound to the texture unit later.
textureUnits[texunit].texture = gltex;
+12 -101
View File
@@ -45,11 +45,6 @@ static const char graphics_lua[] =
#include "wrap_Graphics.lua"
;
// This is in a separate file because VS2013 has a 16KB limit for raw strings..
static const char graphics_shader_lua[] =
#include "wrap_GraphicsShader.lua"
;
namespace love
{
namespace graphics
@@ -748,15 +743,15 @@ static int w__pushNewTexture(lua_State *L, Texture::Slices *slices, const Textur
static void luax_checktexturesettings(lua_State *L, int idx, bool opt, bool checkType, bool checkDimensions, OptionalBool forceRenderTarget, Texture::Settings &s, bool &setdpiscale)
{
setdpiscale = false;
if (forceRenderTarget.hasValue)
s.renderTarget = forceRenderTarget.value;
if (opt && lua_isnoneornil(L, idx))
return;
luax_checktablefields<Texture::SettingType>(L, idx, "texture setting name", Texture::getConstant);
if (forceRenderTarget.hasValue)
s.renderTarget = forceRenderTarget.value;
else
if (!forceRenderTarget.hasValue)
s.renderTarget = luax_boolflag(L, idx, Texture::getConstant(Texture::SETTING_RENDER_TARGET), s.renderTarget);
lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_FORMAT));
@@ -1366,7 +1361,7 @@ int w_newParticleSystem(lua_State *L)
return 1;
}
static int w_getShaderSource(lua_State *L, int startidx, bool gles, std::string &vertexsource, std::string &pixelsource)
static int w_getShaderSource(lua_State *L, int startidx, std::vector<std::string> &stages)
{
using namespace love::filesystem;
@@ -1426,61 +1421,23 @@ static int w_getShaderSource(lua_State *L, int startidx, bool gles, std::string
if (!(has_arg1 || has_arg2))
luaL_checkstring(L, startidx);
luax_getfunction(L, "graphics", "_shaderCodeToGLSL");
// push vertexcode and pixelcode strings to the top of the stack
lua_pushboolean(L, gles);
if (has_arg1)
lua_pushvalue(L, startidx + 0);
else
lua_pushnil(L);
stages.push_back(luax_checkstring(L, startidx + 0));
if (has_arg2)
lua_pushvalue(L, startidx + 1);
else
lua_pushnil(L);
// call effectCodeToGLSL, returned values will be at the top of the stack
if (lua_pcall(L, 3, 2, 0) != 0)
return luaL_error(L, "%s", lua_tostring(L, -1));
// vertex shader code
if (lua_isstring(L, -2))
vertexsource = luax_checkstring(L, -2);
else if (has_arg1 && has_arg2)
return luaL_error(L, "Could not parse vertex shader code (missing 'position' function?)");
// pixel shader code
if (lua_isstring(L, -1))
pixelsource = luax_checkstring(L, -1);
else if (has_arg1 && has_arg2)
return luaL_error(L, "Could not parse pixel shader code (missing 'effect' function?)");
if (vertexsource.empty() && pixelsource.empty())
{
// Original args had source code, but effectCodeToGLSL couldn't translate it
for (int i = startidx; i < startidx + 2; i++)
{
if (lua_isstring(L, i))
return luaL_argerror(L, i, "missing 'position' or 'effect' function?");
}
}
stages.push_back(luax_checkstring(L, startidx + 1));
return 0;
}
int w_newShader(lua_State *L)
{
bool gles = instance()->getRenderer() == Graphics::RENDERER_OPENGLES;
std::string vertexsource, pixelsource;
w_getShaderSource(L, 1, gles, vertexsource, pixelsource);
std::vector<std::string> stages;
w_getShaderSource(L, 1, stages);
bool should_error = false;
try
{
Shader *shader = instance()->newShader(vertexsource, pixelsource);
Shader *shader = instance()->newShader(stages);
luax_pushtype(L, shader);
shader->release();
}
@@ -1504,14 +1461,14 @@ int w_validateShader(lua_State *L)
{
bool gles = luax_checkboolean(L, 1);
std::string vertexsource, pixelsource;
w_getShaderSource(L, 2, gles, vertexsource, pixelsource);
std::vector<std::string> stages;
w_getShaderSource(L, 2, stages);
bool success = true;
std::string err;
try
{
success = instance()->validateShader(gles, vertexsource, pixelsource, err);
success = instance()->validateShader(gles, stages, err);
}
catch (love::Exception &e)
{
@@ -2312,46 +2269,6 @@ int w_getShader(lua_State *L)
return 1;
}
int w_setDefaultShaderCode(lua_State *L)
{
for (int i = 0; i < 2; i++)
{
luaL_checktype(L, i + 1, LUA_TTABLE);
for (int lang = 0; lang < Shader::LANGUAGE_MAX_ENUM; lang++)
{
const char *langname;
if (!Shader::getConstant((Shader::Language) lang, langname))
continue;
lua_getfield(L, i + 1, langname);
lua_getfield(L, -1, "vertex");
lua_getfield(L, -2, "pixel");
lua_getfield(L, -3, "videopixel");
lua_getfield(L, -4, "arraypixel");
std::string vertex = luax_checkstring(L, -4);
std::string pixel = luax_checkstring(L, -3);
std::string videopixel = luax_checkstring(L, -2);
std::string arraypixel = luax_checkstring(L, -1);
lua_pop(L, 5);
Graphics::defaultShaderCode[Shader::STANDARD_DEFAULT][lang][i].source[ShaderStage::STAGE_VERTEX] = vertex;
Graphics::defaultShaderCode[Shader::STANDARD_DEFAULT][lang][i].source[ShaderStage::STAGE_PIXEL] = pixel;
Graphics::defaultShaderCode[Shader::STANDARD_VIDEO][lang][i].source[ShaderStage::STAGE_VERTEX] = vertex;
Graphics::defaultShaderCode[Shader::STANDARD_VIDEO][lang][i].source[ShaderStage::STAGE_PIXEL] = videopixel;
Graphics::defaultShaderCode[Shader::STANDARD_ARRAY][lang][i].source[ShaderStage::STAGE_VERTEX] = vertex;
Graphics::defaultShaderCode[Shader::STANDARD_ARRAY][lang][i].source[ShaderStage::STAGE_PIXEL] = arraypixel;
}
}
return 0;
}
int w_getSupported(lua_State *L)
{
const Graphics::Capabilities &caps = instance()->getCapabilities();
@@ -3226,7 +3143,6 @@ static const luaL_Reg functions[] =
{ "setShader", w_setShader },
{ "getShader", w_getShader },
{ "_setDefaultShaderCode", w_setDefaultShaderCode },
{ "getSupported", w_getSupported },
{ "getTextureFormats", w_getTextureFormats },
@@ -3343,11 +3259,6 @@ extern "C" int luaopen_love_graphics(lua_State *L)
else
lua_error(L);
if (luaL_loadbuffer(L, (const char *)graphics_shader_lua, sizeof(graphics_shader_lua), "wrap_GraphicsShader.lua") == 0)
lua_call(L, 0, 0);
else
lua_error(L);
return n;
}
@@ -1,503 +0,0 @@
R"luastring"--(
-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string.
-- There is a matching delimiter at the bottom of the file.
--[[
Copyright (c) 2006-2020 LOVE Development Team
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
--]]
local table_concat, table_insert = table.concat, table.insert
local ipairs = ipairs
local GLSL = {}
GLSL.VERSION = { -- index using [target][gles]
glsl1 = {[false]="#version 120", [true]="#version 100"},
glsl3 = {[false]="#version 330 core", [true]="#version 300 es"},
glsl4 = {[false]="#version 430 core", [true]="#version 310 es"},
}
GLSL.SYNTAX = [[
#if !defined(GL_ES) && __VERSION__ < 140
#define lowp
#define mediump
#define highp
#endif
#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH)
#define LOVE_HIGHP_OR_MEDIUMP highp
#else
#define LOVE_HIGHP_OR_MEDIUMP mediump
#endif
#define number float
#define Image sampler2D
#define ArrayImage sampler2DArray
#define CubeImage samplerCube
#define VolumeImage sampler3D
#if __VERSION__ >= 300 && !defined(LOVE_GLSL1_ON_GLSL3)
#define DepthImage sampler2DShadow
#define DepthArrayImage sampler2DArrayShadow
#define DepthCubeImage samplerCubeShadow
#endif
#define extern uniform
#ifdef GL_EXT_texture_array
#extension GL_EXT_texture_array : enable
#endif
#ifdef GL_OES_texture_3D
#extension GL_OES_texture_3D : enable
#endif
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif
]]
-- Uniforms shared by the vertex and pixel shader stages.
GLSL.UNIFORMS = [[
// According to the GLSL ES 1.0 spec, uniform precision must match between stages,
// but we can't guarantee that highp is always supported in fragment shaders...
// We *really* don't want to use mediump for these in vertex shaders though.
uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13];
// These are initialized in love_initializeBuiltinUniforms below. GLSL ES can't
// do it as an initializer.
LOVE_HIGHP_OR_MEDIUMP mat4 TransformMatrix;
LOVE_HIGHP_OR_MEDIUMP mat4 ProjectionMatrix;
LOVE_HIGHP_OR_MEDIUMP mat3 NormalMatrix;
LOVE_HIGHP_OR_MEDIUMP vec4 love_ScreenSize;
LOVE_HIGHP_OR_MEDIUMP vec4 ConstantColor;
#define TransformProjectionMatrix (ProjectionMatrix * TransformMatrix)
// Alternate names
#define ViewSpaceFromLocal TransformMatrix
#define ClipSpaceFromView ProjectionMatrix
#define ClipSpaceFromLocal TransformProjectionMatrix
#define ViewNormalFromLocal NormalMatrix
void love_initializeBuiltinUniforms() {
TransformMatrix = mat4(
love_UniformsPerDraw[0],
love_UniformsPerDraw[1],
love_UniformsPerDraw[2],
love_UniformsPerDraw[3]
);
ProjectionMatrix = mat4(
love_UniformsPerDraw[4],
love_UniformsPerDraw[5],
love_UniformsPerDraw[6],
love_UniformsPerDraw[7]
);
NormalMatrix = mat3(
love_UniformsPerDraw[8].xyz,
love_UniformsPerDraw[9].xyz,
love_UniformsPerDraw[10].xyz
);
love_ScreenSize = love_UniformsPerDraw[11];
ConstantColor = love_UniformsPerDraw[12];
}
]]
GLSL.FUNCTIONS = [[
#ifdef GL_ES
#if __VERSION__ >= 300 || defined(GL_EXT_texture_array)
precision lowp sampler2DArray;
#endif
#if __VERSION__ >= 300 || defined(GL_OES_texture_3D)
precision lowp sampler3D;
#endif
#if __VERSION__ >= 300
precision lowp sampler2DShadow;
precision lowp samplerCubeShadow;
precision lowp sampler2DArrayShadow;
#endif
#endif
#if __VERSION__ >= 130 && !defined(LOVE_GLSL1_ON_GLSL3)
#define Texel texture
#else
#if __VERSION__ >= 130
#define texture2D Texel
#define texture3D Texel
#define textureCube Texel
#define texture2DArray Texel
#define love_texture2D texture
#define love_texture3D texture
#define love_textureCube texture
#define love_texture2DArray texture
#else
#define love_texture2D texture2D
#define love_texture3D texture3D
#define love_textureCube textureCube
#define love_texture2DArray texture2DArray
#endif
vec4 Texel(sampler2D s, vec2 c) { return love_texture2D(s, c); }
vec4 Texel(samplerCube s, vec3 c) { return love_textureCube(s, c); }
#if __VERSION__ > 100 || defined(GL_OES_texture_3D)
vec4 Texel(sampler3D s, vec3 c) { return love_texture3D(s, c); }
#endif
#if __VERSION__ >= 130 || defined(GL_EXT_texture_array)
vec4 Texel(sampler2DArray s, vec3 c) { return love_texture2DArray(s, c); }
#endif
#ifdef PIXEL
vec4 Texel(sampler2D s, vec2 c, float b) { return love_texture2D(s, c, b); }
vec4 Texel(samplerCube s, vec3 c, float b) { return love_textureCube(s, c, b); }
#if __VERSION__ > 100 || defined(GL_OES_texture_3D)
vec4 Texel(sampler3D s, vec3 c, float b) { return love_texture3D(s, c, b); }
#endif
#if __VERSION__ >= 130 || defined(GL_EXT_texture_array)
vec4 Texel(sampler2DArray s, vec3 c, float b) { return love_texture2DArray(s, c, b); }
#endif
#endif
#define texture love_texture
#endif
float gammaToLinearPrecise(float c) {
return c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4);
}
vec3 gammaToLinearPrecise(vec3 c) {
bvec3 leq = lessThanEqual(c, vec3(0.04045));
c.r = leq.r ? c.r / 12.92 : pow((c.r + 0.055) / 1.055, 2.4);
c.g = leq.g ? c.g / 12.92 : pow((c.g + 0.055) / 1.055, 2.4);
c.b = leq.b ? c.b / 12.92 : pow((c.b + 0.055) / 1.055, 2.4);
return c;
}
vec4 gammaToLinearPrecise(vec4 c) { return vec4(gammaToLinearPrecise(c.rgb), c.a); }
float linearToGammaPrecise(float c) {
return c < 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1.0 / 2.4) - 0.055;
}
vec3 linearToGammaPrecise(vec3 c) {
bvec3 lt = lessThanEqual(c, vec3(0.0031308));
c.r = lt.r ? c.r * 12.92 : 1.055 * pow(c.r, 1.0 / 2.4) - 0.055;
c.g = lt.g ? c.g * 12.92 : 1.055 * pow(c.g, 1.0 / 2.4) - 0.055;
c.b = lt.b ? c.b * 12.92 : 1.055 * pow(c.b, 1.0 / 2.4) - 0.055;
return c;
}
vec4 linearToGammaPrecise(vec4 c) { return vec4(linearToGammaPrecise(c.rgb), c.a); }
// http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
mediump float gammaToLinearFast(mediump float c) { return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878); }
mediump vec3 gammaToLinearFast(mediump vec3 c) { return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878); }
mediump vec4 gammaToLinearFast(mediump vec4 c) { return vec4(gammaToLinearFast(c.rgb), c.a); }
mediump float linearToGammaFast(mediump float c) { return max(1.055 * pow(max(c, 0.0), 0.41666666) - 0.055, 0.0); }
mediump vec3 linearToGammaFast(mediump vec3 c) { return max(1.055 * pow(max(c, vec3(0.0)), vec3(0.41666666)) - 0.055, vec3(0.0)); }
mediump vec4 linearToGammaFast(mediump vec4 c) { return vec4(linearToGammaFast(c.rgb), c.a); }
#define gammaToLinear gammaToLinearFast
#define linearToGamma linearToGammaFast
#ifdef LOVE_GAMMA_CORRECT
#define gammaCorrectColor gammaToLinear
#define unGammaCorrectColor linearToGamma
#define gammaCorrectColorPrecise gammaToLinearPrecise
#define unGammaCorrectColorPrecise linearToGammaPrecise
#define gammaCorrectColorFast gammaToLinearFast
#define unGammaCorrectColorFast linearToGammaFast
#else
#define gammaCorrectColor
#define unGammaCorrectColor
#define gammaCorrectColorPrecise
#define unGammaCorrectColorPrecise
#define gammaCorrectColorFast
#define unGammaCorrectColorFast
#endif]]
GLSL.VERTEX = {
HEADER = [[
#define love_Position gl_Position
#if __VERSION__ >= 130
#define attribute in
#define varying out
#ifndef LOVE_GLSL1_ON_GLSL3
#define love_VertexID gl_VertexID
#define love_InstanceID gl_InstanceID
#endif
#endif
#ifdef GL_ES
uniform mediump float love_PointSize;
#endif]],
FUNCTIONS = [[
void setPointSize() {
#ifdef GL_ES
gl_PointSize = love_PointSize;
#endif
}]],
MAIN = [[
attribute vec4 VertexPosition;
attribute vec4 VertexTexCoord;
attribute vec4 VertexColor;
varying vec4 VaryingTexCoord;
varying vec4 VaryingColor;
vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition);
void main() {
love_initializeBuiltinUniforms();
VaryingTexCoord = VertexTexCoord;
VaryingColor = gammaCorrectColor(VertexColor) * ConstantColor;
setPointSize();
love_Position = position(ClipSpaceFromLocal, VertexPosition);
}]],
}
GLSL.PIXEL = {
HEADER = [[
#ifdef GL_ES
precision mediump float;
#endif
#define love_MaxRenderTargets gl_MaxDrawBuffers
#if __VERSION__ >= 130
#define varying in
// Some drivers seem to make the pixel shader do more work when multiple
// pixel shader outputs are defined, even when only one is actually used.
// TODO: We should use reflection or something instead of this, to determine
// how many outputs are actually used in the shader code.
#ifdef LOVE_MULTI_RENDER_TARGETS
layout(location = 0) out vec4 love_RenderTargets[love_MaxRenderTargets];
#define love_PixelColor love_RenderTargets[0]
#else
layout(location = 0) out vec4 love_PixelColor;
#endif
#else
#ifdef LOVE_MULTI_RENDER_TARGETS
#define love_RenderTargets gl_FragData
#endif
#define love_PixelColor gl_FragColor
#endif
// Legacy
#define love_MaxCanvases love_MaxRenderTargets
#define love_Canvases love_RenderTargets
#ifdef LOVE_MULTI_RENDER_TARGETS
#define LOVE_MULTI_CANVASES 1
#endif
// See Shader::updateScreenParams in Shader.cpp.
#define love_PixelCoord (vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w))]],
FUNCTIONS = [[
uniform sampler2D love_VideoYChannel;
uniform sampler2D love_VideoCbChannel;
uniform sampler2D love_VideoCrChannel;
vec4 VideoTexel(vec2 texcoords) {
vec3 yuv;
yuv[0] = Texel(love_VideoYChannel, texcoords).r;
yuv[1] = Texel(love_VideoCbChannel, texcoords).r;
yuv[2] = Texel(love_VideoCrChannel, texcoords).r;
yuv += vec3(-0.0627451017, -0.501960814, -0.501960814);
vec4 color;
color.r = dot(yuv, vec3(1.164, 0.000, 1.596));
color.g = dot(yuv, vec3(1.164, -0.391, -0.813));
color.b = dot(yuv, vec3(1.164, 2.018, 0.000));
color.a = 1.0;
return gammaCorrectColor(color);
}]],
MAIN = [[
uniform sampler2D MainTex;
varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
varying mediump vec4 VaryingColor;
vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord);
void main() {
love_initializeBuiltinUniforms();
love_PixelColor = effect(VaryingColor, MainTex, VaryingTexCoord.st, love_PixelCoord);
}]],
MAIN_CUSTOM = [[
varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
varying mediump vec4 VaryingColor;
void effect();
void main() {
love_initializeBuiltinUniforms();
effect();
}]],
}
local function getLanguageTarget(code)
if not code then return nil end
return (code:match("^%s*#pragma language (%w+)")) or "glsl1"
end
local function createShaderStageCode(stage, code, lang, gles, glsl1on3, gammacorrect, custom, multirendertarget)
stage = stage:upper()
local lines = {
GLSL.VERSION[lang][gles],
"#define " ..stage .. " " .. stage,
glsl1on3 and "#define LOVE_GLSL1_ON_GLSL3 1" or "",
gammacorrect and "#define LOVE_GAMMA_CORRECT 1" or "",
multirendertarget and "#define LOVE_MULTI_RENDER_TARGETS 1" or "",
GLSL.SYNTAX,
GLSL[stage].HEADER,
GLSL.UNIFORMS,
GLSL.FUNCTIONS,
GLSL[stage].FUNCTIONS,
custom and GLSL[stage].MAIN_CUSTOM or GLSL[stage].MAIN,
((lang == "glsl1" or glsl1on3) and not gles) and "#line 0" or "#line 1",
code,
}
return table_concat(lines, "\n")
end
local function isVertexCode(code)
return code:match("vec4%s+position%s*%(") ~= nil
end
local function isPixelCode(code)
if code:match("vec4%s+effect%s*%(") then
return true
elseif code:match("void%s+effect%s*%(") then -- custom effect function
local multirendertargets = (code:match("love_RenderTargets") ~= nil) or (code:match("love_Canvases") ~= nil)
return true, true, multirendertargets
else
return false
end
end
function love.graphics._shaderCodeToGLSL(gles, arg1, arg2)
local vertexcode, pixelcode
local is_custompixel = false -- whether pixel code has "effects" function instead of "effect"
local is_multicanvas = false
if arg1 then
if isVertexCode(arg1) then
vertexcode = arg1 -- first arg contains vertex shader code
end
local ispixel, isCustomPixel, isMultiCanvas = isPixelCode(arg1)
if ispixel then
pixelcode = arg1 -- first arg contains pixel shader code
is_custompixel, is_multicanvas = isCustomPixel, isMultiCanvas
end
end
if arg2 then
if isVertexCode(arg2) then
vertexcode = arg2 -- second arg contains vertex shader code
end
local ispixel, isCustomPixel, isMultiCanvas = isPixelCode(arg2)
if ispixel then
pixelcode = arg2 -- second arg contains pixel shader code
is_custompixel, is_multicanvas = isCustomPixel, isMultiCanvas
end
end
local graphicsfeatures = love.graphics.getSupported()
local supportsGLSL3 = graphicsfeatures.glsl3
local supportsGLSL4 = graphicsfeatures.glsl4
local gammacorrect = love.graphics.isGammaCorrect()
local targetlang = getLanguageTarget(pixelcode or vertexcode)
if getLanguageTarget(vertexcode or pixelcode) ~= targetlang then
error("vertex and pixel shader languages must match", 2)
end
if targetlang == "glsl3" and not supportsGLSL3 then
error("GLSL 3 shaders are not supported on this system.", 2)
end
if targetlang == "glsl4" and not supportsGLSL4 then
error("GLSL 4 shaders are not supported on this system.", 2)
end
if targetlang ~= nil and not GLSL.VERSION[targetlang] then
error("Invalid shader language: " .. targetlang, 2)
end
local lang = targetlang or "glsl1"
local glsl1on3 = false
if lang == "glsl1" and supportsGLSL3 then
lang = "glsl3"
glsl1on3 = true
end
if vertexcode then
vertexcode = createShaderStageCode("VERTEX", vertexcode, lang, gles, glsl1on3, gammacorrect)
end
if pixelcode then
pixelcode = createShaderStageCode("PIXEL", pixelcode, lang, gles, glsl1on3, gammacorrect, is_custompixel, is_multicanvas)
end
return vertexcode, pixelcode
end
local defaultcode = {
vertex = [[
vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition) {
return clipSpaceFromLocal * localPosition;
}]],
pixel = [[
vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord) {
return Texel(tex, texcoord) * vcolor;
}]],
videopixel = [[
void effect() {
love_PixelColor = VideoTexel(VaryingTexCoord.xy) * VaryingColor;
}]],
arraypixel = [[
uniform ArrayImage MainTex;
void effect() {
love_PixelColor = Texel(MainTex, VaryingTexCoord.xyz) * VaryingColor;
}]],
}
local defaults = {}
local defaults_gammacorrect = {}
local langs = {
glsl1 = {target="glsl1", gles=false},
essl1 = {target="glsl1", gles=true},
glsl3 = {target="glsl3", gles=false},
essl3 = {target="glsl3", gles=true},
}
for lang, info in pairs(langs) do
for _, gammacorrect in ipairs{false, true} do
local t = gammacorrect and defaults_gammacorrect or defaults
t[lang] = {
vertex = createShaderStageCode("VERTEX", defaultcode.vertex, info.target, info.gles, false, gammacorrect),
pixel = createShaderStageCode("PIXEL", defaultcode.pixel, info.target, info.gles, false, gammacorrect, false),
videopixel = createShaderStageCode("PIXEL", defaultcode.videopixel, info.target, info.gles, false, gammacorrect, true),
arraypixel = createShaderStageCode("PIXEL", defaultcode.arraypixel, info.target, info.gles, false, gammacorrect, true),
}
end
end
love.graphics._setDefaultShaderCode(defaults, defaults_gammacorrect)
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
--)luastring"--"
+2 -1
View File
@@ -30,12 +30,13 @@ static void loveSTBIAssert(bool test, const char *teststr)
}
// stb_image
#define STBI_ONLY_JPEG
#define STBI_ONLY_JPEG
// #define STBI_ONLY_PNG
#define STBI_ONLY_BMP
#define STBI_ONLY_TGA
#define STBI_ONLY_HDR
#define STBI_NO_STDIO
#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#define STBI_ASSERT(A) loveSTBIAssert((A), #A)
#include "libraries/stb/stb_image.h"
+70 -39
View File
@@ -24,6 +24,7 @@
#include "common/delay.h"
#include "Timer.h"
#include <iostream>
#if defined(LOVE_WINDOWS)
#include <windows.h>
#elif defined(LOVE_MACOS) || defined(LOVE_IOS)
@@ -35,15 +36,6 @@
#include <sys/time.h>
#endif
#if defined(LOVE_LINUX)
static inline double getTimeOfDay()
{
timeval t;
gettimeofday(&t, NULL);
return (double) t.tv_sec + (double) t.tv_usec / 1000000.0;
}
#endif
namespace love
{
namespace timer
@@ -109,52 +101,91 @@ double Timer::getAverageDelta() const
return averageDelta;
}
double Timer::getTimerPeriod()
#if defined(LOVE_LINUX)
static inline timespec getTimeOfDay()
{
#if defined(LOVE_MACOS) || defined(LOVE_IOS)
mach_timebase_info_data_t info;
mach_timebase_info(&info);
return (double) info.numer / (double) info.denom / 1000000000.0;
#elif defined(LOVE_WINDOWS)
LARGE_INTEGER temp;
if (QueryPerformanceFrequency(&temp) != 0 && temp.QuadPart != 0)
return 1.0 / (double) temp.QuadPart;
#endif
return 0;
timeval t;
gettimeofday(&t, NULL);
return timespec { t.tv_sec, t.tv_usec * 1000 };
}
double Timer::getTime()
static timespec getTimeAbsolute()
{
// The timer period (reciprocal of the frequency.)
static const double timerPeriod = getTimerPeriod();
#if defined(LOVE_LINUX)
(void) timerPeriod; // Unused on linux
double mt;
// Check for POSIX timers and monotonic clocks. If not supported, use the gettimeofday fallback.
#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) \
&& (defined(CLOCK_MONOTONIC_RAW) || defined(CLOCK_MONOTONIC))
timespec t;
#ifdef CLOCK_MONOTONIC_RAW
clockid_t clk_id = CLOCK_MONOTONIC_RAW;
#else
clockid_t clk_id = CLOCK_MONOTONIC;
#endif
timespec t;
if (clock_gettime(clk_id, &t) == 0)
mt = (double) t.tv_sec + (double) t.tv_nsec / 1000000000.0;
return t;
else
return getTimeOfDay();
#endif
mt = getTimeOfDay();
return mt;
#elif defined(LOVE_MACOS) || defined(LOVE_IOS)
return (double) mach_absolute_time() * timerPeriod;
#elif defined(LOVE_WINDOWS)
LARGE_INTEGER microTime;
QueryPerformanceCounter(&microTime);
return (double) microTime.QuadPart * timerPeriod;
#endif
return getTimeOfDay();
}
double Timer::getTime()
{
static const timespec start = getTimeAbsolute();
const timespec now = getTimeAbsolute();
// tv_sec and tv_nsec should be signed on POSIX, so we are fine in just subtracting here.
const long sec = now.tv_sec - start.tv_sec;
const long nsec = now.tv_nsec - start.tv_nsec;
return (double) sec + (double) nsec / 1.0e9;
}
#elif defined(LOVE_MACOS) || defined(LOVE_IOS)
static mach_timebase_info_data_t getTimebaseInfo()
{
mach_timebase_info_data_t info;
mach_timebase_info(&info);
return info;
}
double Timer::getTime()
{
static const mach_timebase_info_data_t info = getTimebaseInfo();
static const uint64_t start = mach_absolute_time();
const uint64_t rel = mach_absolute_time() - start;
return ((double) rel * 1.0e-9) * (double) info.numer / (double) info.denom;
}
#elif defined(LOVE_WINDOWS)
static LARGE_INTEGER getTimeAbsolute()
{
LARGE_INTEGER t;
QueryPerformanceCounter(&t);
return t;
}
static LARGE_INTEGER getFrequency()
{
LARGE_INTEGER freq;
// "On systems that run Windows XP or later, the function will always succeed and will thus never return zero."
QueryPerformanceFrequency(&freq);
return freq;
}
double Timer::getTime()
{
static const LARGE_INTEGER freq = getFrequency();
static const LARGE_INTEGER start = getTimeAbsolute();
const LARGE_INTEGER now = getTimeAbsolute();
LARGE_INTEGER rel;
rel.QuadPart = now.QuadPart - start.QuadPart;
return (double) rel.QuadPart / (double) freq.QuadPart;
}
#endif
} // timer
} // love
+5 -6
View File
@@ -72,9 +72,11 @@ public:
double getAverageDelta() const;
/**
* Gets the amount of time passed since an unspecified time. Useful for
* profiling code or measuring intervals. The time is microsecond-precise,
* and increases monotonically.
* Gets the amount of time in seconds passed since its first invocation
* (which happens as part of the Timer constructor,
* which is called when the module is first opened).
* Useful for profiling code or measuring intervals.
* The time is microsecond-precise, and increases monotonically.
* @return The time (in seconds)
**/
static double getTime();
@@ -99,9 +101,6 @@ private:
// The current timestep.
double dt;
// Returns the timer period on some platforms.
static double getTimerPeriod();
}; // Timer
} // timer
+1 -1
View File
@@ -532,6 +532,7 @@ function love.init()
-- Setup window here.
if c.window and c.modules.window then
love.window.setTitle(c.window.title or c.title)
assert(love.window.setMode(c.window.width, c.window.height,
{
fullscreen = c.window.fullscreen,
@@ -551,7 +552,6 @@ function love.init()
x = c.window.x,
y = c.window.y,
}), "Could not set window mode")
love.window.setTitle(c.window.title or c.title)
if c.window.icon then
assert(love.image, "If an icon is set in love.conf, love.image must be loaded!")
love.window.setIcon(love.image.newImageData(c.window.icon))
+3 -3
View File
@@ -1055,6 +1055,9 @@ const unsigned char boot_lua[] =
0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63,
0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x74, 0x68,
0x65, 0x6e, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x54,
0x69, 0x74, 0x6c, 0x65, 0x28, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x74, 0x69, 0x74, 0x6c,
0x65, 0x20, 0x6f, 0x72, 0x20, 0x63, 0x2e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x0a,
0x09, 0x09, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64,
0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f,
0x77, 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e,
@@ -1094,9 +1097,6 @@ const unsigned char boot_lua[] =
0x09, 0x09, 0x09, 0x79, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x79, 0x2c, 0x0a,
0x09, 0x09, 0x7d, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73,
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,
0x69, 0x74, 0x6c, 0x65, 0x28, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x74, 0x69, 0x74, 0x6c,
0x65, 0x20, 0x6f, 0x72, 0x20, 0x63, 0x2e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x29, 0x0a,
0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x69, 0x63, 0x6f, 0x6e,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x09, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6d, 0x61,