Files
projectm/src/libprojectM/MilkdropPreset/ShapePerFrameContext.cpp
2025-12-07 17:24:48 +01:00

214 lines
6.6 KiB
C++

#include "ShapePerFrameContext.hpp"
#include "CustomShape.hpp"
#include "MilkdropPresetExceptions.hpp"
#include "PerFrameContext.hpp"
#include <Logging.hpp>
#define REG_VAR(var) \
var = projectm_eval_context_register_variable(perFrameCodeContext, #var);
namespace libprojectM {
namespace MilkdropPreset {
ShapePerFrameContext::ShapePerFrameContext(projectm_eval_mem_buffer gmegabuf, PRJM_EVAL_F (*globalRegisters)[100])
: perFrameCodeContext(projectm_eval_context_create(gmegabuf, globalRegisters))
{
}
ShapePerFrameContext::~ShapePerFrameContext()
{
if (perFrameCodeHandle != nullptr)
{
projectm_eval_code_destroy(perFrameCodeHandle);
}
if (perFrameCodeContext != nullptr)
{
projectm_eval_context_destroy(perFrameCodeContext);
}
}
void ShapePerFrameContext::RegisterBuiltinVariables()
{
projectm_eval_context_reset_variables(perFrameCodeContext);
REG_VAR(time);
REG_VAR(fps);
REG_VAR(frame);
REG_VAR(progress);
for (int q = 0; q < QVarCount; q++)
{
std::string qvar = "q" + std::to_string(q + 1);
q_vars[q] = projectm_eval_context_register_variable(perFrameCodeContext, qvar.c_str());
}
for (int t = 0; t < TVarCount; t++)
{
std::string tvar = "t" + std::to_string(t + 1);
t_vars[t] = projectm_eval_context_register_variable(perFrameCodeContext, tvar.c_str());
}
REG_VAR(bass);
REG_VAR(mid);
REG_VAR(treb);
REG_VAR(bass_att);
REG_VAR(mid_att);
REG_VAR(treb_att);
REG_VAR(x);
REG_VAR(y);
REG_VAR(rad);
REG_VAR(ang);
REG_VAR(tex_ang);
REG_VAR(tex_zoom);
REG_VAR(sides);
REG_VAR(textured);
REG_VAR(instance);
REG_VAR(num_inst);
REG_VAR(additive);
REG_VAR(thick);
REG_VAR(r);
REG_VAR(g);
REG_VAR(b);
REG_VAR(a);
REG_VAR(r2);
REG_VAR(g2);
REG_VAR(b2);
REG_VAR(a2);
REG_VAR(border_r);
REG_VAR(border_g);
REG_VAR(border_b);
REG_VAR(border_a);
}
void ShapePerFrameContext::LoadStateVariables(const PresetState& state,
CustomShape& shape,
int inst)
{
*time = static_cast<double>(state.renderContext.time);
*frame = static_cast<double>(state.renderContext.frame);
*fps = static_cast<double>(state.renderContext.fps);
*progress = static_cast<double>(state.renderContext.progress);
*bass = static_cast<double>(state.audioData.bass);
*mid = static_cast<double>(state.audioData.mid);
*treb = static_cast<double>(state.audioData.treb);
*bass_att = static_cast<double>(state.audioData.bassAtt);
*mid_att = static_cast<double>(state.audioData.midAtt);
*treb_att = static_cast<double>(state.audioData.trebAtt);
for (int q = 0; q < QVarCount; q++)
{
*q_vars[q] = state.frameQVariables[q];
}
for (int t = 0; t < TVarCount; t++)
{
*t_vars[t] = shape.m_tValuesAfterInitCode[t];
}
*x = static_cast<double>(shape.m_x);
*y = static_cast<double>(shape.m_y);
*rad = static_cast<double>(shape.m_radius);
*ang = static_cast<double>(shape.m_angle);
*tex_zoom = static_cast<double>(shape.m_tex_zoom);
*tex_ang = static_cast<double>(shape.m_tex_ang);
*sides = static_cast<double>(shape.m_sides);
*additive = static_cast<double>(shape.m_additive);
*textured = static_cast<double>(shape.m_textured);
*num_inst = static_cast<double>(shape.m_instances);
*instance = static_cast<double>(inst);
*thick = static_cast<double>(shape.m_thickOutline);
*r = static_cast<double>(shape.m_r);
*g = static_cast<double>(shape.m_g);
*b = static_cast<double>(shape.m_b);
*a = static_cast<double>(shape.m_a);
*r2 = static_cast<double>(shape.m_r2);
*g2 = static_cast<double>(shape.m_g2);
*b2 = static_cast<double>(shape.m_b2);
*a2 = static_cast<double>(shape.m_a2);
*border_r = static_cast<double>(shape.m_border_r);
*border_g = static_cast<double>(shape.m_border_g);
*border_b = static_cast<double>(shape.m_border_b);
*border_a = static_cast<double>(shape.m_border_a);
}
void ShapePerFrameContext::EvaluateInitCode(const std::string& perFrameInitCode,
const CustomShape& shape)
{
if (perFrameInitCode.empty())
{
return;
}
auto* initCode = projectm_eval_code_compile(perFrameCodeContext, perFrameInitCode.c_str());
if (initCode == nullptr)
{
std::string error;
int line;
int col;
auto* errmsg = projectm_eval_get_error(perFrameCodeContext, &line, &col);
if (errmsg)
{
error = "[ShapePerFrameContext] Could not compile custom shape ";
error += std::to_string(shape.m_index);
error += " per-frame INIT code: ";
error += std::string(errmsg);
error += "(L" + std::to_string(line) + " C" + std::to_string(col) + ")";
}
else
{
error = "[ShapePerFrameContext] Could not compile custom shape " + std::to_string(shape.m_index) + " per-frame init code.";
}
LOG_DEBUG("[ShapePerFrameContext] Failed custom shape per-frame INIT code:\n" + perFrameInitCode);
throw MilkdropCompileException(error);
}
projectm_eval_code_execute(initCode);
projectm_eval_code_destroy(initCode);
}
void ShapePerFrameContext::CompilePerFrameCode(const std::string& perFrameCode,
const CustomShape& shape)
{
if (perFrameCode.empty())
{
return;
}
perFrameCodeHandle = projectm_eval_code_compile(perFrameCodeContext, perFrameCode.c_str());
if (perFrameCodeHandle == nullptr)
{
std::string error;
int line;
int col;
auto* errmsg = projectm_eval_get_error(perFrameCodeContext, &line, &col);
if (errmsg)
{
error = "[ShapePerFrameContext] Could not compile custom shape ";
error += std::to_string(shape.m_index);
error += " per-frame code: ";
error += errmsg;
error += "(L" + std::to_string(line) + " C" + std::to_string(col) + ")";
}
else
{
error = "[ShapePerFrameContext] Could not compile custom shape " + std::to_string(shape.m_index) + " per-frame code.";
}
LOG_DEBUG("[ShapePerFrameContext] Failed custom shape per-frame code:\n" + perFrameCode);
throw MilkdropCompileException(error);
}
}
void ShapePerFrameContext::ExecutePerFrameCode()
{
if (perFrameCodeHandle != nullptr)
{
projectm_eval_code_execute(perFrameCodeHandle);
}
}
} // namespace MilkdropPreset
} // namespace libprojectM