Skip to content

Commit ba5e236

Browse files
committed
Add expression variable watch helper and associated internal functions
1 parent 0c1aa9e commit ba5e236

8 files changed

Lines changed: 302 additions & 10 deletions

File tree

src/libprojectM/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ add_subdirectory(UserSprites)
1313

1414
add_library(projectM_main OBJECT
1515
"${PROJECTM_EXPORT_HEADER}"
16+
ExpressionVariableWatcher.cpp
17+
ExpressionVariableWatcher.hpp
1618
Logging.cpp
1719
Logging.hpp
1820
Preset.hpp
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#include "ExpressionVariableWatcher.hpp"
2+
3+
#include "Utils.hpp"
4+
5+
#include <projectM-4/debug.h>
6+
7+
#include <cstdint>
8+
#include <string>
9+
#include <utility>
10+
11+
namespace libprojectM {
12+
13+
auto ExpressionVariableWatcher::Add(ExpressionBlocks block, uint32_t index, VariableName variableName) -> const ExpressionVariableWatcher::VariableValues*
14+
{
15+
// Validate block value only, set index to 0 in blocks only occurring once.
16+
switch (block)
17+
{
18+
case PROJECTM_EXPR_PER_FRAME:
19+
case PROJECTM_EXPR_PER_POINT:
20+
index = 0;
21+
22+
case PROJECTM_EXPR_SHAPE_PER_FRAME:
23+
case PROJECTM_EXPR_WAVE_PER_FRAME:
24+
case PROJECTM_EXPR_WAVE_PER_POINT:
25+
case PROJECTM_EXPR_MILKDROP_SPRITE:
26+
break;
27+
28+
default:
29+
return nullptr;
30+
}
31+
32+
libprojectM::Utils::ToLowerInPlace(variableName);
33+
34+
IndexedExpressionBlock const indexedBlock = std::make_pair(block, index);
35+
36+
auto blockInMap = m_watches.find(indexedBlock);
37+
if (blockInMap == m_watches.end())
38+
{
39+
blockInMap = m_watches.insert({indexedBlock, {}}).first;
40+
}
41+
42+
// If the watch was already registered with the given, return the existing pointer again.
43+
auto variableWatch = blockInMap->second.find(variableName);
44+
if (variableWatch != blockInMap->second.end())
45+
{
46+
return &variableWatch->second;
47+
}
48+
49+
// New watch. Create a new value struct and return it.
50+
return &blockInMap->second.insert({variableName, {}}).first->second;
51+
}
52+
53+
auto ExpressionVariableWatcher::Remove(ExpressionBlocks block, uint32_t index, VariableName variableName) -> const ExpressionVariableWatcher::VariableValues*
54+
{
55+
// Validate block value only, set index to 0 in blocks only occurring once.
56+
switch (block)
57+
{
58+
case PROJECTM_EXPR_PER_FRAME:
59+
case PROJECTM_EXPR_PER_POINT:
60+
index = 0;
61+
62+
case PROJECTM_EXPR_SHAPE_PER_FRAME:
63+
case PROJECTM_EXPR_WAVE_PER_FRAME:
64+
case PROJECTM_EXPR_WAVE_PER_POINT:
65+
case PROJECTM_EXPR_MILKDROP_SPRITE:
66+
break;
67+
68+
default:
69+
return nullptr;
70+
}
71+
72+
libprojectM::Utils::ToLowerInPlace(variableName);
73+
74+
IndexedExpressionBlock const indexedBlock = std::make_pair(block, index);
75+
76+
auto blockInMap = m_watches.find(indexedBlock);
77+
if (blockInMap == m_watches.end())
78+
{
79+
return nullptr;
80+
}
81+
82+
auto variableWatch = blockInMap->second.find(variableName);
83+
if (variableWatch == blockInMap->second.end())
84+
{
85+
return nullptr;
86+
}
87+
88+
// Watch found, make a copy of the values struct pointer, then delete it.
89+
const auto* oldValuesStruct = &variableWatch->second;
90+
91+
blockInMap->second.erase(variableWatch);
92+
93+
return oldValuesStruct;
94+
}
95+
96+
void ExpressionVariableWatcher::Clear()
97+
{
98+
m_watches.clear();
99+
}
100+
101+
auto ExpressionVariableWatcher::GetBlockWatches(ExpressionBlocks block, uint32_t index) -> BlockWatches&
102+
{
103+
// Validate block value only.
104+
switch (block)
105+
{
106+
case PROJECTM_EXPR_PER_FRAME:
107+
case PROJECTM_EXPR_PER_POINT:
108+
case PROJECTM_EXPR_SHAPE_PER_FRAME:
109+
case PROJECTM_EXPR_WAVE_PER_FRAME:
110+
case PROJECTM_EXPR_WAVE_PER_POINT:
111+
case PROJECTM_EXPR_MILKDROP_SPRITE:
112+
break;
113+
114+
default:
115+
throw InvalidBlockException("Block type " + std::to_string(block) + " is not supported!");
116+
}
117+
118+
IndexedExpressionBlock const indexedBlock = std::make_pair(block, index);
119+
120+
auto blockInMap = m_watches.find(indexedBlock);
121+
if (blockInMap == m_watches.end())
122+
{
123+
blockInMap = m_watches.insert({indexedBlock, {}}).first;
124+
}
125+
126+
return blockInMap->second;
127+
}
128+
129+
} // namespace libprojectM
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* projectM -- Milkdrop-esque visualisation SDK
3+
* Copyright (C)2003-2007 projectM Team
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 2.1 of the License, or (at your option) any later version.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+
* See 'LICENSE.txt' included within this release
19+
*
20+
*/
21+
#pragma once
22+
23+
#include <projectM-4/debug.h>
24+
25+
#include <cstdint>
26+
#include <exception>
27+
#include <map>
28+
#include <string>
29+
#include <utility>
30+
31+
namespace libprojectM {
32+
33+
/**
34+
* @class ExpressionVariableWatcher
35+
* @brief Container class managing active expression variable watches.
36+
*
37+
* All watches are stored in a three-tiered map, with the first map using the block and index as key.
38+
* The second level map associated each watched variable to the struct which will receive the
39+
* values. This struct and is also used by the outside application to display or otherwise evaluate
40+
* the values after a frame is rendered.
41+
*/
42+
class ExpressionVariableWatcher
43+
{
44+
public:
45+
/**
46+
* @brief Exception for an invalid block argument in GetBlockWatches().
47+
*/
48+
class InvalidBlockException : public std::exception
49+
{
50+
public:
51+
InvalidBlockException(std::string message)
52+
: m_message(std::move(message))
53+
{
54+
}
55+
56+
~InvalidBlockException() override = default;
57+
58+
auto what() const noexcept -> const char* override
59+
{
60+
return m_message.c_str();
61+
}
62+
63+
auto message() const -> const std::string&
64+
{
65+
return m_message;
66+
}
67+
68+
private:
69+
std::string m_message;
70+
};
71+
72+
using ExpressionBlocks = projectm_expression_blocks; //!< Alias for the projectm_expression_blocks public API enum.
73+
using IndexedExpressionBlock = std::pair<ExpressionBlocks, uint32_t>; //!< A pair if ExpressionBlocks and the custom shape/waveform or sprite index.
74+
using VariableName = std::string; //!< the name of a watched variable, lower-case.
75+
using VariableValues = projectm_expression_variable_values; //!< Alias for the projectm_expression_variable_values public API struct.
76+
using BlockWatches = std::map<VariableName, VariableValues>; //!< A map of variable names to the associated value structs.
77+
78+
/**
79+
* @brief Adds a new watch, or returns a pointer to the previously registered one.
80+
* @param block The expression code block to add the watch for.
81+
* @param index The custom shape/waveform or user sprite index.
82+
* @param variableName The variable to watch.
83+
* @return A pointer to the newly added values struct, if the watch was successfully added.
84+
*/
85+
auto Add(ExpressionBlocks block, uint32_t index, VariableName variableName) -> const VariableValues*;
86+
87+
/**
88+
* @brief Removes a previously registered variable watch.
89+
* @param block The expression code block to remove the watch from.
90+
* @param index The custom shape/waveform or user sprite index.
91+
* @param variableName The variable to unwatch.
92+
* @return If the previous watch was found, a pointer to the initially registered values struct,
93+
* or nullptr if no watch was found.
94+
*/
95+
auto Remove(ExpressionBlocks block, uint32_t index, VariableName variableName) -> const VariableValues*;
96+
97+
/**
98+
* Clears all previously registered watches.
99+
*/
100+
void Clear();
101+
102+
/**
103+
* @brief Returns all watched variables and their value structs for the given block and index.
104+
* @throws InvalidBlockException Thrown if the passed block value is invalid.
105+
* @param block The expression code block to return the watch list for.
106+
* @param index The custom shape/waveform or user sprite index to return the watch list for.
107+
* @return A reference to a map of type BlockWatches with all registered watched variables.
108+
*/
109+
auto GetBlockWatches(ExpressionBlocks block, uint32_t index) -> BlockWatches&;
110+
111+
private:
112+
/**
113+
* @brief Registered watches.
114+
*
115+
* A three-tiered map of indexed blocks, variables and the value struct returned to the application.
116+
*/
117+
std::map<IndexedExpressionBlock, BlockWatches> m_watches;
118+
};
119+
120+
} // namespace libprojectM

src/libprojectM/MilkdropPreset/MilkdropPreset.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,14 @@ void MilkdropPreset::BindFramebuffer()
187187
}
188188
}
189189

190+
void MilkdropPreset::UpdateWatches(ExpressionVariableWatcher& watcher)
191+
{
192+
}
193+
194+
void MilkdropPreset::RemoveWatches()
195+
{
196+
}
197+
190198
void MilkdropPreset::PerFrameUpdate()
191199
{
192200
m_perFrameContext.LoadStateVariables(m_state);
@@ -227,7 +235,7 @@ void MilkdropPreset::Load(std::istream& stream)
227235

228236
if (!parser.Read(stream))
229237
{
230-
const std::string error = "[MilkdropPreset] Could not parse preset data.";
238+
const std::string error = "[MilkdropPreset] Could not parse preset data.";
231239
LOG_ERROR(error)
232240
throw MilkdropPresetLoadException(error);
233241
}

src/libprojectM/MilkdropPreset/MilkdropPreset.hpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#pragma once
2525

2626
#include "Border.hpp"
27+
#include "Constants.hpp"
2728
#include "CustomShape.hpp"
2829
#include "CustomWaveform.hpp"
2930
#include "DarkenCenter.hpp"
@@ -32,37 +33,42 @@
3233
#include "PerFrameContext.hpp"
3334
#include "PerPixelContext.hpp"
3435
#include "PerPixelMesh.hpp"
35-
#include "Preset.hpp"
3636
#include "Waveform.hpp"
3737

38+
#include <ExpressionVariableWatcher.hpp>
39+
#include <Preset.hpp>
40+
41+
#include <Audio/FrameAudioData.hpp>
42+
3843
#include <Renderer/CopyTexture.hpp>
3944
#include <Renderer/Framebuffer.hpp>
45+
#include <Renderer/RenderContext.hpp>
46+
#include <Renderer/Texture.hpp>
47+
#include <Renderer/TextureAttachment.hpp>
4048

49+
#include <array>
50+
#include <istream>
4151
#include <memory>
4252
#include <string>
4353

4454
namespace libprojectM {
45-
class PresetFileParser;
46-
4755
namespace MilkdropPreset {
4856

4957
class Factory;
5058

51-
class MilkdropPreset : public ::libprojectM::Preset
59+
class MilkdropPreset : public Preset
5260
{
5361

5462
public:
5563
/**
5664
* @brief LoadCode a MilkdropPreset by filename with input and output buffers specified.
57-
* @param factory The factory class that created this preset instance.
5865
* @param absoluteFilePath the absolute file path of a MilkdropPreset to load from the file system
5966
*/
6067
MilkdropPreset(const std::string& absoluteFilePath);
6168

6269
/**
6370
* @brief LoadCode a MilkdropPreset from an input stream with input and output buffers specified.
6471
* @param presetData an already initialized input stream to read the MilkdropPreset file from
65-
* @param presetOutputs initialized and filled with data parsed from a MilkdropPreset
6672
*/
6773
MilkdropPreset(std::istream& presetData);
6874

@@ -77,7 +83,7 @@ class MilkdropPreset : public ::libprojectM::Preset
7783
* @param audioData The frame audio data.
7884
* @param renderContext The current rendering context/information.
7985
*/
80-
void RenderFrame(const libprojectM::Audio::FrameAudioData& audioData,
86+
void RenderFrame(const Audio::FrameAudioData& audioData,
8187
const Renderer::RenderContext& renderContext) override;
8288

8389
auto OutputTexture() const -> std::shared_ptr<Renderer::Texture> override;
@@ -86,6 +92,10 @@ class MilkdropPreset : public ::libprojectM::Preset
8692

8793
void BindFramebuffer() override;
8894

95+
void UpdateWatches(ExpressionVariableWatcher& watcher) override;
96+
97+
void RemoveWatches() override;
98+
8999
private:
90100
void PerFrameUpdate();
91101

0 commit comments

Comments
 (0)