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:
brunoherbelin
2020-09-20 00:26:39 +02:00
parent db6d3a6fa0
commit 59db2cf57c
31 changed files with 2199 additions and 48 deletions

View File

@@ -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)

View File

@@ -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_];

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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_;

View File

@@ -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_);
}
}

View File

@@ -3,6 +3,8 @@
#include "Source.h"
class MediaPlayer;
class MediaSource : public Source
{
public:

View File

@@ -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;

View File

@@ -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
View 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
View 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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
};

View File

@@ -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) {

View File

@@ -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;

View File

@@ -13,7 +13,6 @@ class ImageShader;
class ImageProcessingShader;
class FrameBuffer;
class FrameBufferSurface;
class MediaPlayer;
class Surface;
class Session;
class Frame;

View File

@@ -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
View File

@@ -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

View File

@@ -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);

View File

@@ -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_;

View File

@@ -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&) {}

View File

@@ -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
View 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

View File

@@ -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)
{

View File

@@ -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);