Add initial video playback support for Ogg Theora videos (resolves issue #66.)

The basic APIs are:

video = love.graphics.newVideo("myvideo.ogv")

love.graphics.draw(video, ...) -- Video objects are Drawables.

video:play(), video:pause()

video:getDuration(), video:tell(), video:rewind(), video:seek(seconds)

video:getSource()

video:getWidth(), video:getHeight(), video:setFilter(min, mag)

More advanced APIs include video:setSource(source), video:getStream(), and videostream:setSync.

To use a custom pixel shader when drawing a Video, call the new TexelVideo(texcoords) function instead of Texel(texture, texcoords) in order to get the pixel colors of a video frame.
This commit is contained in:
Bart van Strien
2015-12-08 22:41:19 -04:00
parent a1dab12117
commit 22f2175bec
41 changed files with 2241 additions and 20 deletions
+17
View File
@@ -86,6 +86,11 @@ Graphics::~Graphics()
Shader::defaultShader->release();
Shader::defaultShader = nullptr;
}
if (Shader::defaultVideoShader)
{
Shader::defaultVideoShader->release();
Shader::defaultVideoShader = nullptr;
}
if (quadIndices)
delete quadIndices;
@@ -320,6 +325,13 @@ bool Graphics::setMode(int width, int height)
Shader::defaultShader = newShader(Shader::defaultCode[renderer]);
}
// and a default video shader.
if (!Shader::defaultVideoShader)
{
Renderer renderer = GLAD_ES_VERSION_2_0 ? RENDERER_OPENGLES : RENDERER_OPENGL;
Shader::defaultVideoShader = newShader(Shader::defaultVideoCode[renderer]);
}
// A shader should always be active, but the default shader shouldn't be
// returned by getShader(), so we don't do setShader(defaultShader).
if (!Shader::current)
@@ -819,6 +831,11 @@ Text *Graphics::newText(Font *font, const std::vector<Font::ColoredString> &text
return new Text(font, text);
}
Video *Graphics::newVideo(love::video::VideoStream *stream)
{
return new Video(stream);
}
bool Graphics::isGammaCorrect() const
{
return love::graphics::isGammaCorrect();
+5
View File
@@ -37,6 +37,8 @@
#include "window/Window.h"
#include "video/VideoStream.h"
#include "Font.h"
#include "Image.h"
#include "graphics/Quad.h"
@@ -47,6 +49,7 @@
#include "Shader.h"
#include "Mesh.h"
#include "Text.h"
#include "Video.h"
namespace love
{
@@ -185,6 +188,8 @@ public:
Text *newText(Font *font, const std::vector<Font::ColoredString> &text = {});
Video *newVideo(love::video::VideoStream *stream);
bool isGammaCorrect() const;
/**
+60
View File
@@ -64,8 +64,10 @@ namespace
Shader *Shader::current = nullptr;
Shader *Shader::defaultShader = nullptr;
Shader *Shader::defaultVideoShader = nullptr;
Shader::ShaderSource Shader::defaultCode[Graphics::RENDERER_MAX_ENUM];
Shader::ShaderSource Shader::defaultVideoCode[Graphics::RENDERER_MAX_ENUM];
std::vector<int> Shader::textureCounters;
@@ -77,6 +79,7 @@ Shader::Shader(const ShaderSource &source)
, lastCanvas((Canvas *) -1)
, lastViewport()
, lastPointSize(0.0f)
, videoTextureUnits()
{
if (source.vertex.empty() && source.pixel.empty())
throw love::Exception("Cannot create shader: no source code!");
@@ -225,6 +228,9 @@ bool Shader::loadVolatile()
lastProjectionMatrix.setTranslation(nan, nan);
lastTransformMatrix.setTranslation(nan, nan);
for (int i = 0; i < 3; i++)
videoTextureUnits[i] = 0;
// zero out active texture list
activeTexUnits.clear();
activeTexUnits.insert(activeTexUnits.begin(), gl.getMaxTextureUnits() - 1, 0);
@@ -635,6 +641,57 @@ bool Shader::hasVertexAttrib(VertexAttribID attrib) const
return builtinAttributes[int(attrib)] != -1;
}
void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtexture)
{
TemporaryAttacher attacher(this);
// Set up the texture units that will be used by the shader to sample from
// the textures, if they haven't been set up yet.
if (videoTextureUnits[0] == 0)
{
const GLint locs[3] = {
builtinUniforms[BUILTIN_VIDEO_Y_CHANNEL],
builtinUniforms[BUILTIN_VIDEO_CB_CHANNEL],
builtinUniforms[BUILTIN_VIDEO_CR_CHANNEL]
};
const char *names[3] = {nullptr, nullptr, nullptr};
builtinNames.find(BUILTIN_VIDEO_Y_CHANNEL, names[0]);
builtinNames.find(BUILTIN_VIDEO_CB_CHANNEL, names[1]);
builtinNames.find(BUILTIN_VIDEO_CR_CHANNEL, names[2]);
for (int i = 0; i < 3; i++)
{
if (locs[i] >= 0 && names[i] != nullptr)
{
videoTextureUnits[i] = getTextureUnit(names[i]);
// Increment global shader texture id counter for this texture
// unit, if we haven't already.
if (activeTexUnits[videoTextureUnits[i] - 1] == 0)
++textureCounters[videoTextureUnits[i] - 1];
glUniform1i(locs[i], videoTextureUnits[i]);
}
}
}
const GLuint textures[3] = {ytexture, cbtexture, crtexture};
// Bind the textures to their respective texture units.
for (int i = 0; i < 3; i++)
{
if (videoTextureUnits[i] != 0)
{
// Store texture id so it can be re-bound later.
activeTexUnits[videoTextureUnits[i] - 1] = textures[i];
gl.bindTextureToUnit(textures[i], videoTextureUnits[i], false);
}
}
gl.setTextureUnit(0);
}
void Shader::checkSetScreenParams()
{
OpenGL::Viewport view = gl.getViewport();
@@ -898,6 +955,9 @@ StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::built
{"NormalMatrix", Shader::BUILTIN_NORMAL_MATRIX},
{"love_PointSize", Shader::BUILTIN_POINT_SIZE},
{"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE},
{"love_VideoYChannel", Shader::BUILTIN_VIDEO_Y_CHANNEL},
{"love_VideoCbChannel", Shader::BUILTIN_VIDEO_CB_CHANNEL},
{"love_VideoCrChannel", Shader::BUILTIN_VIDEO_CR_CHANNEL},
};
StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries));
+8
View File
@@ -64,6 +64,9 @@ public:
BUILTIN_NORMAL_MATRIX,
BUILTIN_POINT_SIZE,
BUILTIN_SCREEN_SIZE,
BUILTIN_VIDEO_Y_CHANNEL,
BUILTIN_VIDEO_CB_CHANNEL,
BUILTIN_VIDEO_CR_CHANNEL,
BUILTIN_MAX_ENUM
};
@@ -89,9 +92,11 @@ public:
// Pointer to the default Shader.
static Shader *defaultShader;
static Shader *defaultVideoShader;
// Default shader code (a shader is always required internally.)
static ShaderSource defaultCode[Graphics::RENDERER_MAX_ENUM];
static ShaderSource defaultVideoCode[Graphics::RENDERER_MAX_ENUM];
/**
* Creates a new Shader using a list of source codes.
@@ -182,6 +187,7 @@ public:
**/
bool hasVertexAttrib(VertexAttribID attrib) const;
void setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtexture);
void checkSetScreenParams();
void checkSetPointSize(float size);
void checkSetBuiltinUniforms();
@@ -263,6 +269,8 @@ private:
Matrix4 lastTransformMatrix;
Matrix4 lastProjectionMatrix;
GLuint videoTextureUnits[3];
// Counts total number of textures bound to each texture unit in all shaders
static std::vector<int> textureCounters;
+212
View File
@@ -0,0 +1,212 @@
/**
* Copyright (c) 2006-2015 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.
**/
#include "Video.h"
// LOVE
#include "Shader.h"
namespace love
{
namespace graphics
{
namespace opengl
{
Video::Video(love::video::VideoStream *stream)
: stream(stream)
, filter(Texture::getDefaultFilter())
{
filter.mipmap = Texture::FILTER_NONE;
stream->fillBackBuffer();
for (int i = 0; i < 4; i++)
vertices[i].r = vertices[i].g = vertices[i].b = vertices[i].a = 255;
// Vertices are ordered for use with triangle strips:
// 0----2
// | / |
// | / |
// 1----3
vertices[0].x = 0.0f;
vertices[0].y = 0.0f;
vertices[1].x = 0.0f;
vertices[1].y = (float) stream->getHeight();
vertices[2].x = (float) stream->getWidth();
vertices[2].y = 0.0f;
vertices[3].x = (float) stream->getWidth();
vertices[3].y = (float) stream->getHeight();
vertices[0].s = 0.0f;
vertices[0].t = 0.0f;
vertices[1].s = 0.0f;
vertices[1].t = 1.0f;
vertices[2].s = 1.0f;
vertices[2].t = 0.0f;
vertices[3].s = 1.0f;
vertices[3].t = 1.0f;
loadVolatile();
}
Video::~Video()
{
unloadVolatile();
}
bool Video::loadVolatile()
{
glGenTextures(3, &textures[0]);
// Create the textures using the initial frame data.
auto frame = (const love::video::VideoStream::Frame*) stream->getFrontBuffer();
gl.bindTexture(textures[0]);
gl.setTextureFilter(filter);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, frame->yw, frame->yh,
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->yplane);
gl.bindTexture(textures[1]);
gl.setTextureFilter(filter);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, frame->cw, frame->ch,
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->cbplane);
gl.bindTexture(textures[2]);
gl.setTextureFilter(filter);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, frame->cw, frame->ch,
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->crplane);
return true;
}
void Video::unloadVolatile()
{
for (int i = 0; i < 3; i++)
{
gl.deleteTexture(textures[i]);
textures[i] = 0;
}
}
love::video::VideoStream *Video::getStream()
{
return stream;
}
void Video::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{
update();
Shader *shader = Shader::current;
bool defaultShader = (shader == Shader::defaultShader);
if (defaultShader)
{
// If we're still using the default shader, substitute the video version
Shader::defaultVideoShader->attach();
shader = Shader::defaultVideoShader;
}
shader->setVideoTextures(textures[0], textures[1], textures[2]);
OpenGL::TempTransform transform(gl);
transform.get() *= Matrix4(x, y, angle, sx, sy, ox, oy, kx, ky);
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertices[0].x);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &vertices[0].s);
gl.prepareDraw();
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
// If we were using the default shader, reattach it
if (defaultShader)
Shader::defaultShader->attach();
}
void Video::update()
{
bool bufferschanged = stream->swapBuffers();
stream->fillBackBuffer();
if (bufferschanged)
{
auto frame = (const love::video::VideoStream::Frame*) stream->getFrontBuffer();
gl.bindTexture(textures[0]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame->yw, frame->yh,
GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->yplane);
gl.bindTexture(textures[1]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame->cw, frame->ch,
GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->cbplane);
gl.bindTexture(textures[2]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame->cw, frame->ch,
GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->crplane);
}
}
love::audio::Source *Video::getSource()
{
return source;
}
void Video::setSource(love::audio::Source *source)
{
this->source = source;
}
int Video::getWidth() const
{
return stream->getWidth();
}
int Video::getHeight() const
{
return stream->getHeight();
}
void Video::setFilter(const Texture::Filter &f)
{
if (!Texture::validateFilter(f, false))
throw love::Exception("Invalid texture filter.");
filter = f;
for (int i = 0; i < 3; i++)
{
gl.bindTexture(textures[i]);
gl.setTextureFilter(filter);
}
}
const Texture::Filter &Video::getFilter() const
{
return filter;
}
} // opengl
} // graphics
} // love
+79
View File
@@ -0,0 +1,79 @@
/**
* Copyright (c) 2006-2015 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.
**/
#pragma once
// LOVE
#include "common/math.h"
#include "graphics/Drawable.h"
#include "graphics/Volatile.h"
#include "video/VideoStream.h"
#include "audio/Source.h"
#include "OpenGL.h"
namespace love
{
namespace graphics
{
namespace opengl
{
class Video : public Drawable, public Volatile
{
public:
Video(love::video::VideoStream *stream);
~Video();
// Volatile
bool loadVolatile();
void unloadVolatile();
love::video::VideoStream *getStream();
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
love::audio::Source *getSource();
void setSource(love::audio::Source *source);
int getWidth() const;
int getHeight() const;
void setFilter(const Texture::Filter &f);
const Texture::Filter &getFilter() const;
private:
void update();
StrongRef<love::video::VideoStream> stream;
StrongRef<love::audio::Source> source;
GLuint textures[3];
Vertex vertices[4];
Texture::Filter filter;
}; // Video
} // opengl
} // graphics
} // love
+35 -6
View File
@@ -25,6 +25,7 @@
#include "image/Image.h"
#include "font/Rasterizer.h"
#include "filesystem/wrap_Filesystem.h"
#include "video/VideoStream.h"
#include "image/wrap_Image.h"
#include <cassert>
@@ -862,6 +863,20 @@ int w_newText(lua_State *L)
return 1;
}
int w_newVideo(lua_State *L)
{
if (!luax_istype(L, 1, VIDEO_VIDEO_STREAM_ID))
luax_convobj(L, 1, "video", "newVideoStream");
auto stream = luax_checktype<love::video::VideoStream>(L, 1, VIDEO_VIDEO_STREAM_ID);
Video *video = nullptr;
luax_catchexcept(L, [&]() { video = instance()->newVideo(stream); });
luax_pushtype(L, GRAPHICS_VIDEO_ID, video);
video->release();
return 1;
}
int w_setColor(lua_State *L)
{
Colorf c;
@@ -1274,25 +1289,37 @@ int w_setDefaultShaderCode(lua_State *L)
lua_getfield(L, 1, "opengl");
lua_rawgeti(L, -1, 1);
lua_rawgeti(L, -2, 2);
lua_rawgeti(L, -3, 3);
Shader::ShaderSource openglcode;
openglcode.vertex = luax_checkstring(L, -2);
openglcode.pixel = luax_checkstring(L, -1);
openglcode.vertex = luax_checkstring(L, -3);
openglcode.pixel = luax_checkstring(L, -2);
lua_pop(L, 3);
Shader::ShaderSource openglVideocode;
openglVideocode.vertex = luax_checkstring(L, -3);
openglVideocode.pixel = luax_checkstring(L, -1);
lua_pop(L, 4);
lua_getfield(L, 1, "opengles");
lua_rawgeti(L, -1, 1);
lua_rawgeti(L, -2, 2);
lua_rawgeti(L, -3, 3);
Shader::ShaderSource openglescode;
openglescode.vertex = luax_checkstring(L, -2);
openglescode.pixel = luax_checkstring(L, -1);
openglescode.vertex = luax_checkstring(L, -3);
openglescode.pixel = luax_checkstring(L, -2);
lua_pop(L, 3);
Shader::ShaderSource openglesVideocode;
openglesVideocode.vertex = luax_checkstring(L, -3);
openglesVideocode.pixel = luax_checkstring(L, -1);
lua_pop(L, 4);
Shader::defaultCode[Graphics::RENDERER_OPENGL] = openglcode;
Shader::defaultCode[Graphics::RENDERER_OPENGLES] = openglescode;
Shader::defaultVideoCode[Graphics::RENDERER_OPENGL] = openglVideocode;
Shader::defaultVideoCode[Graphics::RENDERER_OPENGLES] = openglesVideocode;
return 0;
}
@@ -1863,6 +1890,7 @@ static const luaL_Reg functions[] =
{ "newShader", w_newShader },
{ "newMesh", w_newMesh },
{ "newText", w_newText },
{ "_newVideo", w_newVideo },
{ "setColor", w_setColor },
{ "getColor", w_getColor },
@@ -1965,6 +1993,7 @@ static const lua_CFunction types[] =
luaopen_shader,
luaopen_mesh,
luaopen_text,
luaopen_video,
0
};
@@ -32,6 +32,7 @@
#include "wrap_Shader.h"
#include "wrap_Mesh.h"
#include "wrap_Text.h"
#include "wrap_Video.h"
#include "Graphics.h"
namespace love
+48 -1
View File
@@ -165,6 +165,28 @@ varying mediump vec4 VaryingColor;
uniform sampler2D _tex0_;]],
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);
}]],
FOOTER = [[
void main() {
// fix crashing issue in OSX when _tex0_ is unused within effect()
@@ -209,6 +231,7 @@ local function createPixelCode(pixelcode, is_multicanvas, lang)
love.graphics.isGammaCorrect() and "#define LOVE_GAMMA_CORRECT 1" or "",
GLSL.PIXEL.HEADER, GLSL.UNIFORMS,
GLSL.FUNCTIONS,
GLSL.PIXEL.FUNCTIONS,
lang == "glsles" and "#line 1" or "#line 0",
pixelcode,
is_multicanvas and GLSL.PIXEL.FOOTER_MULTI_CANVAS or GLSL.PIXEL.FOOTER,
@@ -309,21 +332,45 @@ vec4 position(mat4 transform_proj, vec4 vertpos) {
pixel = [[
vec4 effect(mediump vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord) {
return Texel(tex, texcoord) * vcolor;
}]]
}]],
videopixel = [[
vec4 effect(mediump vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord) {
return VideoTexel(texcoord) * vcolor;
}]],
}
local defaults = {
opengl = {
createVertexCode(defaultcode.vertex, "glsl"),
createPixelCode(defaultcode.pixel, false, "glsl"),
createPixelCode(defaultcode.videopixel, false, "glsl"),
},
opengles = {
createVertexCode(defaultcode.vertex, "glsles"),
createPixelCode(defaultcode.pixel, false, "glsles"),
createPixelCode(defaultcode.videopixel, false, "glsles"),
},
}
love.graphics._setDefaultShaderCode(defaults)
function love.graphics.newVideo(file, loadaudio)
local video = love.graphics._newVideo(file)
local source, success
if loadaudio ~= false then
success, source = pcall(love.audio.newSource, video:getStream():getFilename())
end
if success then
video:setSource(source)
elseif loadaudio == true then
error("Video had no audio track", 2)
else
video:getStream():setSync(love.video.newRemote())
end
return video
end
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
--)luastring"--"
+157
View File
@@ -0,0 +1,157 @@
/**
* Copyright (c) 2006-2015 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.
**/
#include "wrap_Video.h"
// Shove the wrap_Video.lua code directly into a raw string literal.
static const char video_lua[] =
#include "wrap_Video.lua"
;
namespace love
{
namespace graphics
{
namespace opengl
{
Video *luax_checkvideo(lua_State *L, int idx)
{
return luax_checktype<Video>(L, idx, GRAPHICS_VIDEO_ID);
}
int w_Video_getStream(lua_State *L)
{
Video *video = luax_checkvideo(L, 1);
luax_pushtype(L, VIDEO_VIDEO_STREAM_ID, video->getStream());
return 1;
}
int w_Video_getSource(lua_State *L)
{
Video *video = luax_checkvideo(L, 1);
auto source = video->getSource();
if (source)
luax_pushtype(L, AUDIO_SOURCE_ID, video->getSource());
else
lua_pushnil(L);
return 1;
}
int w_Video_setSource(lua_State *L)
{
Video *video = luax_checkvideo(L, 1);
if (lua_isnoneornil(L, 2))
video->setSource(nullptr);
else
{
auto source = luax_checktype<love::audio::Source>(L, 2, AUDIO_SOURCE_ID);
video->setSource(source);
}
return 0;
}
int w_Video_getWidth(lua_State *L)
{
Video *video = luax_checkvideo(L, 1);
lua_pushnumber(L, video->getWidth());
return 1;
}
int w_Video_getHeight(lua_State *L)
{
Video *video = luax_checkvideo(L, 1);
lua_pushnumber(L, video->getHeight());
return 1;
}
int w_Video_getDimensions(lua_State *L)
{
Video *video = luax_checkvideo(L, 1);
lua_pushnumber(L, video->getWidth());
lua_pushnumber(L, video->getHeight());
return 2;
}
int w_Video_setFilter(lua_State *L)
{
Video *video = luax_checkvideo(L, 1);
Texture::Filter f = video->getFilter();
const char *minstr = luaL_checkstring(L, 2);
const char *magstr = luaL_optstring(L, 3, minstr);
if (!Texture::getConstant(minstr, f.min))
return luaL_error(L, "Invalid filter mode: %s", minstr);
if (!Texture::getConstant(magstr, f.mag))
return luaL_error(L, "Invalid filter mode: %s", magstr);
f.anisotropy = (float) luaL_optnumber(L, 4, 1.0);
luax_catchexcept(L, [&](){ video->setFilter(f); });
return 0;
}
int w_Video_getFilter(lua_State *L)
{
Video *video = luax_checkvideo(L, 1);
const Texture::Filter f = video->getFilter();
const char *minstr = nullptr;
const char *magstr = nullptr;
if (!Texture::getConstant(f.min, minstr))
return luaL_error(L, "Unknown filter mode.");
if (!Texture::getConstant(f.mag, magstr))
return luaL_error(L, "Unknown filter mode.");
lua_pushstring(L, minstr);
lua_pushstring(L, magstr);
lua_pushnumber(L, f.anisotropy);
return 3;
}
static const luaL_Reg functions[] =
{
{ "getStream", w_Video_getStream },
{ "getSource", w_Video_getSource },
{ "_setSource", w_Video_setSource },
{ "getWidth", w_Video_getWidth },
{ "getHeight", w_Video_getHeight },
{ "getDimensions", w_Video_getDimensions },
{ "setFilter", w_Video_setFilter },
{ "getFilter", w_Video_getFilter },
{ 0, 0 }
};
int luaopen_video(lua_State *L)
{
int ret = luax_register_type(L, GRAPHICS_VIDEO_ID, "Video", functions, nullptr);
luaL_loadbuffer(L, video_lua, sizeof(video_lua), "Video.lua");
luax_gettypemetatable(L, GRAPHICS_VIDEO_ID);
lua_call(L, 1, 0);
return ret;
}
} // opengl
} // graphics
} // love
+38
View File
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2006-2015 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.
**/
#pragma once
// LOVE
#include "Video.h"
#include "common/runtime.h"
namespace love
{
namespace graphics
{
namespace opengl
{
int luaopen_video(lua_State *L);
} // opengl
} // graphics
} // love
@@ -0,0 +1,69 @@
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-2015 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 Video_mt = ...
local Video = Video_mt.__index
function Video:loadRemote()
local stream = self:getStream()
local remote = love.video.newRemote()
stream:setSync(remote)
return remote
end
function Video:setSource(source)
self:_setSource(source)
if source then
self:getStream():setSync(source)
else
self:getStream():setSync(love.video.newRemote())
end
end
function Video:play()
return self:getStream():play()
end
function Video:pause()
return self:getStream():pause()
end
function Video:seek(offset)
return self:getStream():seek(offset)
end
function Video:rewind()
return self:getStream():rewind()
end
function Video:tell()
return self:getStream():tell()
end
function Video:isPlaying()
return self:getStream():isPlaying()
end
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
--)luastring"--"