Commit 6bb6e5bd authored by OyyoDams's avatar OyyoDams

feat(video): add video snaps

parent 6a7edb3f
FROM ubuntu:16.04
FROM ubuntu:18.04
ARG RB_VERSION=''
RUN apt-get update && apt-get install -y libsdl2-dev libsdl2-mixer-dev libboost-all-dev libfreeimage-dev libfreetype6-dev libeigen3-dev libcurl4-openssl-dev libasound2-dev libgl1-mesa-dev build-essential cmake gettext
RUN apt-get update && apt-get install -y libsdl2-dev libsdl2-mixer-dev libboost-all-dev libfreeimage-dev libfreetype6-dev libeigen3-dev libcurl4-openssl-dev libasound2-dev libgl1-mesa-dev build-essential cmake gettext libavcodec-dev libavdevice-dev libavfilter-dev libavformat-dev libavresample-dev libavutil-dev libswresample-dev libswscale-dev libpostproc-dev
WORKDIR /src
......
......@@ -11,7 +11,7 @@ const std::string MetadataDescriptor::DefaultValueEmpty = "";
const std::string MetadataDescriptor::DefaultValueRating = "0.0";
const std::string MetadataDescriptor::DefaultValuePlayers = "1";
const std::string MetadataDescriptor::DefaultValuePlaycount = "0";
const std::string MetadataDescriptor::DefaultValueUnknown = "unknown";
//const std::string MetadataDescriptor::DefaultValueUnknown = "unknown";
const std::string MetadataDescriptor::DefaultValueFavorite = "false";
const std::string MetadataDescriptor::DefaultValueHidden = "false";
......@@ -44,6 +44,7 @@ const MetadataFieldDescriptor* MetadataDescriptor::GetMetadataFieldDescriptors(I
MetadataFieldDescriptor("desc" , DefaultValueEmpty , _("Description") , _("enter description") , (int)offsetof(MetadataDescriptor, _Description), MetadataFieldDescriptor::DataType::Text , &MetadataDescriptor::IsDefaultDescription , &MetadataDescriptor::DescriptionAsString , &MetadataDescriptor::SetDescription , false, false),
MetadataFieldDescriptor("image" , DefaultValueEmpty , _("Image") , _("enter path to image") , (int)offsetof(MetadataDescriptor, _Image) , MetadataFieldDescriptor::DataType::Path , &MetadataDescriptor::IsDefaultImage , &MetadataDescriptor::ImageAsString , &MetadataDescriptor::SetImagePath , false, false),
MetadataFieldDescriptor("thumbnail" , DefaultValueEmpty , _("Thumbnail") , _("enter path to thumbnail") , (int)offsetof(MetadataDescriptor, _Thumbnail) , MetadataFieldDescriptor::DataType::PPath , &MetadataDescriptor::IsDefaultThumbnail , &MetadataDescriptor::ThumbnailAsString , &MetadataDescriptor::SetThumbnailPath , false, false),
MetadataFieldDescriptor("video" , DefaultValueEmpty , _("Video") , _("enter path to video") , (int)offsetof(MetadataDescriptor, _Video) , MetadataFieldDescriptor::DataType::PPath , &MetadataDescriptor::IsDefaultVideo , &MetadataDescriptor::VideoAsString , &MetadataDescriptor::SetVideoPath , false, false),
MetadataFieldDescriptor("releasedate", DefaultValueEmpty , _("Release date"), _("enter release date") , (int)offsetof(MetadataDescriptor, _ReleaseDate), MetadataFieldDescriptor::DataType::Date , &MetadataDescriptor::IsDefaultReleaseDateEpoc, &MetadataDescriptor::ReleaseDateAsString , &MetadataDescriptor::SetReleaseDateAsString , false, false),
MetadataFieldDescriptor("developer" , DefaultValueEmpty , _("Developer") , _("enter game developer") , (int)offsetof(MetadataDescriptor, _Developer) , MetadataFieldDescriptor::DataType::String , &MetadataDescriptor::IsDefaultDeveloper , &MetadataDescriptor::DeveloperAsString , &MetadataDescriptor::SetDeveloper , false, false),
MetadataFieldDescriptor("publisher" , DefaultValueEmpty , _("Publisher") , _("enter game publisher") , (int)offsetof(MetadataDescriptor, _Publisher) , MetadataFieldDescriptor::DataType::String , &MetadataDescriptor::IsDefaultPublisher , &MetadataDescriptor::PublisherAsString , &MetadataDescriptor::SetPublisher , false, false),
......
......@@ -30,7 +30,7 @@ class MetadataDescriptor
static const std::string DefaultValueRating;
static const std::string DefaultValuePlayers;
static const std::string DefaultValuePlaycount;
static const std::string DefaultValueUnknown;
//static const std::string DefaultValueUnknown;
static const std::string DefaultValueFavorite;
static const std::string DefaultValueHidden;
......@@ -50,6 +50,7 @@ class MetadataDescriptor
std::string* _Core; //!< Specific core
std::string* _Ratio; //!< Specific screen ratio
std::string* _Thumbnail; //!< Thumbnail path
std::string* _Video; //!< Video path
std::string* _Region; //!< Rom/Game Region
float _Rating; //!< Rating from 0.0 to 1.0
int _Players; //!< Players range: LSW:from - MSW:to (allow sorting by max players)
......@@ -198,6 +199,7 @@ class MetadataDescriptor
_Core(nullptr),
_Ratio(nullptr),
_Thumbnail(nullptr),
_Video(nullptr),
_Region(nullptr),
_Rating(0.0f),
_Players((1<<16)+1),
......@@ -232,6 +234,7 @@ class MetadataDescriptor
_Core (source._Core ),
_Ratio (source._Ratio ),
_Thumbnail (source._Thumbnail ),
_Video (source._Video ),
_Region (source._Region ),
_Rating (source._Rating ),
_Players (source._Players ),
......@@ -266,6 +269,7 @@ class MetadataDescriptor
_Core ( source._Core ),
_Ratio ( source._Ratio ),
_Thumbnail ( source._Thumbnail ),
_Video ( source._Video ),
_Region ( source._Region ),
_Rating ( source._Rating ),
_Players ( source._Players ),
......@@ -314,6 +318,7 @@ class MetadataDescriptor
if (source._Core != nullptr) _Core = new std::string(*source._Core );
if (source._Ratio != nullptr) _Ratio = new std::string(*source._Ratio );
if (source._Thumbnail != nullptr) _Thumbnail = new std::string(*source._Thumbnail);
if (source._Video != nullptr) _Video = new std::string(*source._Video );
if (source._Region != nullptr) _Region = new std::string(*source._Region );
_Rating = source._Rating ;
_Players = source._Players ;
......@@ -353,6 +358,7 @@ class MetadataDescriptor
_Description = std::move(source._Description);
_Image = std::move(source._Image );
_Thumbnail = source._Thumbnail ; source._Thumbnail = nullptr;
_Video = source._Video ; source._Video = nullptr;
_Developer = std::move(source._Developer );
_Publisher = std::move(source._Publisher );
_Genre = std::move(source._Genre );
......@@ -412,6 +418,7 @@ class MetadataDescriptor
const std::string& Description() const { return _Description; }
const std::string& Image() const { return _Image; }
const std::string& Thumbnail() const { return ReadPString(_Thumbnail, DefaultValueEmpty); }
const std::string& Video() const { return ReadPString(_Video, DefaultValueEmpty); }
const std::string& Developer() const { return _Developer; }
const std::string& Publisher() const { return _Publisher; }
const std::string& Genre() const { return _Genre; }
......@@ -441,6 +448,7 @@ class MetadataDescriptor
std::string DescriptionAsString() const { return _Description; }
std::string ImageAsString() const { return _Image; }
std::string ThumbnailAsString() const { return ReadPString(_Thumbnail, DefaultValueEmpty); }
std::string VideoAsString() const { return ReadPString(_Video, DefaultValueEmpty); }
std::string DeveloperAsString() const { return _Developer; }
std::string PublisherAsString() const { return _Publisher; }
std::string GenreAsString() const { return _Genre; }
......@@ -466,6 +474,7 @@ class MetadataDescriptor
void SetDescription(const std::string& description) { _Description = description; _Dirty = true; }
void SetImagePath(const std::string& image) { _Image = image; _Dirty = true; }
void SetThumbnailPath(const std::string& thumbnail) { AssignPString(_Thumbnail, thumbnail); _Dirty = true; }
void SetVideoPath(const std::string& video) { AssignPString(_Video, video); _Dirty = true; }
void SetReleaseDate(const DateTime& releasedate) { _ReleaseDate = (int)releasedate.ToEpochTime(); _Dirty = true; }
void SetDeveloper(const std::string& developer) { _Developer = developer; _Dirty = true; }
void SetPublisher(const std::string& publisher) { _Publisher = publisher; _Dirty = true; }
......@@ -518,6 +527,7 @@ class MetadataDescriptor
bool IsDefaultDescription() const { return _Default._Description == _Description; }
bool IsDefaultImage() const { return _Default._Image == _Image; }
bool IsDefaultThumbnail() const { return _Default.Thumbnail() == Thumbnail(); }
bool IsDefaultVideo() const { return _Default.Video() == Video(); }
bool IsDefaultDeveloper() const { return _Default._Developer == _Developer; }
bool IsDefaultPublisher() const { return _Default._Publisher == _Publisher; }
bool IsDefaultGenre() const { return _Default._Genre == _Genre; }
......
......@@ -12,6 +12,7 @@
#include <RecalboxConf.h>
#include <RootFolders.h>
#include <recalbox/RecalboxSystem.h>
#include <VideoEngine.h>
std::vector<SystemData *> SystemData::sSystemVector;
......@@ -164,6 +165,7 @@ void SystemData::launchGame(Window* window, FileData* game, const std::string& n
LOG(LogInfo) << "Attempting to launch game...";
VideoEngine::This().StopVideo();
AudioManager::getInstance()->deinit();
VolumeControl::getInstance()->deinit();
......@@ -239,6 +241,7 @@ std::string SystemData::demoInitialize(Window& window)
std::string controlersConfig = InputManager::getInstance()->configureEmulators();
LOG(LogInfo) << "Controllers config : " << controlersConfig;
VideoEngine::This().StopVideo();
AudioManager::getInstance()->deinit();
VolumeControl::getInstance()->deinit();
......@@ -343,7 +346,10 @@ SystemData *createSystem(const SystemData::Tree &system)
name = system.get("name", "");
fullname = system.get("fullname", "");
path = system.get("path", "");
//#ifdef DEBUG
//strFindAndReplace(path, "roms", "romstest");
//#endif
// convert extensions list from a string into a vector of strings
std::string extensions = system.get("extension", "");
......
......@@ -10,6 +10,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <RootFolders.h>
#include <VideoEngine.h>
#include "AudioManager.h"
#include "CommandThread.h"
......@@ -400,6 +401,9 @@ int main(int argc, char* argv[])
// Start the socket server
CommandThread commandThread(&window);
// Starts Video engine
VideoEngine::This().StartEngine();
// Allocate custom event types
unsigned int NetPlayPopupEvent = SDL_RegisterEvents(2);
unsigned int MusicStartEvent = NetPlayPopupEvent + 1;
......
......@@ -23,6 +23,7 @@
#include <boost/algorithm/string/replace.hpp>
#include <fstream>
#include <Locale.h>
#include <VideoEngine.h>
RecalboxSystem::RecalboxSystem() {
......@@ -53,6 +54,7 @@ void RecalboxSystem::NotifySystemAndGame(const SystemData* system, const FileDat
fwrite(output.c_str(), output.size(), 1, f);
fclose(f);
}
VideoEngine::This().StopVideo();
}
......
......@@ -42,7 +42,7 @@ DetailedGameListView::DetailedGameListView(Window* window, FolderData* root, Sys
// folder components
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
ImageComponent *img = new ImageComponent(window);
auto *img = new ImageComponent(window);
addChild(img); // normalised functions required to be added first
img->setOrigin(0.5f, 0.5f);
img->setNormalisedMaxSize(0.4f, 0.4f);
......@@ -370,6 +370,8 @@ void DetailedGameListView::setGameInfo(FileData* file)
mFavorite.setValue(file->Metadata().FavoriteAsString());
mImage.setImage(file->Metadata().Image());
mImage.setVideo(file->Metadata().Video());
mImage.ResetAnimations();
mDescription.setText(file->Metadata().Description());
mDescContainer.reset();
}
......
......@@ -4,6 +4,7 @@
#include "components/ScrollableContainer.h"
#include "components/RatingComponent.h"
#include "components/DateTimeComponent.h"
#include "components/ImageVideoComponent.h"
#include "SystemData.h"
class DetailedGameListView : public BasicGameListView
......@@ -24,7 +25,7 @@ private:
void initMDLabels();
void initMDValues();
ImageComponent mImage;
ImageVideoComponent mImage;
std::vector<ImageComponent *> mFolderContent;
TextComponent mLblRating, mLblReleaseDate, mLblDeveloper, mLblPublisher, mLblGenre, mLblPlayers, mLblLastPlayed, mLblPlayCount, mLblFavorite;
......
......@@ -22,8 +22,14 @@ set(CORE_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/RootFolders.h
${CMAKE_CURRENT_SOURCE_DIR}/src/MenuThemeData.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Util.h
${CMAKE_CURRENT_SOURCE_DIR}/src/VideoEngine.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.h
# Utils
${CMAKE_CURRENT_SOURCE_DIR}/src/util/Thread.h
${CMAKE_CURRENT_SOURCE_DIR}/src/util/Mutex.h
${CMAKE_CURRENT_SOURCE_DIR}/src/util/HighResolutionTimer.h
# Animations
${CMAKE_CURRENT_SOURCE_DIR}/src/animations/Animation.h
${CMAKE_CURRENT_SOURCE_DIR}/src/animations/AnimationController.h
......@@ -39,6 +45,7 @@ set(CORE_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/components/HelpComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/IList.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageVideoComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageGridComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/MenuComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/NinePatchComponent.h
......@@ -95,8 +102,13 @@ set(CORE_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/RootFolders.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/MenuThemeData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Util.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/VideoEngine.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.cpp
# Utils
${CMAKE_CURRENT_SOURCE_DIR}/src/util/Thread.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/util/Mutex.cpp
# Animations
${CMAKE_CURRENT_SOURCE_DIR}/src/animations/AnimationController.cpp
......@@ -109,6 +121,7 @@ set(CORE_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/components/DateTimeComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/HelpComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageVideoComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/MenuComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/NinePatchComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollableContainer.cpp
......@@ -195,6 +208,9 @@ set(EMBEDDED_ASSET_SOURCES
list(APPEND CORE_SOURCES ${EMBEDDED_ASSET_SOURCES})
set(FFMPEGLIBS avcodec avformat swresample avutil swscale avdevice)
include_directories(${COMMON_INCLUDE_DIRS})
add_library(es-core STATIC ${CORE_SOURCES} ${CORE_HEADERS} src/RecalboxConf.cpp src/RecalboxConf.h)
target_link_libraries(es-core ${COMMON_LIBRARIES})
target_link_libraries(es-core ${COMMON_LIBRARIES} ${FFMPEGLIBS})
This diff is collapsed.
//
// Created by bkg2k on 14/05/19.
//
#pragma once
#include <string>
#include <util/Thread.h>
#include <util/Mutex.h>
#include <SDL_system.h>
#include <resources/TextureData.h>
extern "C"
{
#include <libavfilter/avfilter.h> // libavfilter-dev
#include <libavformat/avformat.h> // libavformat-dev
#include <libavcodec/avcodec.h> // libavformat-dev
#include <libavdevice/avdevice.h> // libavdevice-dev
#include <libavutil/imgutils.h> // libavutil-dev
#include <libswresample/swresample.h> // libavformat-dev
#include <libswscale/swscale.h> // libavfilter-dev
}
class VideoEngine : Thread
{
public:
/*!
* @brief Curren tplayer state
*/
enum class PlayerState
{
Idle, // Do nothing, sleep
StartPending, // Initializing the video
Playing, // Currently playing
Paused, // Pause flag
StopPending, // Currently playing but must stop asap and return idle
};
private:
/*!
* @brief Small packet queue
*/
class AudioPacketQueue
{
private:
Mutex mMutex;
//! First paquet
AVPacketList* First;
//! Last paquet
AVPacketList* Last;
//! Packet count
int Count;
//! Packet size
int Size;
public:
/*!
* @brief Constructor
*/
AudioPacketQueue()
{
First = Last = nullptr;
Count = Size = 0;
}
void Reset()
{
AVPacket packet;
while(Dequeue(packet));
First = Last = nullptr;
Count = Size = 0;
}
/*!
* @brief Enqueue a new packet
* @param packet packet to enqueue
*/
void Enqueue(const AVPacket* packet);
/*!
* @brief Dequeue a packet or return nullptr of the queue is empty.
* This call is non blocking
* @param packet packet to dequeue
* @return True if the packet is valid
*/
bool Dequeue(AVPacket& pkt);
};
/*!
* @brief Internal context, all embedded in a POD object
*/
class PlayerContext
{
public:
//! Global audio/video context
AVFormatContext* AudioVideoContext;
//! Index of the first audio stream available in the file
int AudioStreamIndex;
//! Index of the first video stream available in the file
int VideoStreamIndex;
//! Audio codec
AVCodec* AudioCodec;
//! Video codec
AVCodec* VideoCodec;
//! Audio codec context
AVCodecContext* AudioCodecContext;
//! Video codec context
AVCodecContext* VideoCodecContext;
//! Rescaler context
SwrContext* ResamplerContext;
//! Color Space context
SwsContext* ColorsSpaceContext;
//! Audio packets
AudioPacketQueue AudioQueue;
//! Frame buffer
unsigned char* FrameBuffer;
//! Source video Frame in native pixel format
AVFrame* Frame;
//! Video Frame transcode to RGB
AVFrame* FrameRGB[2];
//! RGB frame access locker
Mutex FrammeRGBLocker[2];
//! Buffer in use by the decoder (0/1)
unsigned int FrameInUse;
//! Video width in pixel
int Width;
//!Video height in pixel
int Height;
//! Frame time in Nano-seconds
long long FrameTime;
//! Video duration in milliseconds
int TotalTime;
PlayerContext()
{
Reset();
}
void Reset()
{
AudioVideoContext = nullptr;
AudioCodec = VideoCodec = nullptr;
AudioCodecContext = VideoCodecContext = nullptr;
ResamplerContext = nullptr;
ColorsSpaceContext = nullptr;
AudioStreamIndex = VideoStreamIndex = -1;
FrameBuffer = nullptr;
Frame = FrameRGB[0] = FrameRGB[1] = nullptr;
Width = Height = 0;
FrameInUse = 0;
FrameTime = 0;
AudioQueue.Reset();
}
};
private:
//! Signal used to unlock the thread and actually run the video decoding
Mutex mSignal;
//! Video filename
std::string mFileName;
//! Video playing state
volatile PlayerState mState;
//! Global context
PlayerContext mContext;
//! Textures to render
TextureData mTexture;
static constexpr int SDL_AUDIO_BUFFER_SIZE = 4096;
private:
/*!
* Thread main loop
*/
void Run() override;
/*!
* @brief Unlock the thread on exit
*/
void Break() override
{
mSignal.Signal();
}
static void AudioCallback(void *userdata, unsigned char* stream, int len)
{
((VideoEngine*)userdata)->DecodeAudioFrameOnDemand(stream, len);
}
bool InitializeDecoder();
void DecodeAudioFrameOnDemand(unsigned char * stream, int len);
int DecodeAudioFrame(AVCodecContext& audioContext, unsigned char* buffer, int size);
void DecodeFrames();
void FinalizeDecoder();
/*!
* @brief Default constructor
*/
VideoEngine();
public:
/*!
* @brief Destructor
*/
~VideoEngine() override { Thread::Stop(); }
/*!
* @brief Start playing a video file
* If a video is already playing, a call to stop is performed playing the new video
* @param videopath Path to the video file ot play
*/
void PlayVideo(const std::string& videopath);
/*!
* @brief Stop the currently playing video file.
* Does nothing if no file is actually playing
*/
void StopVideo(bool waitforstop = false);
/*!
* @brief Get current image of the current playing video
* This must be called fr
* @return TextureData containing last image
*/
TextureData& GetDisplayableFrame();
/*!
* @brief Get Instance
* @return Instance
*/
static VideoEngine& This();
/*!
* @brief Return true if the player is actually playing a video
* @return True if a video is playing, false otherwise
*/
bool IsPlaying() { return ((mState == PlayerState::Playing) || (mState == PlayerState::StopPending)); }
/*!
* @brief Return true if the engine is in idle state
* @return True if in idle state, false otherwise
*/
bool IsIdle() { return (mState == PlayerState::Idle); }
int GetVideoDurationMs() { return IsPlaying() ? mContext.TotalTime : 0; }
/*!
* @brief Start the video engine. After calling this method, the player is ready to play video
*/
void StartEngine() { Thread::Start("VideoEngine"); }
/*!
* Pause the engine if it's actually playing a video. Otherwise do nothing.
*/
void PauseEngine() { if (mState == PlayerState::Playing) mState = PlayerState::Paused; }
/*!
* Resume the engine if it's actually paused. Otherwise do nothing.
*/
void ResumeEngine() { if (mState == PlayerState::Paused) mState = PlayerState::Playing; }
};
This diff is collapsed.
//
// Created by bkg2k on 16/05/19.
//
#pragma once
#include "platform.h"
#include "platform_gl.h"
#include "GuiComponent.h"
#include <string>
#include <memory>
#include <util/HighResolutionTimer.h>
#include "resources/TextureResource.h"
class ImageVideoComponent : public GuiComponent
{
private:
enum State
{
DisplayImage,
InitializeVideo,
BumpVideo,
DisplayVideo,
FinalizeVideo,
};
State mState;
Eigen::Vector2f mTargetSize;
std::string mPath;
std::string mVideoPath;
bool mTargetIsMax;
// Calculates the correct mSize from our resizing information (set by setResize/setMaxSize).
// Used internally whenever the resizing parameters or texture change.
void resize();
typedef struct Vertex
{
Eigen::Vector2f pos;
Eigen::Vector2f tex;
} RectangleVertexes[6];
RectangleVertexes mVertices;
GLubyte mColors[6*4];
void updateVertices();
void updateColors();
unsigned int mColorShift;
std::shared_ptr<TextureResource> mTexture;
unsigned char mFadeOpacity;
bool mFading;
bool mDynamic;
HighResolutionTimer mTimer;
static constexpr int IMAGE_TIMING = 5000;
static constexpr int IMAGE_TO_VIDEO_TIMING = 500;
/*!
* @brief Decide what to display
* @param video [out] Set if we must display the video
* @param image [out] Set if we must display the image
* @param bumpEffect [out] Set to the video bump value
*/
void ProcessDisplay(bool& video, bool&image, double& bumpEffect);
/*!
* @brief Calculate new bumped vertexes
* @param bump
*/
void CalculateVideoVextexes(RectangleVertexes& destinationVertexes, double bump);
public:
explicit ImageVideoComponent(Window* window, bool dynamic = true);
~ImageVideoComponent() override;
// Loads the image at the given filepath. Will tile if tile is true (retrieves texture as tiling, creates vertices accordingly).
void setImage(const std::string& path, bool tile = false);
// Loads an image from memory.
void setImage(const char* image, size_t length, bool tile = false);
// Use an already existing texture.
void setImage(const std::shared_ptr<TextureResource>& texture);
// Set video file path
void setVideo(const std::string& path);
void onSizeChanged() override;
void setOpacity(unsigned char opacity) override;
Eigen::Vector2f getTargetSize() const { return mTargetSize; }
// Resize the image to fit this size. If one axis is zero, scale that axis to maintain aspect ratio.
// If both are non-zero, potentially break the aspect ratio. If both are zero, no resizing.
// Can be set before or after an image is loaded.
// setMaxSize() and setResize() are mutually exclusive.
void setResize(float width, float height);
inline void setResize(const Eigen::Vector2f& size) { setResize(size.x(), size.y()); }
// Resize the image to be as large as possible but fit within a box of this size.
// Can be set before or after an image is loaded.
// Never breaks the aspect ratio. setMaxSize() and setResize() are mutually exclusive.
void setMaxSize(float width, float height);
void setNormalisedMaxSize(float width, float height);
inline void setMaxSize(const Eigen::Vector2f& size) { setMaxSize(size.x(), size.y()); }
// Multiply all pixels in the image by this color when rendering.
void setColorShift(unsigned int color);
void setColor(unsigned int color) override;
// Returns the size of the current texture, or (0, 0) if none is loaded. May be different than drawn size (use getSize() for that).
Eigen::Vector2i getTextureSize() const;
bool hasImage();
void render(const Eigen::Affine3f& parentTrans) override;
void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
std::vector<HelpPrompt> getHelpPrompts() override;
void ResetAnimations();
};
......@@ -10,6 +10,19 @@
#define DPI 96
TextureData::TextureData()
: mTile(false),
mTextureID(0),
mDataRGBA(nullptr),
mWidth(0),
mHeight(0),
mSourceWidth(0.0f),
mSourceHeight(0.0f),
mScalable(false),
mSVGImage(nullptr)
{
}
TextureData::TextureData(bool tile)
: mTile(tile),
mTextureID(0),
......@@ -25,11 +38,19 @@ TextureData::TextureData(bool tile)
TextureData::~TextureData()
{
releaseVRAM();
releaseRAM();
if (mSVGImage)
nsvgDelete(mSVGImage);
mSVGImage = nullptr;
reset();
}
void TextureData::reset()
{
releaseVRAM();
releaseRAM();
if (mSVGImage)
nsvgDelete(mSVGImage);
mWidth = mHeight = 0;
mDataRGBA = nullptr;
mSVGImage = nullptr;