mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-06 16:00:00 +01:00
Implementation of new type of source: Pattern generator (GUI, icons,
saving). A new class for gstreamer stream (Stream) is defined for generic pipeline sources; to be integrated (inheritance) into MediaPlayer.
This commit is contained in:
@@ -235,8 +235,10 @@ set(VMIX_SRCS
|
||||
Resource.cpp
|
||||
FileDialog.cpp
|
||||
Timeline.cpp
|
||||
Stream.cpp
|
||||
MediaPlayer.cpp
|
||||
MediaSource.cpp
|
||||
PatternSource.cpp
|
||||
FrameBuffer.cpp
|
||||
RenderingManager.cpp
|
||||
UserInterfaceManager.cpp
|
||||
@@ -306,6 +308,7 @@ set(VMIX_RSC_FILES
|
||||
./rsc/mesh/icon_video.ply
|
||||
./rsc/mesh/icon_image.ply
|
||||
./rsc/mesh/icon_render.ply
|
||||
./rsc/mesh/icon_gear.ply
|
||||
./rsc/mesh/icon_clone.ply
|
||||
./rsc/mesh/icon_vimix.ply
|
||||
./rsc/mesh/icon_circles.ply
|
||||
@@ -433,6 +436,8 @@ IF(APPLE)
|
||||
# create GST plugins directory in Bundle Resources subfolder
|
||||
set(plugin_dest_dir vimix.app/Contents/Resources/)
|
||||
|
||||
### TODO configure auto to find installation dir of gst
|
||||
|
||||
# intall the gst-plugin-scanner program (used by plugins at load time)
|
||||
install(FILES "/usr/local/Cellar/gstreamer/1.18.0/libexec/gstreamer-1.0/gst-plugin-scanner"
|
||||
DESTINATION "${plugin_dest_dir}"
|
||||
@@ -457,7 +462,6 @@ IF(APPLE)
|
||||
install(FILES "/Users/herbelin/Development/gst/gst-plugins-bad-1.16.2/build/sys/applemedia/libgstapplemedia.dylib" DESTINATION "${plugin_dest_dir}/gstreamer-1.0" COMPONENT Runtime)
|
||||
install(FILES "/Users/herbelin/Development/gst/gst-plugins-bad-1.16.2/build/sys/decklink/libgstdecklink.dylib" DESTINATION "${plugin_dest_dir}/gstreamer-1.0" COMPONENT Runtime)
|
||||
install(FILES "/Users/herbelin/Development/gst/gst-plugins-bad-1.16.2/build/ext/aom/libgstaom.dylib" DESTINATION "${plugin_dest_dir}/gstreamer-1.0" COMPONENT Runtime)
|
||||
|
||||
install(FILES "/Users/herbelin/Development/gst/gst-plugins-bad-1.16.2/build/gst/videoparsers/libgstvideoparsersbad.dylib" DESTINATION "${plugin_dest_dir}/gstreamer-1.0" COMPONENT Runtime)
|
||||
install(FILES "/Users/herbelin/Development/gst/gst-plugins-bad-1.16.2/build/gst-libs/gst/codecparsers/libgstcodecparsers-1.0.0.dylib" DESTINATION "${plugin_dest_dir}/gstreamer-1.0" COMPONENT Runtime)
|
||||
|
||||
|
||||
@@ -310,7 +310,7 @@ Symbol::Symbol(Type t, glm::vec3 pos) : Node(), type_(t)
|
||||
icons[SESSION] = new Mesh("mesh/icon_vimix.ply");
|
||||
icons[CLONE] = new Mesh("mesh/icon_clone.ply");
|
||||
icons[RENDER] = new Mesh("mesh/icon_render.ply");
|
||||
icons[EMPTY] = new Mesh("mesh/icon_empty.ply");
|
||||
icons[PATTERN] = new Mesh("mesh/icon_gear.ply");
|
||||
icons[DOTS] = new Mesh("mesh/icon_dots.ply");
|
||||
icons[BUSY] = new Mesh("mesh/icon_circles.ply");
|
||||
icons[LOCK] = new Mesh("mesh/icon_lock.ply");
|
||||
@@ -321,6 +321,7 @@ Symbol::Symbol(Type t, glm::vec3 pos) : Node(), type_(t)
|
||||
icons[SQUARE] = new Mesh("mesh/icon_square.ply");
|
||||
icons[CROSS] = new Mesh("mesh/icon_cross.ply");
|
||||
icons[GRID] = new Mesh("mesh/icon_grid.ply");
|
||||
icons[EMPTY] = new Mesh("mesh/icon_empty.ply");
|
||||
}
|
||||
|
||||
symbol_ = icons[type_];
|
||||
|
||||
@@ -60,7 +60,8 @@ protected:
|
||||
class Symbol : public Node
|
||||
{
|
||||
public:
|
||||
typedef enum { CIRCLE_POINT = 0, SQUARE_POINT, IMAGE, VIDEO, SESSION, CLONE, RENDER, DOTS, BUSY, LOCK, UNLOCK, CIRCLE, SQUARE, CLOCK, CLOCK_H, GRID, CROSS, EMPTY } Type;
|
||||
typedef enum { CIRCLE_POINT = 0, SQUARE_POINT, IMAGE, VIDEO, SESSION, CLONE, RENDER, PATTERN,
|
||||
DOTS, BUSY, LOCK, UNLOCK, CIRCLE, SQUARE, CLOCK, CLOCK_H, GRID, CROSS, EMPTY } Type;
|
||||
Symbol(Type t = CIRCLE_POINT, glm::vec3 pos = glm::vec3(0.f));
|
||||
~Symbol();
|
||||
|
||||
|
||||
@@ -179,3 +179,17 @@ GlmToolkit::AxisAlignedBoundingBox GlmToolkit::AxisAlignedBoundingBox::transform
|
||||
return bb;
|
||||
}
|
||||
|
||||
|
||||
glm::ivec2 GlmToolkit::resolutionFromDescription(int aspectratio, int height)
|
||||
{
|
||||
int ar = glm::clamp(aspectratio, 0, 5);
|
||||
int h = glm::clamp(height, 0, 8);
|
||||
|
||||
static glm::vec2 aspect_ratio_size[6] = { glm::vec2(1.f,1.f), glm::vec2(4.f,3.f), glm::vec2(3.f,2.f), glm::vec2(16.f,10.f), glm::vec2(16.f,9.f), glm::vec2(21.f,9.f) };
|
||||
static float resolution_height[9] = { 16.f, 64.f, 200.f, 320.f, 480.f, 720.f, 1080.f, 1440.f, 2160.f };
|
||||
|
||||
float width = aspect_ratio_size[ar].x * resolution_height[h] / aspect_ratio_size[ar].y;
|
||||
glm::ivec2 res = glm::ivec2( width, resolution_height[h]);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ public:
|
||||
AxisAlignedBoundingBox transformed(glm::mat4 m) const;
|
||||
};
|
||||
|
||||
|
||||
static const char* aspect_ratio_names[6] = { "1:1", "4:3", "3:2", "16:10", "16:9", "21:9" };
|
||||
static const char* height_names[9] = { "16", "64", "200", "320", "480", "720p", "1080p", "1440", "4K" };
|
||||
|
||||
glm::ivec2 resolutionFromDescription(int aspectratio, int height);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "MediaPlayer.h"
|
||||
#include "MediaSource.h"
|
||||
#include "SessionSource.h"
|
||||
#include "PatternSource.h"
|
||||
#include "Settings.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
@@ -353,3 +354,17 @@ void ImGuiVisitor::visit (CloneSource& s)
|
||||
Mixer::manager().setCurrentSource(s.origin());
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit (PatternSource& s)
|
||||
{
|
||||
ImGuiToolkit::Icon(13,5);
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::Text("Pattern %s", Pattern::pattern_names[s.pattern()]);
|
||||
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
int p = s.pattern();
|
||||
if ( ImGui::Combo("Pattern", &p, Pattern::pattern_names, IM_ARRAYSIZE(Pattern::pattern_names) ) )
|
||||
{
|
||||
s.setPattern(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ public:
|
||||
void visit (SessionSource& s) override;
|
||||
void visit (RenderSource& s) override;
|
||||
void visit (CloneSource& s) override;
|
||||
void visit (PatternSource& s) override;
|
||||
};
|
||||
|
||||
#endif // IMGUIVISITOR_H
|
||||
|
||||
@@ -31,7 +31,6 @@ MediaPlayer::MediaPlayer()
|
||||
|
||||
uri_ = "undefined";
|
||||
pipeline_ = nullptr;
|
||||
converter_ = nullptr;
|
||||
|
||||
ready_ = false;
|
||||
failed_ = false;
|
||||
@@ -347,10 +346,6 @@ void MediaPlayer::close()
|
||||
// un-ready the media player
|
||||
ready_ = false;
|
||||
|
||||
// no more need to reference converter
|
||||
if (converter_ != nullptr)
|
||||
gst_object_unref (converter_);
|
||||
|
||||
// clean up GST
|
||||
if (pipeline_ != nullptr) {
|
||||
GstStateChangeReturn ret = gst_element_set_state (pipeline_, GST_STATE_NULL);
|
||||
|
||||
@@ -262,7 +262,6 @@ private:
|
||||
LoopMode loop_;
|
||||
GstState desired_state_;
|
||||
GstElement *pipeline_;
|
||||
GstElement *converter_;
|
||||
GstVideoInfo v_frame_video_info_;
|
||||
std::atomic<bool> ready_;
|
||||
std::atomic<bool> failed_;
|
||||
|
||||
@@ -79,8 +79,8 @@ void MediaSource::init()
|
||||
mediasurface_->setTextureIndex( mediaplayer_->texture() );
|
||||
|
||||
// create Frame buffer matching size of media player
|
||||
float height = float(mediaplayer()->width()) / mediaplayer()->aspectRatio();
|
||||
FrameBuffer *renderbuffer = new FrameBuffer(mediaplayer()->width(), (uint)height, true);
|
||||
float height = float(mediaplayer_->width()) / mediaplayer_->aspectRatio();
|
||||
FrameBuffer *renderbuffer = new FrameBuffer(mediaplayer_->width(), (uint)height, true);
|
||||
|
||||
// set the renderbuffer of the source and attach rendering nodes
|
||||
attach(renderbuffer);
|
||||
@@ -115,7 +115,7 @@ void MediaSource::setActive (bool on)
|
||||
|
||||
// change status of media player (only if status changed)
|
||||
if ( active_ != was_active ) {
|
||||
mediaplayer()->enable(active_);
|
||||
mediaplayer_->enable(active_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "Source.h"
|
||||
|
||||
class MediaPlayer;
|
||||
|
||||
class MediaSource : public Source
|
||||
{
|
||||
public:
|
||||
|
||||
17
Mixer.cpp
17
Mixer.cpp
@@ -22,6 +22,7 @@ using namespace tinyxml2;
|
||||
#include "SessionVisitor.h"
|
||||
#include "SessionSource.h"
|
||||
#include "MediaSource.h"
|
||||
#include "PatternSource.h"
|
||||
|
||||
#include "Mixer.h"
|
||||
|
||||
@@ -207,7 +208,7 @@ void Mixer::draw()
|
||||
}
|
||||
|
||||
// manangement of sources
|
||||
Source * Mixer::createSourceFile(std::string path)
|
||||
Source * Mixer::createSourceFile(const std::string &path)
|
||||
{
|
||||
// ready to create a source
|
||||
Source *s = nullptr;
|
||||
@@ -256,7 +257,19 @@ Source * Mixer::createSourceRender()
|
||||
return s;
|
||||
}
|
||||
|
||||
Source * Mixer::createSourceClone(std::string namesource)
|
||||
Source * Mixer::createSourcePattern(int pattern, glm::ivec2 res)
|
||||
{
|
||||
// ready to create a source
|
||||
PatternSource *s = new PatternSource(res);
|
||||
s->setPattern(pattern);
|
||||
|
||||
// propose a new name based on pattern name
|
||||
renameSource(s, Pattern::pattern_names[pattern]);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
Source * Mixer::createSourceClone(const std::string &namesource)
|
||||
{
|
||||
// ready to create a source
|
||||
Source *s = nullptr;
|
||||
|
||||
5
Mixer.h
5
Mixer.h
@@ -36,9 +36,10 @@ public:
|
||||
void draw();
|
||||
|
||||
// creation of sources
|
||||
Source * createSourceFile (std::string path);
|
||||
Source * createSourceClone (std::string namesource = "");
|
||||
Source * createSourceFile (const std::string &path);
|
||||
Source * createSourceClone (const std::string &namesource = "");
|
||||
Source * createSourceRender ();
|
||||
Source * createSourcePattern(int pattern, glm::ivec2 res);
|
||||
|
||||
// operations on sources
|
||||
void addSource (Source *s);
|
||||
|
||||
264
PatternSource.cpp
Normal file
264
PatternSource.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
#include <sstream>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "PatternSource.h"
|
||||
|
||||
#include "defines.h"
|
||||
#include "ImageShader.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
#include "Resource.h"
|
||||
#include "Primitives.h"
|
||||
#include "Stream.h"
|
||||
#include "Visitor.h"
|
||||
#include "Log.h"
|
||||
|
||||
// smpte (0) – SMPTE 100%% color bars
|
||||
// snow (1) – Random (television snow)
|
||||
// black (2) – 100%% Black
|
||||
// white (3) – 100%% White
|
||||
// red (4) – Red
|
||||
// green (5) – Green
|
||||
// blue (6) – Blue
|
||||
// checkers-1 (7) – Checkers 1px
|
||||
// checkers-2 (8) – Checkers 2px
|
||||
// checkers-4 (9) – Checkers 4px
|
||||
// checkers-8 (10) – Checkers 8px
|
||||
// circular (11) – Circular
|
||||
// blink (12) – Blink
|
||||
// smpte75 (13) – SMPTE 75%% color bars
|
||||
// zone-plate (14) – Zone plate
|
||||
// gamut (15) – Gamut checkers
|
||||
// chroma-zone-plate (16) – Chroma zone plate
|
||||
// solid-color (17) – Solid color
|
||||
// ball (18) – Moving ball
|
||||
// smpte100 (19) – SMPTE 100%% color bars
|
||||
// bar (20) – Bar
|
||||
// pinwheel (21) – Pinwheel
|
||||
// spokes (22) – Spokes
|
||||
// gradient (23) – Gradient
|
||||
// colors (24) – Colors
|
||||
const char* pattern_internal_[25] = { "videotestsrc pattern=black",
|
||||
"videotestsrc pattern=white",
|
||||
"frei0r-src-test-pat-l",
|
||||
"videotestsrc pattern=gradient",
|
||||
"videotestsrc pattern=checkers-1 ! video/x-raw,format=GRAY8 ! videoconvert",
|
||||
"frei0r-src-test-pat-g",
|
||||
"videotestsrc pattern=circular",
|
||||
"videotestsrc pattern=pinwheel",
|
||||
"videotestsrc pattern=spokes",
|
||||
"videotestsrc pattern=red",
|
||||
"videotestsrc pattern=green",
|
||||
"videotestsrc pattern=blue",
|
||||
"videotestsrc pattern=smpte100",
|
||||
"frei0r-src-test-pat-c",
|
||||
"videotestsrc pattern=colors",
|
||||
"videotestsrc pattern=smpte",
|
||||
"videotestsrc pattern=snow",
|
||||
"videotestsrc pattern=blink",
|
||||
"videotestsrc pattern=zone-plate",
|
||||
"videotestsrc pattern=chroma-zone-plate",
|
||||
"videotestsrc pattern=bar horizontal-speed=5",
|
||||
"videotestsrc pattern=ball",
|
||||
"frei0r-src-ising0r",
|
||||
"videotestsrc pattern=black ! timeoverlay halignment=center valignment=center font-desc=\"Sans, 72\" ",
|
||||
"videotestsrc pattern=black ! clockoverlay halignment=center valignment=center font-desc=\"Sans, 72\" "
|
||||
};
|
||||
|
||||
|
||||
const char* Pattern::pattern_names[25] = { "100% Black",
|
||||
"100% White",
|
||||
"Gray bars",
|
||||
"Gradient",
|
||||
"Checkers 1x1 px",
|
||||
"Checkerboard",
|
||||
"Circles",
|
||||
"Pinwheel",
|
||||
"Spokes",
|
||||
"100% Red",
|
||||
"100% Green",
|
||||
"100% Blue",
|
||||
"Color bars",
|
||||
"Color Gradient",
|
||||
"Color grid",
|
||||
"SMPTE test pattern",
|
||||
"Television snow",
|
||||
"Blink",
|
||||
"Fresnel zone plate",
|
||||
"Chroma zone plate",
|
||||
"Moving bar",
|
||||
"Moving ball",
|
||||
"Blob",
|
||||
"Timer",
|
||||
"Clock"
|
||||
};
|
||||
|
||||
Pattern::Pattern(glm::ivec2 res) : Stream()
|
||||
{
|
||||
|
||||
width_ = res.x;
|
||||
height_ = res.y;
|
||||
}
|
||||
|
||||
|
||||
void Pattern::open( uint pattern )
|
||||
{
|
||||
std::string gstreamer_pattern = pattern_internal_[pattern];
|
||||
|
||||
// always some special cases...
|
||||
switch(pattern)
|
||||
{
|
||||
case 16:
|
||||
case 17:
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << " kx2=" << (int)(aspectRatio() * 10.f) << " ky2=10 kt=4";
|
||||
gstreamer_pattern += oss.str(); // Zone plate
|
||||
single_frame_ = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// all patterns before index are single frames (not animated)
|
||||
single_frame_ = pattern < 13;
|
||||
|
||||
// (private) open stream
|
||||
open(gstreamer_pattern);
|
||||
}
|
||||
|
||||
void Pattern::open(std::string gstreamer_pattern)
|
||||
{
|
||||
// set gstreamer pipeline source
|
||||
description_ = gstreamer_pattern;
|
||||
|
||||
// close before re-openning
|
||||
if (isOpen())
|
||||
close();
|
||||
|
||||
execute_open();
|
||||
}
|
||||
|
||||
|
||||
PatternSource::PatternSource(glm::ivec2 resolution) : Source()
|
||||
{
|
||||
// create stream
|
||||
stream_ = new Pattern(resolution);
|
||||
|
||||
// create surface
|
||||
patternsurface_ = new Surface(renderingshader_);
|
||||
}
|
||||
|
||||
glm::ivec2 PatternSource::resolution()
|
||||
{
|
||||
return glm::ivec2( stream_->width(), stream_->height());
|
||||
}
|
||||
|
||||
PatternSource::~PatternSource()
|
||||
{
|
||||
// delete media surface & stream
|
||||
delete patternsurface_;
|
||||
delete stream_;
|
||||
}
|
||||
|
||||
bool PatternSource::failed() const
|
||||
{
|
||||
return stream_->failed();
|
||||
}
|
||||
|
||||
uint PatternSource::texture() const
|
||||
{
|
||||
return stream_->texture();
|
||||
}
|
||||
|
||||
void PatternSource::replaceRenderingShader()
|
||||
{
|
||||
patternsurface_->replaceShader(renderingshader_);
|
||||
}
|
||||
|
||||
void PatternSource::setPattern(int id)
|
||||
{
|
||||
pattern_ = CLAMP(id, 0, 25);
|
||||
|
||||
stream_->open(pattern_);
|
||||
stream_->play(true);
|
||||
|
||||
Log::Notify("Creating pattern %s", Pattern::pattern_names[pattern_]);
|
||||
}
|
||||
|
||||
|
||||
void PatternSource::init()
|
||||
{
|
||||
if ( stream_->isOpen() ) {
|
||||
|
||||
// update video
|
||||
stream_->update();
|
||||
|
||||
// once the texture of media player is created
|
||||
if (stream_->texture() != Resource::getTextureBlack()) {
|
||||
|
||||
// get the texture index from media player, apply it to the media surface
|
||||
patternsurface_->setTextureIndex( stream_->texture() );
|
||||
|
||||
// create Frame buffer matching size of media player
|
||||
float height = float(stream_->width()) / stream_->aspectRatio();
|
||||
FrameBuffer *renderbuffer = new FrameBuffer(stream_->width(), (uint)height, true);
|
||||
|
||||
// set the renderbuffer of the source and attach rendering nodes
|
||||
attach(renderbuffer);
|
||||
|
||||
// icon in mixing view
|
||||
overlays_[View::MIXING]->attach( new Symbol(Symbol::PATTERN, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
overlays_[View::LAYER]->attach( new Symbol(Symbol::PATTERN, glm::vec3(0.8f, 0.8f, 0.01f)) );
|
||||
|
||||
// done init
|
||||
initialized_ = true;
|
||||
Log::Info("Source Pattern linked to Stream %d.", stream_->description().c_str());
|
||||
|
||||
// force update of activation mode
|
||||
active_ = true;
|
||||
touch();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PatternSource::setActive (bool on)
|
||||
{
|
||||
bool was_active = active_;
|
||||
|
||||
Source::setActive(on);
|
||||
|
||||
// change status of media player (only if status changed)
|
||||
if ( active_ != was_active ) {
|
||||
stream_->enable(active_);
|
||||
}
|
||||
}
|
||||
|
||||
void PatternSource::update(float dt)
|
||||
{
|
||||
Source::update(dt);
|
||||
|
||||
// update stream
|
||||
// TODO : update only if animated pattern
|
||||
stream_->update();
|
||||
}
|
||||
|
||||
void PatternSource::render()
|
||||
{
|
||||
if (!initialized_)
|
||||
init();
|
||||
else {
|
||||
// render the media player into frame buffer
|
||||
static glm::mat4 projection = glm::ortho(-1.f, 1.f, 1.f, -1.f, -1.f, 1.f);
|
||||
renderbuffer_->begin();
|
||||
patternsurface_->draw(glm::identity<glm::mat4>(), projection);
|
||||
renderbuffer_->end();
|
||||
}
|
||||
}
|
||||
|
||||
void PatternSource::accept(Visitor& v)
|
||||
{
|
||||
Source::accept(v);
|
||||
v.visit(*this);
|
||||
}
|
||||
52
PatternSource.h
Normal file
52
PatternSource.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef PATTERNSOURCE_H
|
||||
#define PATTERNSOURCE_H
|
||||
|
||||
|
||||
#include "Source.h"
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
class Pattern : public Stream
|
||||
{
|
||||
public:
|
||||
static const char* pattern_names[25];
|
||||
|
||||
Pattern(glm::ivec2 res);
|
||||
void open( uint pattern );
|
||||
|
||||
private:
|
||||
void open( std::string description ) override;
|
||||
};
|
||||
|
||||
class PatternSource : public Source
|
||||
{
|
||||
public:
|
||||
PatternSource(glm::ivec2 resolution);
|
||||
~PatternSource();
|
||||
|
||||
// implementation of source API
|
||||
void update (float dt) override;
|
||||
void setActive (bool on) override;
|
||||
void render() override;
|
||||
bool failed() const override;
|
||||
uint texture() const override;
|
||||
void accept (Visitor& v) override;
|
||||
|
||||
// Pattern specific interface
|
||||
inline uint pattern() const { return pattern_; }
|
||||
void setPattern(int id);
|
||||
|
||||
glm::ivec2 resolution();
|
||||
|
||||
protected:
|
||||
|
||||
void init() override;
|
||||
void replaceRenderingShader() override;
|
||||
|
||||
Surface *patternsurface_;
|
||||
Pattern *stream_;
|
||||
|
||||
uint pattern_;
|
||||
};
|
||||
|
||||
#endif // PATTERNSOURCE_H
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Source.h"
|
||||
#include "MediaSource.h"
|
||||
#include "SessionSource.h"
|
||||
#include "PatternSource.h"
|
||||
#include "Session.h"
|
||||
#include "ImageShader.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
@@ -110,6 +111,17 @@ void SessionCreator::loadSession(XMLElement *sessionNode)
|
||||
new_render_source->accept(*this);
|
||||
session_->addSource(new_render_source);
|
||||
}
|
||||
else if ( std::string(pType) == "PatternSource") {
|
||||
|
||||
glm::ivec2 resolution(800, 600);
|
||||
XMLElement* res = xmlCurrent_->FirstChildElement("resolution");
|
||||
if (res)
|
||||
tinyxml2::XMLElementToGLM( res->FirstChildElement("ivec2"), resolution);
|
||||
|
||||
PatternSource *new_pattern_source = new PatternSource(resolution);
|
||||
new_pattern_source->accept(*this);
|
||||
session_->addSource(new_pattern_source);
|
||||
}
|
||||
// TODO : create other types of source
|
||||
|
||||
}
|
||||
@@ -328,5 +340,11 @@ void SessionCreator::visit (SessionSource& s)
|
||||
|
||||
}
|
||||
|
||||
void SessionCreator::visit (PatternSource& s)
|
||||
{
|
||||
uint p = xmlCurrent_->UnsignedAttribute("pattern");
|
||||
s.setPattern(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
void visit (Source& s) override;
|
||||
void visit (MediaSource& s) override;
|
||||
void visit (SessionSource& s) override;
|
||||
void visit (PatternSource& s) override;
|
||||
|
||||
static std::string info(const std::string& filename);
|
||||
static void XMLToNode(tinyxml2::XMLElement *xml, Node &n);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Source.h"
|
||||
#include "MediaSource.h"
|
||||
#include "SessionSource.h"
|
||||
#include "PatternSource.h"
|
||||
#include "ImageShader.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
#include "MediaPlayer.h"
|
||||
@@ -379,3 +380,13 @@ void SessionVisitor::visit (CloneSource& s)
|
||||
XMLText *text = xmlDoc_->NewText( s.origin()->name().c_str() );
|
||||
origin->InsertEndChild( text );
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (PatternSource& s)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("type", "PatternSource");
|
||||
xmlCurrent_->SetAttribute("pattern", s.pattern() );
|
||||
|
||||
XMLElement *resolution = xmlDoc_->NewElement("resolution");
|
||||
resolution->InsertEndChild( XMLElementFromGLM(xmlDoc_, s.resolution() ) );
|
||||
xmlCurrent_->InsertEndChild(resolution);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
void visit (SessionSource& s) override;
|
||||
void visit (RenderSource& s) override;
|
||||
void visit (CloneSource& s) override;
|
||||
void visit (PatternSource& s) override;
|
||||
|
||||
static tinyxml2::XMLElement *NodeToXML(Node &n, tinyxml2::XMLDocument *doc);
|
||||
};
|
||||
|
||||
17
Settings.cpp
17
Settings.cpp
@@ -96,6 +96,14 @@ void Settings::Save()
|
||||
TransitionNode->SetAttribute("profile", application.transition.profile);
|
||||
pRoot->InsertEndChild(TransitionNode);
|
||||
|
||||
// Source
|
||||
XMLElement *SourceConfNode = xmlDoc.NewElement( "Source" );
|
||||
SourceConfNode->SetAttribute("new_type", application.source.new_type);
|
||||
SourceConfNode->SetAttribute("pattern_type", application.source.pattern_type);
|
||||
SourceConfNode->SetAttribute("ratio", application.source.ratio);
|
||||
SourceConfNode->SetAttribute("res", application.source.res);
|
||||
pRoot->InsertEndChild(SourceConfNode);
|
||||
|
||||
// bloc views
|
||||
{
|
||||
XMLElement *viewsNode = xmlDoc.NewElement( "Views" );
|
||||
@@ -241,6 +249,15 @@ void Settings::Load()
|
||||
application.record.path = SystemToolkit::home_path();
|
||||
}
|
||||
|
||||
// Source
|
||||
XMLElement * sourceconfnode = pRoot->FirstChildElement("Source");
|
||||
if (sourceconfnode != nullptr) {
|
||||
sourceconfnode->QueryIntAttribute("new_type", &application.source.new_type);
|
||||
sourceconfnode->QueryIntAttribute("pattern_type", &application.source.pattern_type);
|
||||
sourceconfnode->QueryIntAttribute("ratio", &application.source.ratio);
|
||||
sourceconfnode->QueryIntAttribute("res", &application.source.res);
|
||||
}
|
||||
|
||||
// Transition
|
||||
XMLElement * transitionnode = pRoot->FirstChildElement("Transition");
|
||||
if (transitionnode != nullptr) {
|
||||
|
||||
19
Settings.h
19
Settings.h
@@ -136,6 +136,22 @@ struct RenderConfig
|
||||
}
|
||||
};
|
||||
|
||||
struct SourceConfig
|
||||
{
|
||||
int new_type;
|
||||
int pattern_type;
|
||||
int ratio;
|
||||
int res;
|
||||
|
||||
SourceConfig() {
|
||||
new_type = 0;
|
||||
pattern_type = 0;
|
||||
ratio = 3;
|
||||
res = 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Application
|
||||
{
|
||||
// Verification
|
||||
@@ -162,6 +178,9 @@ struct Application
|
||||
// settings render
|
||||
RecordConfig record;
|
||||
|
||||
// settings new source
|
||||
SourceConfig source;
|
||||
|
||||
// settings transition
|
||||
TransitionConfig transition;
|
||||
|
||||
|
||||
1
Source.h
1
Source.h
@@ -13,7 +13,6 @@ class ImageShader;
|
||||
class ImageProcessingShader;
|
||||
class FrameBuffer;
|
||||
class FrameBufferSurface;
|
||||
class MediaPlayer;
|
||||
class Surface;
|
||||
class Session;
|
||||
class Frame;
|
||||
|
||||
692
Stream.cpp
692
Stream.cpp
@@ -1,6 +1,698 @@
|
||||
#include <thread>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Desktop OpenGL function loader
|
||||
#include <glad/glad.h>
|
||||
|
||||
|
||||
// vmix
|
||||
#include "defines.h"
|
||||
#include "Log.h"
|
||||
#include "Resource.h"
|
||||
#include "Visitor.h"
|
||||
#include "SystemToolkit.h"
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define STREAM_DEBUG
|
||||
#endif
|
||||
|
||||
#define USE_GST_APPSINK_CALLBACKS_
|
||||
|
||||
|
||||
Stream::Stream()
|
||||
{
|
||||
// create unique id
|
||||
auto duration = std::chrono::high_resolution_clock::now().time_since_epoch();
|
||||
id_ = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count() % 1000000000;
|
||||
|
||||
description_ = "undefined";
|
||||
pipeline_ = nullptr;
|
||||
|
||||
width_ = 800;
|
||||
height_ = 600;
|
||||
single_frame_ = true;
|
||||
ready_ = false;
|
||||
failed_ = false;
|
||||
enabled_ = true;
|
||||
desired_state_ = GST_STATE_PAUSED;
|
||||
|
||||
// start index in frame_ stack
|
||||
write_index_ = 0;
|
||||
last_index_ = 0;
|
||||
|
||||
// no PBO by default
|
||||
pbo_[0] = pbo_[1] = 0;
|
||||
pbo_size_ = 0;
|
||||
pbo_index_ = 0;
|
||||
pbo_next_index_ = 0;
|
||||
|
||||
// OpenGL texture
|
||||
textureindex_ = 0;
|
||||
}
|
||||
|
||||
Stream::~Stream()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void Stream::accept(Visitor& v) {
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
guint Stream::texture() const
|
||||
{
|
||||
if (textureindex_ == 0)
|
||||
return Resource::getTextureBlack();
|
||||
|
||||
return textureindex_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string Stream::description() const
|
||||
{
|
||||
return description_;
|
||||
}
|
||||
|
||||
void Stream::execute_open()
|
||||
{
|
||||
// reset
|
||||
ready_ = false;
|
||||
|
||||
// Create the gstreamer pipeline possible :
|
||||
string description = description_;
|
||||
description += " ! appsink name=sink";
|
||||
|
||||
// parse pipeline descriptor
|
||||
GError *error = NULL;
|
||||
pipeline_ = gst_parse_launch (description.c_str(), &error);
|
||||
if (error != NULL) {
|
||||
Log::Warning("Stream %s Could not construct pipeline %s:\n%s", std::to_string(id_).c_str(), description.c_str(), error->message);
|
||||
g_clear_error (&error);
|
||||
failed_ = true;
|
||||
return;
|
||||
}
|
||||
g_object_set(G_OBJECT(pipeline_), "name", std::to_string(id_).c_str(), NULL);
|
||||
|
||||
// GstCaps *caps = gst_static_caps_get (&frame_render_caps);
|
||||
string capstring = "video/x-raw,format=RGBA,width="+ std::to_string(width_) +
|
||||
",height=" + std::to_string(height_);
|
||||
GstCaps *caps = gst_caps_from_string(capstring.c_str());
|
||||
if (!gst_video_info_from_caps (&v_frame_video_info_, caps)) {
|
||||
Log::Warning("Stream %s Could not configure video frame info", std::to_string(id_).c_str());
|
||||
failed_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// setup appsink
|
||||
GstElement *sink = gst_bin_get_by_name (GST_BIN (pipeline_), "sink");
|
||||
if (sink) {
|
||||
// instruct the sink to send samples synched in time
|
||||
gst_base_sink_set_sync (GST_BASE_SINK(sink), true);
|
||||
|
||||
// instruct sink to use the required caps
|
||||
gst_app_sink_set_caps (GST_APP_SINK(sink), caps);
|
||||
|
||||
// Instruct appsink to drop old buffers when the maximum amount of queued buffers is reached.
|
||||
gst_app_sink_set_max_buffers( GST_APP_SINK(sink), 50);
|
||||
gst_app_sink_set_drop (GST_APP_SINK(sink), true);
|
||||
|
||||
#ifdef USE_GST_APPSINK_CALLBACKS_
|
||||
// set the callbacks
|
||||
GstAppSinkCallbacks callbacks;
|
||||
callbacks.new_preroll = callback_new_preroll;
|
||||
if (single_frame_) {
|
||||
callbacks.eos = NULL;
|
||||
callbacks.new_sample = NULL;
|
||||
}
|
||||
else {
|
||||
callbacks.eos = callback_end_of_stream;
|
||||
callbacks.new_sample = callback_new_sample;
|
||||
}
|
||||
gst_app_sink_set_callbacks (GST_APP_SINK(sink), &callbacks, this, NULL);
|
||||
gst_app_sink_set_emit_signals (GST_APP_SINK(sink), false);
|
||||
#else
|
||||
// connect signals callbacks
|
||||
g_signal_connect(G_OBJECT(sink), "new-sample", G_CALLBACK (callback_new_sample), this);
|
||||
g_signal_connect(G_OBJECT(sink), "new-preroll", G_CALLBACK (callback_new_preroll), this);
|
||||
g_signal_connect(G_OBJECT(sink), "eos", G_CALLBACK (callback_end_of_stream), this);
|
||||
gst_app_sink_set_emit_signals (GST_APP_SINK(sink), true);
|
||||
#endif
|
||||
// done with ref to sink
|
||||
gst_object_unref (sink);
|
||||
}
|
||||
else {
|
||||
Log::Warning("Stream %s Could not configure sink", std::to_string(id_).c_str());
|
||||
failed_ = true;
|
||||
return;
|
||||
}
|
||||
gst_caps_unref (caps);
|
||||
|
||||
// set to desired state (PLAY or PAUSE)
|
||||
GstStateChangeReturn ret = gst_element_set_state (pipeline_, desired_state_);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE) {
|
||||
Log::Warning("Stream %s Could not open '%s'", std::to_string(id_).c_str(), description_.c_str());
|
||||
failed_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// all good
|
||||
Log::Info("Stream %d Opened '%s' (%d x %d)", id_, description_.c_str(), width_, height_);
|
||||
|
||||
ready_ = true;
|
||||
}
|
||||
|
||||
bool Stream::isOpen() const
|
||||
{
|
||||
return ready_;
|
||||
}
|
||||
|
||||
bool Stream::failed() const
|
||||
{
|
||||
return failed_;
|
||||
}
|
||||
|
||||
void Stream::close()
|
||||
{
|
||||
// not openned?
|
||||
if (!ready_) {
|
||||
// nothing else to change
|
||||
return;
|
||||
}
|
||||
|
||||
// un-ready
|
||||
ready_ = false;
|
||||
|
||||
// clean up GST
|
||||
if (pipeline_ != nullptr) {
|
||||
GstStateChangeReturn ret = gst_element_set_state (pipeline_, GST_STATE_NULL);
|
||||
if (ret == GST_STATE_CHANGE_ASYNC) {
|
||||
GstState state;
|
||||
gst_element_get_state (pipeline_, &state, NULL, GST_CLOCK_TIME_NONE);
|
||||
}
|
||||
gst_object_unref (pipeline_);
|
||||
pipeline_ = nullptr;
|
||||
}
|
||||
desired_state_ = GST_STATE_PAUSED;
|
||||
|
||||
// cleanup eventual remaining frame memory
|
||||
for(guint i = 0; i < N_FRAME; i++){
|
||||
if ( frame_[i].full ) {
|
||||
gst_video_frame_unmap(&frame_[i].vframe);
|
||||
frame_[i].status = INVALID;
|
||||
}
|
||||
}
|
||||
write_index_ = 0;
|
||||
last_index_ = 0;
|
||||
|
||||
// cleanup opengl texture
|
||||
if (textureindex_)
|
||||
glDeleteTextures(1, &textureindex_);
|
||||
textureindex_ = 0;
|
||||
|
||||
// cleanup picture buffer
|
||||
if (pbo_[0])
|
||||
glDeleteBuffers(2, pbo_);
|
||||
pbo_size_ = 0;
|
||||
}
|
||||
|
||||
|
||||
guint Stream::width() const
|
||||
{
|
||||
return width_;
|
||||
}
|
||||
|
||||
guint Stream::height() const
|
||||
{
|
||||
return height_;
|
||||
}
|
||||
|
||||
float Stream::aspectRatio() const
|
||||
{
|
||||
return static_cast<float>(width_) / static_cast<float>(height_);
|
||||
}
|
||||
|
||||
void Stream::enable(bool on)
|
||||
{
|
||||
if ( !ready_ )
|
||||
return;
|
||||
|
||||
if ( enabled_ != on ) {
|
||||
|
||||
enabled_ = on;
|
||||
|
||||
// default to pause
|
||||
GstState requested_state = GST_STATE_PAUSED;
|
||||
|
||||
// unpause only if enabled
|
||||
if (enabled_) {
|
||||
requested_state = desired_state_;
|
||||
}
|
||||
|
||||
// apply state change
|
||||
GstStateChangeReturn ret = gst_element_set_state (pipeline_, requested_state);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE) {
|
||||
Log::Warning("Stream %s Failed to enable", std::to_string(id_).c_str());
|
||||
failed_ = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool Stream::isEnabled() const
|
||||
{
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
bool Stream::singleFrame() const
|
||||
{
|
||||
return single_frame_;
|
||||
}
|
||||
|
||||
void Stream::play(bool on)
|
||||
{
|
||||
// ignore if disabled, and cannot play an image
|
||||
if (!enabled_)
|
||||
return;
|
||||
|
||||
// request state
|
||||
GstState requested_state = on ? GST_STATE_PLAYING : GST_STATE_PAUSED;
|
||||
|
||||
// ignore if requesting twice same state
|
||||
if (desired_state_ == requested_state)
|
||||
return;
|
||||
|
||||
// accept request to the desired state
|
||||
desired_state_ = requested_state;
|
||||
|
||||
// if not ready yet, the requested state will be handled later
|
||||
if ( pipeline_ == nullptr )
|
||||
return;
|
||||
|
||||
// all ready, apply state change immediately
|
||||
GstStateChangeReturn ret = gst_element_set_state (pipeline_, desired_state_);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE) {
|
||||
Log::Warning("Stream %s Failed to play", std::to_string(id_).c_str());
|
||||
failed_ = true;
|
||||
}
|
||||
#ifdef STREAM_DEBUG
|
||||
else if (on)
|
||||
Log::Info("Stream %s Start", std::to_string(id_).c_str());
|
||||
else
|
||||
Log::Info("Stream %s Stop", std::to_string(id_).c_str());
|
||||
#endif
|
||||
|
||||
// reset time counter
|
||||
timecount_.reset();
|
||||
|
||||
}
|
||||
|
||||
bool Stream::isPlaying(bool testpipeline) const
|
||||
{
|
||||
// if not ready yet, answer with requested state
|
||||
if ( !testpipeline || pipeline_ == nullptr || !enabled_)
|
||||
return desired_state_ == GST_STATE_PLAYING;
|
||||
|
||||
// if ready, answer with actual state
|
||||
GstState state;
|
||||
gst_element_get_state (pipeline_, &state, NULL, GST_CLOCK_TIME_NONE);
|
||||
return state == GST_STATE_PLAYING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Stream::init_texture(guint index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGenTextures(1, &textureindex_);
|
||||
glBindTexture(GL_TEXTURE_2D, textureindex_);
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width_, height_);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, frame_[index].vframe.data[0]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
|
||||
// set pbo image size
|
||||
pbo_size_ = height_ * width_ * 4;
|
||||
|
||||
// create pixel buffer objects,
|
||||
if (pbo_[0])
|
||||
glDeleteBuffers(2, pbo_);
|
||||
glGenBuffers(2, pbo_);
|
||||
|
||||
for(int i = 0; i < 2; i++ ) {
|
||||
// create 2 PBOs
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_[i]);
|
||||
// glBufferDataARB with NULL pointer reserves only memory space.
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, pbo_size_, 0, GL_STREAM_DRAW);
|
||||
// fill in with reset picture
|
||||
GLubyte* ptr = (GLubyte*) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
|
||||
if (ptr) {
|
||||
// update data directly on the mapped buffer
|
||||
memmove(ptr, frame_[index].vframe.data[0], pbo_size_);
|
||||
// release pointer to mapping buffer
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
}
|
||||
else {
|
||||
// did not work, disable PBO
|
||||
glDeleteBuffers(4, pbo_);
|
||||
pbo_[0] = pbo_[1] = 0;
|
||||
pbo_size_ = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// should be good to go, wrap it up
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
pbo_index_ = 0;
|
||||
pbo_next_index_ = 1;
|
||||
|
||||
#ifdef STREAM_DEBUG
|
||||
Log::Info("Stream %s Using Pixel Buffer Object texturing.", std::to_string(id_).c_str());
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Stream::fill_texture(guint index)
|
||||
{
|
||||
// is this the first frame ?
|
||||
if (textureindex_ < 1)
|
||||
{
|
||||
// initialize texture
|
||||
init_texture(index);
|
||||
|
||||
}
|
||||
else {
|
||||
glBindTexture(GL_TEXTURE_2D, textureindex_);
|
||||
|
||||
// use dual Pixel Buffer Object
|
||||
if (pbo_size_ > 0) {
|
||||
// In dual PBO mode, increment current index first then get the next index
|
||||
pbo_index_ = (pbo_index_ + 1) % 2;
|
||||
pbo_next_index_ = (pbo_index_ + 1) % 2;
|
||||
|
||||
// bind PBO to read pixels
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_[pbo_index_]);
|
||||
// copy pixels from PBO to texture object
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
// bind the next PBO to write pixels
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_[pbo_next_index_]);
|
||||
// See http://www.songho.ca/opengl/gl_pbo.html#map for more details
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, pbo_size_, 0, GL_STREAM_DRAW);
|
||||
// map the buffer object into client's memory
|
||||
GLubyte* ptr = (GLubyte*) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
|
||||
if (ptr) {
|
||||
// update data directly on the mapped buffer
|
||||
// NB : equivalent but faster (memmove instead of memcpy ?) than
|
||||
// glNamedBufferSubData(pboIds[nextIndex], 0, imgsize, vp->getBuffer())
|
||||
memmove(ptr, frame_[index].vframe.data[0], pbo_size_);
|
||||
|
||||
// release pointer to mapping buffer
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
}
|
||||
// done with PBO
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
else {
|
||||
// without PBO, use standard opengl (slower)
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, frame_[index].vframe.data[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Stream::update()
|
||||
{
|
||||
// discard
|
||||
if (failed_)
|
||||
return;
|
||||
|
||||
// not ready yet
|
||||
if (!ready_)
|
||||
return;
|
||||
|
||||
// // prevent unnecessary updates: disabled or already filled image
|
||||
// if (!enabled_)
|
||||
// return;
|
||||
|
||||
|
||||
// local variables before trying to update
|
||||
guint read_index = 0;
|
||||
bool need_loop = false;
|
||||
|
||||
// locked access to current index
|
||||
index_lock_.lock();
|
||||
// get the last frame filled from fill_frame()
|
||||
read_index = last_index_;
|
||||
|
||||
// Do NOT miss and jump directly (after seek) to a pre-roll
|
||||
for (guint i = 0; i < N_FRAME; ++i) {
|
||||
if (frame_[i].status == PREROLL) {
|
||||
read_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// unlock access to index change
|
||||
index_lock_.unlock();
|
||||
|
||||
// lock frame while reading it
|
||||
frame_[read_index].access.lock();
|
||||
|
||||
|
||||
// do not fill a frame twice
|
||||
if (frame_[read_index].status != INVALID ) {
|
||||
|
||||
|
||||
// is this an End-of-Stream frame ?
|
||||
if (frame_[read_index].status == EOS )
|
||||
{
|
||||
// will execute seek command below (after unlock)
|
||||
need_loop = true;
|
||||
}
|
||||
// otherwise just fill non-empty SAMPLE or PREROLL
|
||||
else if (frame_[read_index].full)
|
||||
{
|
||||
// fill the texture with the frame at reading index
|
||||
fill_texture(read_index);
|
||||
|
||||
// double update for pre-roll frame and dual PBO (ensure frame is displayed now)
|
||||
if (frame_[read_index].status == PREROLL && pbo_size_ > 0)
|
||||
fill_texture(read_index);
|
||||
}
|
||||
|
||||
// avoid reading it again
|
||||
frame_[read_index].status = INVALID;
|
||||
|
||||
}
|
||||
|
||||
// unkock frame after reading it
|
||||
frame_[read_index].access.unlock();
|
||||
|
||||
}
|
||||
|
||||
double Stream::updateFrameRate() const
|
||||
{
|
||||
return timecount_.frameRate();
|
||||
}
|
||||
|
||||
|
||||
// CALLBACKS
|
||||
|
||||
bool Stream::fill_frame(GstBuffer *buf, FrameStatus status)
|
||||
{
|
||||
// Log::Info("Stream fill frame");
|
||||
|
||||
// Do NOT overwrite an unread EOS
|
||||
if ( frame_[write_index_].status == EOS )
|
||||
write_index_ = (write_index_ + 1) % N_FRAME;
|
||||
|
||||
// lock access to frame
|
||||
frame_[write_index_].access.lock();
|
||||
|
||||
// always empty frame before filling it again
|
||||
if ( frame_[write_index_].full ) {
|
||||
gst_video_frame_unmap(&frame_[write_index_].vframe);
|
||||
frame_[write_index_].full = false;
|
||||
}
|
||||
|
||||
// accept status of frame received
|
||||
frame_[write_index_].status = status;
|
||||
|
||||
// a buffer is given (not EOS)
|
||||
if (buf != NULL) {
|
||||
// get the frame from buffer
|
||||
if ( !gst_video_frame_map (&frame_[write_index_].vframe, &v_frame_video_info_, buf, GST_MAP_READ ) )
|
||||
{
|
||||
Log::Info("Stream %s Failed to map the video buffer", std::to_string(id_).c_str());
|
||||
// free access to frame & exit
|
||||
frame_[write_index_].status = INVALID;
|
||||
frame_[write_index_].access.unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
// successfully filled the frame
|
||||
frame_[write_index_].full = true;
|
||||
|
||||
// validate frame format
|
||||
if( GST_VIDEO_INFO_IS_RGB(&(frame_[write_index_].vframe).info) && GST_VIDEO_INFO_N_PLANES(&(frame_[write_index_].vframe).info) == 1)
|
||||
{
|
||||
// set presentation time stamp
|
||||
frame_[write_index_].position = buf->pts;
|
||||
|
||||
}
|
||||
// full but invalid frame : will be deleted next iteration
|
||||
// (should never happen)
|
||||
else
|
||||
frame_[write_index_].status = INVALID;
|
||||
}
|
||||
// else; null buffer for EOS: give a position
|
||||
else {
|
||||
frame_[write_index_].status = EOS;
|
||||
}
|
||||
|
||||
// unlock access to frame
|
||||
frame_[write_index_].access.unlock();
|
||||
|
||||
// lock access to change current index (very quick)
|
||||
index_lock_.lock();
|
||||
// indicate update() that this is the last frame filled (and unlocked)
|
||||
last_index_ = write_index_;
|
||||
// unlock access to index change
|
||||
index_lock_.unlock();
|
||||
// for writing, we will access the next in stack
|
||||
write_index_ = (write_index_ + 1) % N_FRAME;
|
||||
|
||||
// calculate actual FPS of update
|
||||
timecount_.tic();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Stream::callback_end_of_stream (GstAppSink *, gpointer p)
|
||||
{
|
||||
Stream *m = (Stream *)p;
|
||||
if (m && m->ready_) {
|
||||
m->fill_frame(NULL, Stream::EOS);
|
||||
}
|
||||
}
|
||||
|
||||
GstFlowReturn Stream::callback_new_preroll (GstAppSink *sink, gpointer p)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
// blocking read pre-roll samples
|
||||
GstSample *sample = gst_app_sink_pull_preroll(sink);
|
||||
|
||||
// if got a valid sample
|
||||
if (sample != NULL) {
|
||||
|
||||
// get buffer from sample
|
||||
GstBuffer *buf = gst_sample_get_buffer (sample);
|
||||
|
||||
// send frames to media player only if ready
|
||||
Stream *m = (Stream *)p;
|
||||
if (m && m->ready_) {
|
||||
|
||||
// fill frame from buffer
|
||||
if ( !m->fill_frame(buf, Stream::PREROLL) )
|
||||
ret = GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
ret = GST_FLOW_FLUSHING;
|
||||
|
||||
// release sample
|
||||
gst_sample_unref (sample);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GstFlowReturn Stream::callback_new_sample (GstAppSink *sink, gpointer p)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
// non-blocking read new sample
|
||||
GstSample *sample = gst_app_sink_pull_sample(sink);
|
||||
|
||||
// if got a valid sample
|
||||
if (sample != NULL && !gst_app_sink_is_eos (sink)) {
|
||||
|
||||
// get buffer from sample (valid until sample is released)
|
||||
GstBuffer *buf = gst_sample_get_buffer (sample) ;
|
||||
|
||||
// send frames to media player only if ready
|
||||
Stream *m = (Stream *)p;
|
||||
if (m && m->ready_) {
|
||||
// fill frame with buffer
|
||||
if ( !m->fill_frame(buf, Stream::SAMPLE) )
|
||||
ret = GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
ret = GST_FLOW_FLUSHING;
|
||||
|
||||
// release sample
|
||||
gst_sample_unref (sample);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Stream::TimeCounter::TimeCounter() {
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void Stream::TimeCounter::tic ()
|
||||
{
|
||||
// how long since last time
|
||||
GstClockTime t = gst_util_get_timestamp ();
|
||||
GstClockTime dt = t - last_time;
|
||||
|
||||
// one more frame since last time
|
||||
nbFrames++;
|
||||
|
||||
// calculate instantaneous framerate
|
||||
// Exponential moving averate with previous framerate to filter jitter (50/50)
|
||||
// The divition of frame/time is done on long integer GstClockTime, counting in microsecond
|
||||
// NB: factor 100 to get 0.01 precision
|
||||
fps = 0.5 * fps + 0.005 * static_cast<double>( ( 100 * GST_SECOND * nbFrames ) / dt );
|
||||
|
||||
// reset counter every second
|
||||
if ( dt >= GST_SECOND)
|
||||
{
|
||||
last_time = t;
|
||||
nbFrames = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GstClockTime Stream::TimeCounter::dt ()
|
||||
{
|
||||
GstClockTime t = gst_util_get_timestamp ();
|
||||
GstClockTime dt = t - tic_time;
|
||||
tic_time = t;
|
||||
|
||||
// return the instantaneous delta t
|
||||
return dt;
|
||||
}
|
||||
|
||||
void Stream::TimeCounter::reset ()
|
||||
{
|
||||
last_time = gst_util_get_timestamp ();;
|
||||
tic_time = last_time;
|
||||
nbFrames = 0;
|
||||
fps = 0.0;
|
||||
}
|
||||
|
||||
double Stream::TimeCounter::frameRate() const
|
||||
{
|
||||
return fps;
|
||||
}
|
||||
|
||||
|
||||
184
Stream.h
184
Stream.h
@@ -1,11 +1,191 @@
|
||||
#ifndef STREAM_H
|
||||
#define STREAM_H
|
||||
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <future>
|
||||
|
||||
// GStreamer
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/app/gstappsink.h>
|
||||
|
||||
// Forward declare classes referenced
|
||||
class Visitor;
|
||||
|
||||
#define N_FRAME 3
|
||||
|
||||
class Stream {
|
||||
|
||||
class Stream
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor of a GStreamer Stream
|
||||
*/
|
||||
Stream();
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Stream();
|
||||
/**
|
||||
* Open a media using gstreamer pipeline keyword
|
||||
* */
|
||||
virtual void open( std::string description ) = 0;
|
||||
/**
|
||||
* Get description string
|
||||
* */
|
||||
virtual std::string description() const;
|
||||
/**
|
||||
* True if a media was oppenned
|
||||
* */
|
||||
bool isOpen() const;
|
||||
/**
|
||||
* True if problem occured
|
||||
* */
|
||||
bool failed() const;
|
||||
/**
|
||||
* Close the Media
|
||||
* */
|
||||
void close();
|
||||
/**
|
||||
* Update texture with latest frame
|
||||
* Must be called in rendering update loop
|
||||
* */
|
||||
virtual void update();
|
||||
/**
|
||||
* Enable / Disable
|
||||
* Suspend playing activity
|
||||
* (restores playing state when re-enabled)
|
||||
* */
|
||||
void enable(bool on);
|
||||
/**
|
||||
* True if enabled
|
||||
* */
|
||||
bool isEnabled() const;
|
||||
/**
|
||||
* True if its an image
|
||||
* */
|
||||
bool singleFrame() const;
|
||||
/**
|
||||
* Pause / Play
|
||||
* Can play backward if play speed is negative
|
||||
* */
|
||||
void play(bool on);
|
||||
/**
|
||||
* Get Pause / Play status
|
||||
* Performs a full check of the Gstreamer pipeline if testpipeline is true
|
||||
* */
|
||||
bool isPlaying(bool testpipeline = false) const;
|
||||
/**
|
||||
* Get rendering update framerate
|
||||
* measured during play
|
||||
* */
|
||||
double updateFrameRate() const;
|
||||
/**
|
||||
* Get frame width
|
||||
* */
|
||||
guint width() const;
|
||||
/**
|
||||
* Get frame height
|
||||
* */
|
||||
guint height() const;
|
||||
/**
|
||||
* Get frames displayt aspect ratio
|
||||
* NB: can be different than width() / height()
|
||||
* */
|
||||
float aspectRatio() const;
|
||||
/**
|
||||
* Get the OpenGL texture
|
||||
* Must be called in OpenGL context
|
||||
* */
|
||||
guint texture() const;
|
||||
/**
|
||||
* Accept visitors
|
||||
* Used for saving session file
|
||||
* */
|
||||
void accept(Visitor& v);
|
||||
|
||||
protected:
|
||||
|
||||
// video player description
|
||||
int id_;
|
||||
std::string description_;
|
||||
guint textureindex_;
|
||||
|
||||
// general properties of media
|
||||
guint width_;
|
||||
guint height_;
|
||||
bool single_frame_;
|
||||
|
||||
// GST & Play status
|
||||
GstState desired_state_;
|
||||
GstElement *pipeline_;
|
||||
GstVideoInfo v_frame_video_info_;
|
||||
std::atomic<bool> ready_;
|
||||
std::atomic<bool> failed_;
|
||||
bool enabled_;
|
||||
|
||||
// fps counter
|
||||
struct TimeCounter {
|
||||
|
||||
GstClockTime last_time;
|
||||
GstClockTime tic_time;
|
||||
int nbFrames;
|
||||
gdouble fps;
|
||||
public:
|
||||
TimeCounter();
|
||||
GstClockTime dt();
|
||||
void tic();
|
||||
void reset();
|
||||
gdouble frameRate() const;
|
||||
};
|
||||
TimeCounter timecount_;
|
||||
|
||||
// frame stack
|
||||
typedef enum {
|
||||
SAMPLE = 0,
|
||||
PREROLL = 1,
|
||||
EOS = 2,
|
||||
INVALID = 3
|
||||
} FrameStatus;
|
||||
|
||||
struct Frame {
|
||||
GstVideoFrame vframe;
|
||||
FrameStatus status;
|
||||
bool full;
|
||||
GstClockTime position;
|
||||
std::mutex access;
|
||||
|
||||
Frame() {
|
||||
full = false;
|
||||
status = INVALID;
|
||||
position = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
};
|
||||
Frame frame_[N_FRAME];
|
||||
guint write_index_;
|
||||
guint last_index_;
|
||||
std::mutex index_lock_;
|
||||
|
||||
// for PBO
|
||||
guint pbo_[2];
|
||||
guint pbo_index_, pbo_next_index_;
|
||||
guint pbo_size_;
|
||||
|
||||
// gst pipeline control
|
||||
virtual void execute_open();
|
||||
|
||||
// gst frame filling
|
||||
void init_texture(guint index);
|
||||
void fill_texture(guint index);
|
||||
bool fill_frame(GstBuffer *buf, FrameStatus status);
|
||||
|
||||
// gst callbacks
|
||||
static void callback_end_of_stream (GstAppSink *, gpointer);
|
||||
static GstFlowReturn callback_new_preroll (GstAppSink *, gpointer );
|
||||
static GstFlowReturn callback_new_sample (GstAppSink *, gpointer);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // STREAM_H
|
||||
|
||||
@@ -44,6 +44,7 @@ using namespace std;
|
||||
#include "SessionCreator.h"
|
||||
#include "ImGuiToolkit.h"
|
||||
#include "ImGuiVisitor.h"
|
||||
#include "GlmToolkit.h"
|
||||
#include "GstToolkit.h"
|
||||
#include "Mixer.h"
|
||||
#include "Recorder.h"
|
||||
@@ -51,6 +52,7 @@ using namespace std;
|
||||
#include "FrameBuffer.h"
|
||||
#include "MediaPlayer.h"
|
||||
#include "MediaSource.h"
|
||||
#include "PatternSource.h"
|
||||
#include "PickingVisitor.h"
|
||||
#include "ImageShader.h"
|
||||
#include "ImageProcessingShader.h"
|
||||
@@ -1532,7 +1534,6 @@ Navigator::Navigator()
|
||||
pannel_width_ = 5.f * width_;
|
||||
height_ = 100;
|
||||
padding_width_ = 100;
|
||||
new_source_type_ = 0;
|
||||
|
||||
// clean start
|
||||
clearButtonSelection();
|
||||
@@ -1841,13 +1842,13 @@ void Navigator::RenderNewPannel()
|
||||
ImGui::SetCursorPosY(width_);
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
|
||||
static const char* origin_names[2] = { ICON_FA_FILE " File", ICON_FA_SITEMAP " Internal" };
|
||||
static const char* origin_names[3] = { ICON_FA_FILE " File", ICON_FA_SITEMAP " Internal", ICON_FA_COG " Generated" };
|
||||
// TODO IMPLEMENT EXTERNAL SOURCES static const char* origin_names[3] = { ICON_FA_FILE " File", ICON_FA_SITEMAP " Internal", ICON_FA_PLUG " External" };
|
||||
if (ImGui::Combo("Origin", &new_source_type_, origin_names, IM_ARRAYSIZE(origin_names)) )
|
||||
if (ImGui::Combo("Origin", &Settings::application.source.new_type, origin_names, IM_ARRAYSIZE(origin_names)) )
|
||||
new_source_preview_.setSource();
|
||||
|
||||
// File Source creation
|
||||
if (new_source_type_ == 0) {
|
||||
if (Settings::application.source.new_type == 0) {
|
||||
|
||||
ImGui::SetCursorPosY(2.f * width_);
|
||||
|
||||
@@ -1896,20 +1897,9 @@ void Navigator::RenderNewPannel()
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
// if a new source was added
|
||||
if (new_source_preview_.ready()) {
|
||||
// show preview
|
||||
new_source_preview_.Render(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, true);
|
||||
// or press Validate button
|
||||
ImGui::Spacing();
|
||||
if ( ImGui::Button(ICON_FA_CHECK " Create", ImVec2(pannel_width_ - padding_width_, 0)) ) {
|
||||
Mixer::manager().addSource(new_source_preview_.getSource());
|
||||
selected_button[NAV_NEW] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Software Source creator
|
||||
else if (new_source_type_ == 1){
|
||||
else if (Settings::application.source.new_type == 1){
|
||||
|
||||
ImGui::SetCursorPosY(2.f * width_);
|
||||
|
||||
@@ -1934,19 +1924,41 @@ void Navigator::RenderNewPannel()
|
||||
|
||||
// Indication
|
||||
ImGui::SameLine();
|
||||
ImGuiToolkit::HelpMarker("Create a source generating images\nfrom internal vimix objects\nor from software algorithms.");
|
||||
ImGuiToolkit::HelpMarker("Create a source replicating internal vimix objects.");
|
||||
}
|
||||
// Software Source creator
|
||||
else if (Settings::application.source.new_type == 2){
|
||||
|
||||
// if a new source was added
|
||||
if (new_source_preview_.ready()) {
|
||||
// show preview
|
||||
new_source_preview_.Render(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
|
||||
// ask to import the source in the mixer
|
||||
ImGui::Text(" ");
|
||||
if ( ImGui::Button( ICON_FA_CHECK " Create", ImVec2(pannel_width_ - padding_width_, 0)) ) {
|
||||
Mixer::manager().addSource(new_source_preview_.getSource());
|
||||
selected_button[NAV_NEW] = false;
|
||||
}
|
||||
ImGui::SetCursorPosY(2.f * width_);
|
||||
|
||||
bool update_new_source = false;
|
||||
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
if (ImGui::Combo("Aspect Ratio", &Settings::application.source.ratio,
|
||||
GlmToolkit::aspect_ratio_names, IM_ARRAYSIZE(GlmToolkit::aspect_ratio_names) ) )
|
||||
update_new_source = true;
|
||||
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
if (ImGui::Combo("Height", &Settings::application.source.res,
|
||||
GlmToolkit::height_names, IM_ARRAYSIZE(GlmToolkit::height_names) ) )
|
||||
update_new_source = true;
|
||||
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
if ( ImGui::Combo("Pattern", &Settings::application.source.pattern_type,
|
||||
Pattern::pattern_names, IM_ARRAYSIZE(Pattern::pattern_names) ) )
|
||||
update_new_source = true;
|
||||
|
||||
if (update_new_source)
|
||||
{
|
||||
std::string label = Pattern::pattern_names[Settings::application.source.pattern_type];
|
||||
glm::ivec2 res = GlmToolkit::resolutionFromDescription(Settings::application.source.ratio, Settings::application.source.res);
|
||||
new_source_preview_.setSource( Mixer::manager().createSourcePattern(Settings::application.source.pattern_type, res), label);
|
||||
}
|
||||
|
||||
// Indication
|
||||
ImGui::SameLine();
|
||||
ImGuiToolkit::HelpMarker("Create a source generated algorithmically.");
|
||||
|
||||
}
|
||||
// Hardware
|
||||
else {
|
||||
@@ -1955,6 +1967,18 @@ void Navigator::RenderNewPannel()
|
||||
ImGuiToolkit::HelpMarker("Create a source capturing images\nfrom external devices or network.");
|
||||
}
|
||||
|
||||
// if a new source was added
|
||||
if (new_source_preview_.ready()) {
|
||||
// show preview
|
||||
new_source_preview_.Render(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, Settings::application.source.new_type != 1);
|
||||
// ask to import the source in the mixer
|
||||
ImGui::NewLine();
|
||||
if ( ImGui::Button( ICON_FA_CHECK " Create", ImVec2(pannel_width_ - padding_width_, 0)) ) {
|
||||
Mixer::manager().addSource(new_source_preview_.getSource());
|
||||
selected_button[NAV_NEW] = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -2209,6 +2233,7 @@ void Navigator::RenderMainPannel()
|
||||
|
||||
// options session
|
||||
ImGui::Spacing();
|
||||
ImGui::Spacing();
|
||||
ImGui::Text("Options");
|
||||
ImGuiToolkit::ButtonSwitch( ICON_FA_ARROW_CIRCLE_RIGHT " Smooth transition", &Settings::application.smooth_transition);
|
||||
ImGuiToolkit::ButtonSwitch( ICON_FA_MOUSE_POINTER " Smooth cursor", &Settings::application.smooth_cursor);
|
||||
|
||||
@@ -49,7 +49,6 @@ class Navigator
|
||||
void RenderMainPannel();
|
||||
void RenderTransitionPannel();
|
||||
void RenderNewPannel();
|
||||
int new_source_type_;
|
||||
char file_browser_path_[2048];
|
||||
|
||||
SourcePreview new_source_preview_;
|
||||
|
||||
@@ -20,12 +20,14 @@ class Mesh;
|
||||
class Frame;
|
||||
class Handles;
|
||||
class Disk;
|
||||
class Stream;
|
||||
class MediaPlayer;
|
||||
class Shader;
|
||||
class ImageShader;
|
||||
class ImageProcessingShader;
|
||||
class Source;
|
||||
class MediaSource;
|
||||
class PatternSource;
|
||||
class SessionSource;
|
||||
class RenderSource;
|
||||
class CloneSource;
|
||||
@@ -53,6 +55,7 @@ public:
|
||||
virtual void visit (Frame&) {}
|
||||
virtual void visit (Handles&) {}
|
||||
virtual void visit (Disk&) {}
|
||||
virtual void visit (Stream&) {}
|
||||
virtual void visit (MediaPlayer&) {}
|
||||
virtual void visit (Shader&) {}
|
||||
virtual void visit (ImageShader&) {}
|
||||
@@ -61,6 +64,7 @@ public:
|
||||
// utility
|
||||
virtual void visit (Source&) {}
|
||||
virtual void visit (MediaSource&) {}
|
||||
virtual void visit (PatternSource&) {}
|
||||
virtual void visit (SessionSource&) {}
|
||||
virtual void visit (RenderSource&) {}
|
||||
virtual void visit (CloneSource&) {}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#define APP_TITLE " -- Video Live Mixer"
|
||||
#define APP_SETTINGS "vimix.xml"
|
||||
#define APP_VERSION_MAJOR 0
|
||||
#define APP_VERSION_MINOR 2
|
||||
#define APP_VERSION_MINOR 3
|
||||
#define XML_VERSION_MAJOR 0
|
||||
#define XML_VERSION_MINOR 1
|
||||
#define MAX_RECENT_HISTORY 20
|
||||
|
||||
800
rsc/mesh/icon_gear.ply
Normal file
800
rsc/mesh/icon_gear.ply
Normal file
@@ -0,0 +1,800 @@
|
||||
ply
|
||||
format ascii 1.0
|
||||
comment Created by Blender 2.90.0 - www.blender.org
|
||||
element vertex 393
|
||||
property float x
|
||||
property float y
|
||||
property float z
|
||||
property uchar red
|
||||
property uchar green
|
||||
property uchar blue
|
||||
property uchar alpha
|
||||
element face 393
|
||||
property list uchar uint vertex_indices
|
||||
end_header
|
||||
-0.122248 -0.092391 0.000000 255 255 255 255
|
||||
-0.101952 0.069939 0.000000 255 255 255 255
|
||||
-0.122248 0.090230 0.000000 255 255 255 255
|
||||
0.121299 0.090230 0.000000 255 255 255 255
|
||||
0.101003 0.069939 0.000000 255 255 255 255
|
||||
0.121299 -0.092391 0.000000 255 255 255 255
|
||||
-0.101952 -0.072100 0.000000 255 255 255 255
|
||||
0.101003 -0.072100 0.000000 255 255 255 255
|
||||
-0.009900 0.059027 0.000000 255 255 255 255
|
||||
-0.008882 0.061032 0.000000 255 255 255 255
|
||||
-0.009204 0.061032 0.000000 255 255 255 255
|
||||
-0.007993 0.061032 0.000000 255 255 255 255
|
||||
-0.006651 0.061032 0.000000 255 255 255 255
|
||||
-0.004968 0.061032 0.000000 255 255 255 255
|
||||
-0.003058 0.061032 0.000000 255 255 255 255
|
||||
-0.001035 0.061032 0.000000 255 255 255 255
|
||||
0.000988 0.061032 0.000000 255 255 255 255
|
||||
0.002898 0.061032 0.000000 255 255 255 255
|
||||
0.004581 0.061032 0.000000 255 255 255 255
|
||||
0.005924 0.061032 0.000000 255 255 255 255
|
||||
0.006812 0.061032 0.000000 255 255 255 255
|
||||
0.007134 0.061032 0.000000 255 255 255 255
|
||||
0.007832 0.059019 0.000000 255 255 255 255
|
||||
-0.010535 0.057143 0.000000 255 255 255 255
|
||||
0.008469 0.057129 0.000000 255 255 255 255
|
||||
-0.011137 0.055379 0.000000 255 255 255 255
|
||||
0.009072 0.055361 0.000000 255 255 255 255
|
||||
-0.011730 0.053734 0.000000 255 255 255 255
|
||||
0.009666 0.053715 0.000000 255 255 255 255
|
||||
-0.012343 0.052208 0.000000 255 255 255 255
|
||||
0.010279 0.052189 0.000000 255 255 255 255
|
||||
-0.013002 0.050798 0.000000 255 255 255 255
|
||||
0.010938 0.050781 0.000000 255 255 255 255
|
||||
-0.013734 0.049506 0.000000 255 255 255 255
|
||||
0.011669 0.049492 0.000000 255 255 255 255
|
||||
-0.014564 0.048329 0.000000 255 255 255 255
|
||||
0.012499 0.048318 0.000000 255 255 255 255
|
||||
-0.038380 0.048818 0.000000 255 255 255 255
|
||||
-0.036234 0.048114 0.000000 255 255 255 255
|
||||
-0.038153 0.049045 0.000000 255 255 255 255
|
||||
0.034180 0.048122 0.000000 255 255 255 255
|
||||
0.036310 0.048818 0.000000 255 255 255 255
|
||||
0.036083 0.049045 0.000000 255 255 255 255
|
||||
-0.039008 0.048189 0.000000 255 255 255 255
|
||||
0.036938 0.048189 0.000000 255 255 255 255
|
||||
-0.015520 0.047268 0.000000 255 255 255 255
|
||||
0.013454 0.047260 0.000000 255 255 255 255
|
||||
-0.039957 0.047240 0.000000 255 255 255 255
|
||||
0.037888 0.047240 0.000000 255 255 255 255
|
||||
0.032402 0.047240 0.000000 255 255 255 255
|
||||
-0.034446 0.047228 0.000000 255 255 255 255
|
||||
-0.016629 0.046320 0.000000 255 255 255 255
|
||||
0.014561 0.046316 0.000000 255 255 255 255
|
||||
-0.041147 0.046051 0.000000 255 255 255 255
|
||||
0.039077 0.046051 0.000000 255 255 255 255
|
||||
0.030732 0.046419 0.000000 255 255 255 255
|
||||
-0.032770 0.046404 0.000000 255 255 255 255
|
||||
0.029149 0.045675 0.000000 255 255 255 255
|
||||
-0.031184 0.045660 0.000000 255 255 255 255
|
||||
-0.017916 0.045486 0.000000 255 255 255 255
|
||||
0.015848 0.045484 0.000000 255 255 255 255
|
||||
-0.042497 0.044701 0.000000 255 255 255 255
|
||||
0.040428 0.044701 0.000000 255 255 255 255
|
||||
0.027635 0.045029 0.000000 255 255 255 255
|
||||
-0.029670 0.045014 0.000000 255 255 255 255
|
||||
-0.019409 0.044764 0.000000 255 255 255 255
|
||||
0.017339 0.044764 0.000000 255 255 255 255
|
||||
0.026170 0.044498 0.000000 255 255 255 255
|
||||
-0.028207 0.044484 0.000000 255 255 255 255
|
||||
-0.020981 0.044216 0.000000 255 255 255 255
|
||||
-0.019414 0.044764 0.000000 255 255 255 255
|
||||
-0.019414 0.044764 0.000000 255 255 255 255
|
||||
-0.019414 0.044764 0.000000 255 255 255 255
|
||||
-0.019414 0.044764 0.000000 255 255 255 255
|
||||
-0.019413 0.044764 0.000000 255 255 255 255
|
||||
-0.019412 0.044764 0.000000 255 255 255 255
|
||||
-0.019412 0.044764 0.000000 255 255 255 255
|
||||
-0.019411 0.044764 0.000000 255 255 255 255
|
||||
-0.019411 0.044764 0.000000 255 255 255 255
|
||||
-0.019410 0.044764 0.000000 255 255 255 255
|
||||
-0.019410 0.044764 0.000000 255 255 255 255
|
||||
-0.019409 0.044764 0.000000 255 255 255 255
|
||||
0.017340 0.044764 0.000000 255 255 255 255
|
||||
0.017340 0.044764 0.000000 255 255 255 255
|
||||
0.017340 0.044764 0.000000 255 255 255 255
|
||||
0.017341 0.044764 0.000000 255 255 255 255
|
||||
0.017341 0.044764 0.000000 255 255 255 255
|
||||
0.017342 0.044764 0.000000 255 255 255 255
|
||||
0.017343 0.044764 0.000000 255 255 255 255
|
||||
0.017343 0.044764 0.000000 255 255 255 255
|
||||
0.017344 0.044764 0.000000 255 255 255 255
|
||||
0.017344 0.044764 0.000000 255 255 255 255
|
||||
0.017344 0.044764 0.000000 255 255 255 255
|
||||
0.017345 0.044764 0.000000 255 255 255 255
|
||||
0.018915 0.044216 0.000000 255 255 255 255
|
||||
-0.043928 0.043271 0.000000 255 255 255 255
|
||||
0.041858 0.043271 0.000000 255 255 255 255
|
||||
0.024735 0.044100 0.000000 255 255 255 255
|
||||
-0.026777 0.044089 0.000000 255 255 255 255
|
||||
0.020421 0.043894 0.000000 255 255 255 255
|
||||
-0.022480 0.043892 0.000000 255 255 255 255
|
||||
0.023311 0.043855 0.000000 255 255 255 255
|
||||
-0.025359 0.043847 0.000000 255 255 255 255
|
||||
0.021880 0.043780 0.000000 255 255 255 255
|
||||
-0.023933 0.043775 0.000000 255 255 255 255
|
||||
-0.045358 0.041841 0.000000 255 255 255 255
|
||||
0.043288 0.041841 0.000000 255 255 255 255
|
||||
-0.046708 0.040491 0.000000 255 255 255 255
|
||||
0.044639 0.040491 0.000000 255 255 255 255
|
||||
-0.047898 0.039301 0.000000 255 255 255 255
|
||||
0.045828 0.039301 0.000000 255 255 255 255
|
||||
-0.048847 0.038352 0.000000 255 255 255 255
|
||||
0.046778 0.038352 0.000000 255 255 255 255
|
||||
-0.049476 0.037724 0.000000 255 255 255 255
|
||||
0.047406 0.037724 0.000000 255 255 255 255
|
||||
-0.049703 0.037497 0.000000 255 255 255 255
|
||||
0.047633 0.037497 0.000000 255 255 255 255
|
||||
-0.048777 0.035587 0.000000 255 255 255 255
|
||||
0.046705 0.035581 0.000000 255 255 255 255
|
||||
-0.047893 0.033804 0.000000 255 255 255 255
|
||||
0.045820 0.033795 0.000000 255 255 255 255
|
||||
-0.047070 0.032131 0.000000 255 255 255 255
|
||||
0.044997 0.032119 0.000000 255 255 255 255
|
||||
-0.046326 0.030548 0.000000 255 255 255 255
|
||||
0.044253 0.030534 0.000000 255 255 255 255
|
||||
-0.045680 0.029034 0.000000 255 255 255 255
|
||||
0.043607 0.029020 0.000000 255 255 255 255
|
||||
-0.045149 0.027571 0.000000 255 255 255 255
|
||||
0.043077 0.027557 0.000000 255 255 255 255
|
||||
-0.044753 0.026139 0.000000 255 255 255 255
|
||||
0.042682 0.026127 0.000000 255 255 255 255
|
||||
-0.044508 0.024718 0.000000 255 255 255 255
|
||||
0.042439 0.024708 0.000000 255 255 255 255
|
||||
-0.044435 0.023290 0.000000 255 255 255 255
|
||||
0.042366 0.023282 0.000000 255 255 255 255
|
||||
-0.044550 0.021834 0.000000 255 255 255 255
|
||||
0.042482 0.021829 0.000000 255 255 255 255
|
||||
-0.044873 0.020331 0.000000 255 255 255 255
|
||||
-0.001035 0.020602 0.000000 255 255 255 255
|
||||
0.042804 0.020329 0.000000 255 255 255 255
|
||||
-0.003778 0.020418 0.000000 255 255 255 255
|
||||
0.001709 0.020418 0.000000 255 255 255 255
|
||||
0.004340 0.019880 0.000000 255 255 255 255
|
||||
-0.006410 0.019880 0.000000 255 255 255 255
|
||||
-0.045421 0.018763 0.000000 255 255 255 255
|
||||
0.043352 0.018763 0.000000 255 255 255 255
|
||||
0.006835 0.019013 0.000000 255 255 255 255
|
||||
-0.008905 0.019013 0.000000 255 255 255 255
|
||||
0.009170 0.017842 0.000000 255 255 255 255
|
||||
-0.011240 0.017842 0.000000 255 255 255 255
|
||||
-0.046143 0.017269 0.000000 255 255 255 255
|
||||
0.043352 0.018762 0.000000 255 255 255 255
|
||||
0.043352 0.018762 0.000000 255 255 255 255
|
||||
0.043352 0.018762 0.000000 255 255 255 255
|
||||
0.043352 0.018761 0.000000 255 255 255 255
|
||||
0.043352 0.018761 0.000000 255 255 255 255
|
||||
0.043352 0.018760 0.000000 255 255 255 255
|
||||
0.043352 0.018759 0.000000 255 255 255 255
|
||||
0.043352 0.018759 0.000000 255 255 255 255
|
||||
0.043352 0.018758 0.000000 255 255 255 255
|
||||
0.043352 0.018758 0.000000 255 255 255 255
|
||||
0.043352 0.018758 0.000000 255 255 255 255
|
||||
0.043352 0.018758 0.000000 255 255 255 255
|
||||
0.044070 0.017268 0.000000 255 255 255 255
|
||||
0.011320 0.016390 0.000000 255 255 255 255
|
||||
-0.013390 0.016390 0.000000 255 255 255 255
|
||||
-0.046978 0.015980 0.000000 255 255 255 255
|
||||
0.044899 0.015984 0.000000 255 255 255 255
|
||||
0.013262 0.014681 0.000000 255 255 255 255
|
||||
-0.015332 0.014681 0.000000 255 255 255 255
|
||||
0.045840 0.014879 0.000000 255 255 255 255
|
||||
-0.047926 0.014871 0.000000 255 255 255 255
|
||||
0.046895 0.013926 0.000000 255 255 255 255
|
||||
-0.048987 0.013915 0.000000 255 255 255 255
|
||||
0.014971 0.012740 0.000000 255 255 255 255
|
||||
-0.017041 0.012740 0.000000 255 255 255 255
|
||||
0.048066 0.013097 0.000000 255 255 255 255
|
||||
-0.050164 0.013084 0.000000 255 255 255 255
|
||||
0.049353 0.012367 0.000000 255 255 255 255
|
||||
-0.051457 0.012352 0.000000 255 255 255 255
|
||||
0.016424 0.010590 0.000000 255 255 255 255
|
||||
-0.018494 0.010590 0.000000 255 255 255 255
|
||||
0.050759 0.011708 0.000000 255 255 255 255
|
||||
-0.052866 0.011694 0.000000 255 255 255 255
|
||||
0.052285 0.011095 0.000000 255 255 255 255
|
||||
-0.054393 0.011080 0.000000 255 255 255 255
|
||||
0.053933 0.010499 0.000000 255 255 255 255
|
||||
-0.056039 0.010487 0.000000 255 255 255 255
|
||||
0.017595 0.008255 0.000000 255 255 255 255
|
||||
-0.019665 0.008255 0.000000 255 255 255 255
|
||||
0.055704 0.009895 0.000000 255 255 255 255
|
||||
-0.057803 0.009885 0.000000 255 255 255 255
|
||||
0.057601 0.009256 0.000000 255 255 255 255
|
||||
-0.059688 0.009250 0.000000 255 255 255 255
|
||||
0.059623 0.008554 0.000000 255 255 255 255
|
||||
-0.061693 0.008554 0.000000 255 255 255 255
|
||||
-0.061693 0.008233 0.000000 255 255 255 255
|
||||
0.059623 -0.007780 0.000000 255 255 255 255
|
||||
-0.020532 0.005761 0.000000 255 255 255 255
|
||||
0.018462 0.005761 0.000000 255 255 255 255
|
||||
-0.061693 0.007344 0.000000 255 255 255 255
|
||||
-0.061693 0.006002 0.000000 255 255 255 255
|
||||
-0.061693 0.004319 0.000000 255 255 255 255
|
||||
-0.021070 0.003130 0.000000 255 255 255 255
|
||||
0.019000 0.003130 0.000000 255 255 255 255
|
||||
-0.061693 0.002410 0.000000 255 255 255 255
|
||||
-0.021254 0.000387 0.000000 255 255 255 255
|
||||
0.019184 0.000387 0.000000 255 255 255 255
|
||||
-0.061693 0.000387 0.000000 255 255 255 255
|
||||
-0.061693 -0.001636 0.000000 255 255 255 255
|
||||
-0.021070 -0.002356 0.000000 255 255 255 255
|
||||
0.019000 -0.002356 0.000000 255 255 255 255
|
||||
-0.061693 -0.003545 0.000000 255 255 255 255
|
||||
0.018462 -0.004987 0.000000 255 255 255 255
|
||||
-0.020532 -0.004987 0.000000 255 255 255 255
|
||||
-0.061693 -0.005228 0.000000 255 255 255 255
|
||||
0.017595 -0.007481 0.000000 255 255 255 255
|
||||
-0.019665 -0.007481 0.000000 255 255 255 255
|
||||
-0.061693 -0.006570 0.000000 255 255 255 255
|
||||
-0.061693 -0.007459 0.000000 255 255 255 255
|
||||
-0.061693 -0.007780 0.000000 255 255 255 255
|
||||
0.016424 -0.009816 0.000000 255 255 255 255
|
||||
-0.018494 -0.009816 0.000000 255 255 255 255
|
||||
-0.059691 -0.008474 0.000000 255 255 255 255
|
||||
0.057620 -0.008475 0.000000 255 255 255 255
|
||||
-0.057808 -0.009108 0.000000 255 255 255 255
|
||||
0.055736 -0.009110 0.000000 255 255 255 255
|
||||
-0.056045 -0.009708 0.000000 255 255 255 255
|
||||
0.053971 -0.009711 0.000000 255 255 255 255
|
||||
-0.054400 -0.010302 0.000000 255 255 255 255
|
||||
0.052325 -0.010305 0.000000 255 255 255 255
|
||||
0.014971 -0.011966 0.000000 255 255 255 255
|
||||
-0.017041 -0.011966 0.000000 255 255 255 255
|
||||
-0.052873 -0.010915 0.000000 255 255 255 255
|
||||
0.050797 -0.010919 0.000000 255 255 255 255
|
||||
-0.051463 -0.011574 0.000000 255 255 255 255
|
||||
0.049386 -0.011579 0.000000 255 255 255 255
|
||||
-0.050169 -0.012306 0.000000 255 255 255 255
|
||||
0.048091 -0.012312 0.000000 255 255 255 255
|
||||
0.013262 -0.013907 0.000000 255 255 255 255
|
||||
-0.015332 -0.013907 0.000000 255 255 255 255
|
||||
-0.048991 -0.013137 0.000000 255 255 255 255
|
||||
0.046912 -0.013143 0.000000 255 255 255 255
|
||||
-0.047928 -0.014094 0.000000 255 255 255 255
|
||||
0.045849 -0.014101 0.000000 255 255 255 255
|
||||
0.011320 -0.015616 0.000000 255 255 255 255
|
||||
-0.013390 -0.015616 0.000000 255 255 255 255
|
||||
-0.046979 -0.015203 0.000000 255 255 255 255
|
||||
0.044899 -0.015211 0.000000 255 255 255 255
|
||||
-0.046144 -0.016490 0.000000 255 255 255 255
|
||||
0.044064 -0.016499 0.000000 255 255 255 255
|
||||
0.009170 -0.017068 0.000000 255 255 255 255
|
||||
-0.011240 -0.017068 0.000000 255 255 255 255
|
||||
-0.045421 -0.017983 0.000000 255 255 255 255
|
||||
0.043342 -0.017994 0.000000 255 255 255 255
|
||||
0.006835 -0.018239 0.000000 255 255 255 255
|
||||
-0.008905 -0.018239 0.000000 255 255 255 255
|
||||
-0.044872 -0.019564 0.000000 255 255 255 255
|
||||
0.042795 -0.019563 0.000000 255 255 255 255
|
||||
0.004340 -0.019106 0.000000 255 255 255 255
|
||||
-0.006410 -0.019106 0.000000 255 255 255 255
|
||||
0.001709 -0.019644 0.000000 255 255 255 255
|
||||
-0.003778 -0.019644 0.000000 255 255 255 255
|
||||
0.042473 -0.021066 0.000000 255 255 255 255
|
||||
-0.044551 -0.021080 0.000000 255 255 255 255
|
||||
-0.001035 -0.019828 0.000000 255 255 255 255
|
||||
0.042359 -0.022523 0.000000 255 255 255 255
|
||||
-0.044439 -0.022549 0.000000 255 255 255 255
|
||||
0.042433 -0.023953 0.000000 255 255 255 255
|
||||
-0.044517 -0.023989 0.000000 255 255 255 255
|
||||
0.042678 -0.025375 0.000000 255 255 255 255
|
||||
-0.044767 -0.025420 0.000000 255 255 255 255
|
||||
0.043076 -0.026809 0.000000 255 255 255 255
|
||||
-0.045168 -0.026860 0.000000 255 255 255 255
|
||||
0.043607 -0.028272 0.000000 255 255 255 255
|
||||
-0.045703 -0.028327 0.000000 255 255 255 255
|
||||
0.044253 -0.029786 0.000000 255 255 255 255
|
||||
-0.046351 -0.029839 0.000000 255 255 255 255
|
||||
0.044997 -0.031369 0.000000 255 255 255 255
|
||||
-0.047094 -0.031416 0.000000 255 255 255 255
|
||||
0.045820 -0.033040 0.000000 255 255 255 255
|
||||
-0.047913 -0.033076 0.000000 255 255 255 255
|
||||
0.046703 -0.034818 0.000000 255 255 255 255
|
||||
-0.048789 -0.034837 0.000000 255 255 255 255
|
||||
0.047628 -0.036723 0.000000 255 255 255 255
|
||||
-0.049703 -0.036718 0.000000 255 255 255 255
|
||||
-0.049476 -0.036945 0.000000 255 255 255 255
|
||||
0.047401 -0.036950 0.000000 255 255 255 255
|
||||
-0.048847 -0.037574 0.000000 255 255 255 255
|
||||
0.046773 -0.037579 0.000000 255 255 255 255
|
||||
-0.047898 -0.038523 0.000000 255 255 255 255
|
||||
0.045823 -0.038528 0.000000 255 255 255 255
|
||||
-0.046708 -0.039713 0.000000 255 255 255 255
|
||||
0.044634 -0.039718 0.000000 255 255 255 255
|
||||
-0.045358 -0.041064 0.000000 255 255 255 255
|
||||
0.043283 -0.041069 0.000000 255 255 255 255
|
||||
-0.043928 -0.042494 0.000000 255 255 255 255
|
||||
0.041853 -0.042499 0.000000 255 255 255 255
|
||||
-0.042497 -0.043925 0.000000 255 255 255 255
|
||||
-0.023947 -0.043005 0.000000 255 255 255 255
|
||||
0.021875 -0.042997 0.000000 255 255 255 255
|
||||
0.040423 -0.043930 0.000000 255 255 255 255
|
||||
0.020431 -0.043111 0.000000 255 255 255 255
|
||||
0.023294 -0.043071 0.000000 255 255 255 255
|
||||
-0.025378 -0.043080 0.000000 255 255 255 255
|
||||
-0.022488 -0.043120 0.000000 255 255 255 255
|
||||
0.024706 -0.043315 0.000000 255 255 255 255
|
||||
-0.026801 -0.043325 0.000000 255 255 255 255
|
||||
0.018941 -0.043431 0.000000 255 255 255 255
|
||||
-0.020984 -0.043442 0.000000 255 255 255 255
|
||||
0.026132 -0.043711 0.000000 255 255 255 255
|
||||
-0.028236 -0.043722 0.000000 255 255 255 255
|
||||
0.017385 -0.043975 0.000000 255 255 255 255
|
||||
-0.019414 -0.043990 0.000000 255 255 255 255
|
||||
0.017380 -0.043975 0.000000 255 255 255 255
|
||||
0.027592 -0.044241 0.000000 255 255 255 255
|
||||
-0.029701 -0.044253 0.000000 255 255 255 255
|
||||
-0.041147 -0.045276 0.000000 255 255 255 255
|
||||
0.039072 -0.045281 0.000000 255 255 255 255
|
||||
-0.019414 -0.043990 0.000000 255 255 255 255
|
||||
-0.019414 -0.043990 0.000000 255 255 255 255
|
||||
-0.019414 -0.043990 0.000000 255 255 255 255
|
||||
-0.019412 -0.043990 0.000000 255 255 255 255
|
||||
-0.019412 -0.043990 0.000000 255 255 255 255
|
||||
-0.019411 -0.043990 0.000000 255 255 255 255
|
||||
-0.019411 -0.043990 0.000000 255 255 255 255
|
||||
-0.019410 -0.043990 0.000000 255 255 255 255
|
||||
-0.019409 -0.043990 0.000000 255 255 255 255
|
||||
-0.019409 -0.043990 0.000000 255 255 255 255
|
||||
0.015878 -0.044702 0.000000 255 255 255 255
|
||||
0.017380 -0.043975 0.000000 255 255 255 255
|
||||
0.017380 -0.043975 0.000000 255 255 255 255
|
||||
0.017381 -0.043975 0.000000 255 255 255 255
|
||||
0.017381 -0.043975 0.000000 255 255 255 255
|
||||
0.017382 -0.043975 0.000000 255 255 255 255
|
||||
0.017382 -0.043975 0.000000 255 255 255 255
|
||||
0.017383 -0.043975 0.000000 255 255 255 255
|
||||
0.017384 -0.043975 0.000000 255 255 255 255
|
||||
0.017384 -0.043975 0.000000 255 255 255 255
|
||||
0.017385 -0.043975 0.000000 255 255 255 255
|
||||
0.017385 -0.043975 0.000000 255 255 255 255
|
||||
-0.019413 -0.043990 0.000000 255 255 255 255
|
||||
-0.019410 -0.043990 0.000000 255 255 255 255
|
||||
-0.017916 -0.044710 0.000000 255 255 255 255
|
||||
0.029104 -0.044888 0.000000 255 255 255 255
|
||||
-0.031215 -0.044899 0.000000 255 255 255 255
|
||||
0.014584 -0.045541 0.000000 255 255 255 255
|
||||
-0.016629 -0.045543 0.000000 255 255 255 255
|
||||
0.030689 -0.045632 0.000000 255 255 255 255
|
||||
-0.032799 -0.045643 0.000000 255 255 255 255
|
||||
-0.039957 -0.046466 0.000000 255 255 255 255
|
||||
0.037883 -0.046471 0.000000 255 255 255 255
|
||||
0.013469 -0.046491 0.000000 255 255 255 255
|
||||
-0.015521 -0.046488 0.000000 255 255 255 255
|
||||
0.032366 -0.046457 0.000000 255 255 255 255
|
||||
-0.034470 -0.046465 0.000000 255 255 255 255
|
||||
0.034156 -0.047344 0.000000 255 255 255 255
|
||||
-0.036248 -0.047347 0.000000 255 255 255 255
|
||||
-0.039008 -0.047415 0.000000 255 255 255 255
|
||||
0.036933 -0.047420 0.000000 255 255 255 255
|
||||
-0.014565 -0.047548 0.000000 255 255 255 255
|
||||
0.012508 -0.047554 0.000000 255 255 255 255
|
||||
0.036078 -0.048276 0.000000 255 255 255 255
|
||||
-0.038380 -0.048043 0.000000 255 255 255 255
|
||||
-0.038153 -0.048271 0.000000 255 255 255 255
|
||||
0.036305 -0.048049 0.000000 255 255 255 255
|
||||
-0.013735 -0.048722 0.000000 255 255 255 255
|
||||
0.011674 -0.048732 0.000000 255 255 255 255
|
||||
-0.013004 -0.050013 0.000000 255 255 255 255
|
||||
0.010939 -0.050024 0.000000 255 255 255 255
|
||||
-0.012346 -0.051421 0.000000 255 255 255 255
|
||||
0.010278 -0.051433 0.000000 255 255 255 255
|
||||
-0.011733 -0.052948 0.000000 255 255 255 255
|
||||
0.009663 -0.052960 0.000000 255 255 255 255
|
||||
-0.011139 -0.054594 0.000000 255 255 255 255
|
||||
0.009068 -0.054604 0.000000 255 255 255 255
|
||||
-0.010537 -0.056360 0.000000 255 255 255 255
|
||||
0.008466 -0.056368 0.000000 255 255 255 255
|
||||
-0.009901 -0.058248 0.000000 255 255 255 255
|
||||
0.007830 -0.058252 0.000000 255 255 255 255
|
||||
-0.009204 -0.060258 0.000000 255 255 255 255
|
||||
0.007134 -0.060258 0.000000 255 255 255 255
|
||||
-0.008882 -0.060258 0.000000 255 255 255 255
|
||||
-0.007993 -0.060258 0.000000 255 255 255 255
|
||||
-0.006651 -0.060258 0.000000 255 255 255 255
|
||||
-0.004968 -0.060258 0.000000 255 255 255 255
|
||||
-0.003058 -0.060258 0.000000 255 255 255 255
|
||||
-0.001035 -0.060258 0.000000 255 255 255 255
|
||||
0.000988 -0.060258 0.000000 255 255 255 255
|
||||
0.002898 -0.060258 0.000000 255 255 255 255
|
||||
0.004581 -0.060258 0.000000 255 255 255 255
|
||||
0.005924 -0.060258 0.000000 255 255 255 255
|
||||
0.006812 -0.060258 0.000000 255 255 255 255
|
||||
3 0 1 2
|
||||
3 1 3 2
|
||||
3 1 4 3
|
||||
3 4 5 3
|
||||
3 0 6 1
|
||||
3 7 5 4
|
||||
3 0 7 6
|
||||
3 0 5 7
|
||||
3 8 9 10
|
||||
3 8 11 9
|
||||
3 8 12 11
|
||||
3 8 13 12
|
||||
3 8 14 13
|
||||
3 8 15 14
|
||||
3 8 16 15
|
||||
3 8 17 16
|
||||
3 8 18 17
|
||||
3 8 19 18
|
||||
3 8 20 19
|
||||
3 8 21 20
|
||||
3 8 22 21
|
||||
3 23 22 8
|
||||
3 23 24 22
|
||||
3 25 24 23
|
||||
3 25 26 24
|
||||
3 27 26 25
|
||||
3 27 28 26
|
||||
3 29 28 27
|
||||
3 29 30 28
|
||||
3 31 30 29
|
||||
3 31 32 30
|
||||
3 33 32 31
|
||||
3 33 34 32
|
||||
3 35 34 33
|
||||
3 35 36 34
|
||||
3 37 38 39
|
||||
3 40 41 42
|
||||
3 43 38 37
|
||||
3 40 44 41
|
||||
3 45 36 35
|
||||
3 45 46 36
|
||||
3 47 38 43
|
||||
3 40 48 44
|
||||
3 49 48 40
|
||||
3 47 50 38
|
||||
3 51 46 45
|
||||
3 51 52 46
|
||||
3 53 50 47
|
||||
3 49 54 48
|
||||
3 55 54 49
|
||||
3 53 56 50
|
||||
3 57 54 55
|
||||
3 53 58 56
|
||||
3 59 52 51
|
||||
3 59 60 52
|
||||
3 61 58 53
|
||||
3 57 62 54
|
||||
3 63 62 57
|
||||
3 61 64 58
|
||||
3 65 60 59
|
||||
3 65 66 60
|
||||
3 67 62 63
|
||||
3 61 68 64
|
||||
3 69 70 71
|
||||
3 69 72 70
|
||||
3 69 73 72
|
||||
3 69 74 73
|
||||
3 69 75 74
|
||||
3 69 76 75
|
||||
3 69 77 76
|
||||
3 69 78 77
|
||||
3 69 79 78
|
||||
3 69 80 79
|
||||
3 69 81 80
|
||||
3 69 65 81
|
||||
3 69 66 65
|
||||
3 69 82 66
|
||||
3 69 83 82
|
||||
3 69 84 83
|
||||
3 69 85 84
|
||||
3 69 86 85
|
||||
3 69 87 86
|
||||
3 69 88 87
|
||||
3 69 89 88
|
||||
3 69 90 89
|
||||
3 69 91 90
|
||||
3 69 92 91
|
||||
3 69 93 92
|
||||
3 69 94 93
|
||||
3 95 68 61
|
||||
3 67 96 62
|
||||
3 97 96 67
|
||||
3 95 98 68
|
||||
3 69 99 94
|
||||
3 100 99 69
|
||||
3 101 96 97
|
||||
3 95 102 98
|
||||
3 100 103 99
|
||||
3 104 103 100
|
||||
3 103 96 101
|
||||
3 95 104 102
|
||||
3 104 96 103
|
||||
3 95 96 104
|
||||
3 105 96 95
|
||||
3 105 106 96
|
||||
3 107 106 105
|
||||
3 107 108 106
|
||||
3 109 108 107
|
||||
3 109 110 108
|
||||
3 111 110 109
|
||||
3 111 112 110
|
||||
3 113 112 111
|
||||
3 113 114 112
|
||||
3 115 114 113
|
||||
3 115 116 114
|
||||
3 117 116 115
|
||||
3 117 118 116
|
||||
3 119 118 117
|
||||
3 119 120 118
|
||||
3 121 120 119
|
||||
3 121 122 120
|
||||
3 123 122 121
|
||||
3 123 124 122
|
||||
3 125 124 123
|
||||
3 125 126 124
|
||||
3 127 126 125
|
||||
3 127 128 126
|
||||
3 129 128 127
|
||||
3 129 130 128
|
||||
3 131 130 129
|
||||
3 131 132 130
|
||||
3 133 132 131
|
||||
3 133 134 132
|
||||
3 135 134 133
|
||||
3 135 136 134
|
||||
3 137 136 135
|
||||
3 137 138 136
|
||||
3 138 139 136
|
||||
3 137 140 138
|
||||
3 141 139 138
|
||||
3 142 139 141
|
||||
3 137 143 140
|
||||
3 144 143 137
|
||||
3 142 145 139
|
||||
3 146 145 142
|
||||
3 144 147 143
|
||||
3 148 145 146
|
||||
3 144 149 147
|
||||
3 150 149 144
|
||||
3 148 151 145
|
||||
3 148 152 151
|
||||
3 148 153 152
|
||||
3 148 154 153
|
||||
3 148 155 154
|
||||
3 148 156 155
|
||||
3 148 157 156
|
||||
3 148 158 157
|
||||
3 148 159 158
|
||||
3 148 160 159
|
||||
3 148 161 160
|
||||
3 148 162 161
|
||||
3 148 163 162
|
||||
3 164 163 148
|
||||
3 150 165 149
|
||||
3 166 165 150
|
||||
3 164 167 163
|
||||
3 168 167 164
|
||||
3 166 169 165
|
||||
3 168 170 167
|
||||
3 171 169 166
|
||||
3 168 172 170
|
||||
3 173 169 171
|
||||
3 174 172 168
|
||||
3 173 175 169
|
||||
3 174 176 172
|
||||
3 177 175 173
|
||||
3 174 178 176
|
||||
3 179 175 177
|
||||
3 180 178 174
|
||||
3 179 181 175
|
||||
3 180 182 178
|
||||
3 183 181 179
|
||||
3 180 184 182
|
||||
3 185 181 183
|
||||
3 180 186 184
|
||||
3 187 181 185
|
||||
3 188 186 180
|
||||
3 187 189 181
|
||||
3 188 190 186
|
||||
3 191 189 187
|
||||
3 188 192 190
|
||||
3 193 189 191
|
||||
3 188 194 192
|
||||
3 195 189 193
|
||||
3 196 189 195
|
||||
3 188 197 194
|
||||
3 196 198 189
|
||||
3 199 197 188
|
||||
3 200 198 196
|
||||
3 201 198 200
|
||||
3 202 198 201
|
||||
3 202 203 198
|
||||
3 204 197 199
|
||||
3 205 203 202
|
||||
3 205 206 203
|
||||
3 207 197 204
|
||||
3 208 206 205
|
||||
3 209 206 208
|
||||
3 209 210 206
|
||||
3 211 197 207
|
||||
3 212 210 209
|
||||
3 213 197 211
|
||||
3 212 214 210
|
||||
3 215 214 212
|
||||
3 216 197 213
|
||||
3 215 217 214
|
||||
3 218 217 215
|
||||
3 219 217 218
|
||||
3 220 217 219
|
||||
3 221 197 216
|
||||
3 220 222 217
|
||||
3 223 222 220
|
||||
3 221 224 197
|
||||
3 225 222 223
|
||||
3 221 226 224
|
||||
3 227 222 225
|
||||
3 221 228 226
|
||||
3 229 222 227
|
||||
3 221 230 228
|
||||
3 231 230 221
|
||||
3 229 232 222
|
||||
3 233 232 229
|
||||
3 231 234 230
|
||||
3 235 232 233
|
||||
3 231 236 234
|
||||
3 237 232 235
|
||||
3 231 238 236
|
||||
3 239 238 231
|
||||
3 237 240 232
|
||||
3 241 240 237
|
||||
3 239 242 238
|
||||
3 243 240 241
|
||||
3 239 244 242
|
||||
3 245 244 239
|
||||
3 243 246 240
|
||||
3 247 246 243
|
||||
3 245 248 244
|
||||
3 249 246 247
|
||||
3 245 250 248
|
||||
3 251 250 245
|
||||
3 249 252 246
|
||||
3 253 252 249
|
||||
3 251 254 250
|
||||
3 255 254 251
|
||||
3 253 256 252
|
||||
3 257 256 253
|
||||
3 255 258 254
|
||||
3 259 258 255
|
||||
3 257 260 256
|
||||
3 261 258 259
|
||||
3 257 262 260
|
||||
3 261 263 258
|
||||
3 264 262 257
|
||||
3 265 263 261
|
||||
3 264 265 262
|
||||
3 264 263 265
|
||||
3 264 266 263
|
||||
3 267 266 264
|
||||
3 267 268 266
|
||||
3 269 268 267
|
||||
3 269 270 268
|
||||
3 271 270 269
|
||||
3 271 272 270
|
||||
3 273 272 271
|
||||
3 273 274 272
|
||||
3 275 274 273
|
||||
3 275 276 274
|
||||
3 277 276 275
|
||||
3 277 278 276
|
||||
3 279 278 277
|
||||
3 279 280 278
|
||||
3 281 280 279
|
||||
3 281 282 280
|
||||
3 283 282 281
|
||||
3 283 284 282
|
||||
3 285 284 283
|
||||
3 286 284 285
|
||||
3 286 287 284
|
||||
3 288 287 286
|
||||
3 288 289 287
|
||||
3 290 289 288
|
||||
3 290 291 289
|
||||
3 292 291 290
|
||||
3 292 293 291
|
||||
3 294 293 292
|
||||
3 294 295 293
|
||||
3 296 295 294
|
||||
3 296 297 295
|
||||
3 298 299 296
|
||||
3 299 297 296
|
||||
3 299 300 297
|
||||
3 300 301 297
|
||||
3 299 302 300
|
||||
3 303 301 300
|
||||
3 298 304 299
|
||||
3 305 302 299
|
||||
3 306 301 303
|
||||
3 298 307 304
|
||||
3 305 308 302
|
||||
3 309 308 305
|
||||
3 310 301 306
|
||||
3 298 311 307
|
||||
3 309 312 308
|
||||
3 313 314 309
|
||||
3 314 312 309
|
||||
3 315 301 310
|
||||
3 298 316 311
|
||||
3 317 316 298
|
||||
3 315 318 301
|
||||
3 313 319 314
|
||||
3 319 320 314
|
||||
3 320 321 314
|
||||
3 321 322 314
|
||||
3 322 323 314
|
||||
3 323 324 314
|
||||
3 324 325 314
|
||||
3 325 326 314
|
||||
3 326 327 314
|
||||
3 327 328 314
|
||||
3 328 329 314
|
||||
3 330 312 314
|
||||
3 331 312 330
|
||||
3 332 312 331
|
||||
3 333 312 332
|
||||
3 334 312 333
|
||||
3 335 312 334
|
||||
3 336 312 335
|
||||
3 337 312 336
|
||||
3 338 312 337
|
||||
3 339 312 338
|
||||
3 340 312 339
|
||||
3 341 322 321
|
||||
3 342 326 325
|
||||
3 343 329 328
|
||||
3 344 318 315
|
||||
3 317 345 316
|
||||
3 343 346 329
|
||||
3 347 346 343
|
||||
3 348 318 344
|
||||
3 317 349 345
|
||||
3 350 349 317
|
||||
3 348 351 318
|
||||
3 347 352 346
|
||||
3 353 352 347
|
||||
3 354 351 348
|
||||
3 350 355 349
|
||||
3 356 351 354
|
||||
3 350 357 355
|
||||
3 358 357 350
|
||||
3 356 359 351
|
||||
3 360 352 353
|
||||
3 360 361 352
|
||||
3 362 359 356
|
||||
3 358 363 357
|
||||
3 363 364 357
|
||||
3 362 365 359
|
||||
3 366 361 360
|
||||
3 366 367 361
|
||||
3 368 367 366
|
||||
3 368 369 367
|
||||
3 370 369 368
|
||||
3 370 371 369
|
||||
3 372 371 370
|
||||
3 372 373 371
|
||||
3 374 373 372
|
||||
3 374 375 373
|
||||
3 376 375 374
|
||||
3 376 377 375
|
||||
3 378 377 376
|
||||
3 378 379 377
|
||||
3 380 379 378
|
||||
3 380 381 379
|
||||
3 382 381 380
|
||||
3 383 381 382
|
||||
3 384 381 383
|
||||
3 385 381 384
|
||||
3 386 381 385
|
||||
3 387 381 386
|
||||
3 388 381 387
|
||||
3 389 381 388
|
||||
3 390 381 389
|
||||
3 391 381 390
|
||||
3 392 381 391
|
||||
@@ -12,6 +12,14 @@ using namespace tinyxml2;
|
||||
|
||||
#include <string>
|
||||
|
||||
XMLElement *tinyxml2::XMLElementFromGLM(XMLDocument *doc, glm::ivec2 vector)
|
||||
{
|
||||
XMLElement *newelement = doc->NewElement( "ivec2" );
|
||||
newelement->SetAttribute("x", vector.x);
|
||||
newelement->SetAttribute("y", vector.y);
|
||||
return newelement;
|
||||
}
|
||||
|
||||
XMLElement *tinyxml2::XMLElementFromGLM(XMLDocument *doc, glm::vec3 vector)
|
||||
{
|
||||
XMLElement *newelement = doc->NewElement( "vec3" );
|
||||
@@ -44,6 +52,13 @@ XMLElement *tinyxml2::XMLElementFromGLM(XMLDocument *doc, glm::mat4 matrix)
|
||||
return newelement;
|
||||
}
|
||||
|
||||
void tinyxml2::XMLElementToGLM(XMLElement *elem, glm::ivec2 &vector)
|
||||
{
|
||||
if ( !elem || std::string(elem->Name()).find("ivec2") == std::string::npos )
|
||||
return;
|
||||
elem->QueryIntAttribute("x", &vector.x); // If this fails, original value is left as-is
|
||||
elem->QueryIntAttribute("y", &vector.y);
|
||||
}
|
||||
|
||||
void tinyxml2::XMLElementToGLM(XMLElement *elem, glm::vec3 &vector)
|
||||
{
|
||||
|
||||
@@ -9,10 +9,12 @@ namespace tinyxml2 {
|
||||
class XMLDocument;
|
||||
class XMLElement;
|
||||
|
||||
XMLElement *XMLElementFromGLM(XMLDocument *doc, glm::ivec2 vector);
|
||||
XMLElement *XMLElementFromGLM(XMLDocument *doc, glm::vec3 vector);
|
||||
XMLElement *XMLElementFromGLM(XMLDocument *doc, glm::vec4 vector);
|
||||
XMLElement *XMLElementFromGLM(XMLDocument *doc, glm::mat4 matrix);
|
||||
|
||||
void XMLElementToGLM(XMLElement *elem, glm::ivec2 &vector);
|
||||
void XMLElementToGLM(XMLElement *elem, glm::vec3 &vector);
|
||||
void XMLElementToGLM(XMLElement *elem, glm::vec4 &vector);
|
||||
void XMLElementToGLM(XMLElement *elem, glm::mat4 &matrix);
|
||||
|
||||
Reference in New Issue
Block a user