mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Build and run a node in VM, first!
This commit is contained in:
parent
416b6b2f43
commit
843fa7aeba
20 changed files with 165 additions and 73 deletions
BIN
art/pack/intro_drako_le_dragon.mp3
Normal file
BIN
art/pack/intro_drako_le_dragon.mp3
Normal file
Binary file not shown.
BIN
art/pack/la_fee_luminelle.mp3
Normal file
BIN
art/pack/la_fee_luminelle.mp3
Normal file
Binary file not shown.
BIN
art/pack/le_sceptre.mp3
Normal file
BIN
art/pack/le_sceptre.mp3
Normal file
Binary file not shown.
BIN
art/pack/qui_drako_va_t_il_rencontrer.mp3
Normal file
BIN
art/pack/qui_drako_va_t_il_rencontrer.mp3
Normal file
Binary file not shown.
Binary file not shown.
BIN
art/pack/qui_sera_le_hero.mp3
Normal file
BIN
art/pack/qui_sera_le_hero.mp3
Normal file
Binary file not shown.
BIN
art/pack/story1_drako_luminelle_sceptre.mp3
Normal file
BIN
art/pack/story1_drako_luminelle_sceptre.mp3
Normal file
Binary file not shown.
BIN
art/pack/un_oiseau.mp3
Normal file
BIN
art/pack/un_oiseau.mp3
Normal file
Binary file not shown.
|
|
@ -340,6 +340,7 @@ bool Assembler::Parse(const std::string &data)
|
|||
if (pos != std::string::npos) {
|
||||
line.erase(pos);
|
||||
}
|
||||
line.erase(std::remove(line.begin(), line.end(), '\t'), line.end()); // remove tabulations
|
||||
if (std::all_of(line.begin(), line.end(), ::isspace)) continue;
|
||||
|
||||
// Split the line
|
||||
|
|
|
|||
|
|
@ -40,44 +40,44 @@ extern "C" {
|
|||
typedef enum
|
||||
{
|
||||
// system:
|
||||
OP_NOP = 0, // do nothing
|
||||
OP_HALT = 1, // halt execution
|
||||
OP_SYSCALL = 2, // system call handled by user-registered function, 4 arguments (R0 - R3) passed by value
|
||||
OP_NOP = 0, ///< do nothing
|
||||
OP_HALT = 1, ///< halt execution
|
||||
OP_SYSCALL = 2, ///< system call handled by user-registered function, 4 arguments (R0 - R3) passed by value
|
||||
// constants:
|
||||
OP_LCONS = 3, // store a value in a register, e.g.: lcons r0, 0xA2 0x00 0x00 0x00
|
||||
// can also load a variable address: lcons r2, $DataInRam
|
||||
OP_LCONS = 3, ///< store a value in a register, e.g.: lcons r0, 0xA2 0x00 0x00 0x00
|
||||
///< can also load a variable address: lcons r2, $DataInRam
|
||||
|
||||
// register operations:
|
||||
OP_MOV = 4, // copy a value between registers, e.g.: mov r0, r2
|
||||
OP_MOV = 4, ///< copy a value between registers, e.g.: mov r0, r2
|
||||
// stack:
|
||||
OP_PUSH = 5, // push a register onto the stack, e.g.: push r0
|
||||
OP_POP = 6, // pop the first element of the stack to a register, e.g.: pop r0
|
||||
OP_PUSH = 5, ///< push a register onto the stack, e.g.: push r0
|
||||
OP_POP = 6, ///< pop the first element of the stack to a register, e.g.: pop r0
|
||||
|
||||
// memory get/set from/to an address. The last argument is a size (1, 2 or 4 bytes)
|
||||
OP_STORE = 7, // copy a value from a register to a ram address located in a register, specific size e.g. : store @r4, r1, 2 (2 bytes)
|
||||
OP_LOAD = 8, // copy a value from a ram address located in a register to a register, specific size e.g.: load r0, @r3, 1 (1 byte)
|
||||
OP_STORE = 7, ///< copy a value from a register to a ram address located in a register, specific size e.g. : store @r4, r1, 2 (2 bytes)
|
||||
OP_LOAD = 8, ///< copy a value from a ram address located in a register to a register, specific size e.g.: load r0, @r3, 1 (1 byte)
|
||||
|
||||
// arithmetic:
|
||||
OP_ADD = 9, // sum and store in first reg, e.g.: add r0, r2
|
||||
OP_SUB = 10, // subtract and store in first reg, e.g.: sub r0, r2
|
||||
OP_MUL = 11, // multiply and store in first reg, e.g.: mul r0, r2
|
||||
OP_DIV = 12, // divide and store in first reg, remain in second, e.g.: div r0, r2
|
||||
OP_ADD = 9, ///< sum and store in first reg, e.g.: add r0, r2
|
||||
OP_SUB = 10, ///< subtract and store in first reg, e.g.: sub r0, r2
|
||||
OP_MUL = 11, ///< multiply and store in first reg, e.g.: mul r0, r2
|
||||
OP_DIV = 12, ///< divide and store in first reg, remain in second, e.g.: div r0, r2
|
||||
|
||||
OP_SHL = 13, // logical shift left, e.g.: shl r0, r1
|
||||
OP_SHR = 14, // logical shift right, e.g.: shr r0, r1
|
||||
OP_ISHR = 15, // arithmetic shift right (for signed values), e.g.: ishr r0, r1
|
||||
OP_SHL = 13, ///< logical shift left, e.g.: shl r0, r1
|
||||
OP_SHR = 14, ///< logical shift right, e.g.: shr r0, r1
|
||||
OP_ISHR = 15, ///< arithmetic shift right (for signed values), e.g.: ishr r0, r1
|
||||
|
||||
OP_AND = 16, // and two registers and store result in the first one, e.g.: and r0, r1
|
||||
OP_OR = 17, // or two registers and store result in the first one, e.g.: or r0, r1
|
||||
OP_XOR = 18, // xor two registers and store result in the first one, e.g.: xor r0, r1
|
||||
OP_NOT = 19, // not a register and store result, e.g.: not r0
|
||||
OP_AND = 16, ///< and two registers and store result in the first one, e.g.: and r0, r1
|
||||
OP_OR = 17, ///< or two registers and store result in the first one, e.g.: or r0, r1
|
||||
OP_XOR = 18, ///< xor two registers and store result in the first one, e.g.: xor r0, r1
|
||||
OP_NOT = 19, ///< not a register and store result, e.g.: not r0
|
||||
|
||||
// branching/functions
|
||||
OP_CALL = 20, // set register RA to the next instruction and jump to subroutine, e.g.: call 0x10 0x00
|
||||
OP_RET = 21, // return to the address of last callee (RA), e.g.: ret
|
||||
OP_JUMP = 22, // jump to address (can use label or address), e.g.: jump .my_label
|
||||
OP_SKIPZ = 23, // skip next instruction if zero, e.g.: skipz r0
|
||||
OP_SKIPNZ = 24, // skip next instruction if not zero, e.g.: skipnz r2
|
||||
OP_CALL = 20, ///< set register RA to the next instruction and jump to subroutine, e.g.: call 0x10 0x00
|
||||
OP_RET = 21, ///< return to the address of last callee (RA), e.g.: ret
|
||||
OP_JUMP = 22, ///< jump to address (can use label or address), e.g.: jump .my_label
|
||||
OP_SKIPZ = 23, ///< skip next instruction if zero, e.g.: skipz r0
|
||||
OP_SKIPNZ = 24, ///< skip next instruction if not zero, e.g.: skipnz r2
|
||||
|
||||
INSTRUCTION_COUNT
|
||||
} chip32_instruction_t;
|
||||
|
|
@ -186,6 +186,10 @@ typedef struct
|
|||
|
||||
typedef uint8_t (*syscall_t)(uint8_t);
|
||||
|
||||
#define SYSCALL_RET_OK 0 ///< Default state, continue execution immediately
|
||||
#define SYSCALL_RET_WAIT_EV 1 ///< Sets the VM in wait for event state
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
virtual_mem_t rom;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 3b9ae0777cd52d6037bdcc6e0b05b57c5eb8701e
|
||||
Subproject commit ba75bd93e1b1c5d5bc387e49f35737697d180b30
|
||||
|
|
@ -82,7 +82,7 @@ MainWindow::MainWindow()
|
|||
addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, m_ostHmiDock);
|
||||
m_toolbar->AddDockToMenu(m_ostHmiDock->toggleViewAction(), m_ostHmiDock);
|
||||
|
||||
connect(m_ostHmiDock, &OstHmiDock::sigOkButton, [=]() {
|
||||
connect(m_ostHmiDock, &OstHmiDock::sigOkButton, [&]() {
|
||||
QCoreApplication::postEvent(this, new VmEvent(VmEvent::evOkButton));
|
||||
});
|
||||
|
||||
|
|
@ -98,16 +98,16 @@ MainWindow::MainWindow()
|
|||
addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, m_vmDock);
|
||||
m_toolbar->AddDockToMenu(m_vmDock->toggleViewAction(), m_vmDock);
|
||||
|
||||
connect(m_vmDock, &VmDock::sigCompile, [=]() {
|
||||
connect(m_vmDock, &VmDock::sigCompile, [&]() {
|
||||
// m_scriptEditorDock->setScript(m_project.BuildResources());
|
||||
});
|
||||
|
||||
connect(m_vmDock, &VmDock::sigStepInstruction, [=]() {
|
||||
connect(m_vmDock, &VmDock::sigStepInstruction, [&]() {
|
||||
QCoreApplication::postEvent(this, new VmEvent(VmEvent::evStep));
|
||||
});
|
||||
|
||||
connect(m_vmDock, &VmDock::sigBuild, [=]() {
|
||||
buildScript();
|
||||
connect(m_vmDock, &VmDock::sigBuild, [&]() {
|
||||
BuildScript();
|
||||
});
|
||||
|
||||
m_ramView = new MemoryViewDock("RamViewDock", "RAM");
|
||||
|
|
@ -176,7 +176,7 @@ MainWindow::MainWindow()
|
|||
NewProject();
|
||||
});
|
||||
|
||||
connect(m_toolbar, &ToolBar::sigSave, this, [=]() {
|
||||
connect(m_toolbar, &ToolBar::sigSave, this, [&]() {
|
||||
SaveProject();
|
||||
});
|
||||
|
||||
|
|
@ -215,6 +215,39 @@ MainWindow::MainWindow()
|
|||
CloseProject();
|
||||
RefreshProjectInformation();
|
||||
|
||||
// Prepare run timer
|
||||
m_runTimer = new QTimer(this);
|
||||
m_runTimer->setSingleShot(true);
|
||||
connect(m_runTimer, &QTimer::timeout, this, [&]() {
|
||||
if (m_dbg.run_result == VM_OK)
|
||||
{
|
||||
stepInstruction();
|
||||
}
|
||||
|
||||
if (m_dbg.run_result == VM_OK)
|
||||
{
|
||||
// Restart timer
|
||||
m_runTimer->start(100);
|
||||
}
|
||||
else if (m_dbg.run_result == VM_FINISHED)
|
||||
{
|
||||
m_dbg.running = false;
|
||||
}
|
||||
else if (m_dbg.run_result == VM_WAIT_EVENT)
|
||||
{
|
||||
m_runTimer->stop(); // just to make sure
|
||||
}
|
||||
});
|
||||
|
||||
connect(&m_model, &StoryGraphModel::sigAudioStopped, this, [&]() {
|
||||
|
||||
if ((m_dbg.run_result == VM_WAIT_EVENT) && (m_dbg.running))
|
||||
{
|
||||
// Continue execution of node
|
||||
m_runTimer->start(100);
|
||||
}
|
||||
});
|
||||
|
||||
// QMetaObject::invokeMethod(this, "slotWelcome", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
|
|
@ -224,8 +257,7 @@ void MainWindow::BuildAndRun()
|
|||
// FIXME
|
||||
|
||||
// 2. Generate the assembly code from the model
|
||||
std::string code = m_project.BuildResources() + "\n";
|
||||
code += m_model.Build();
|
||||
std::string code = m_model.Build();
|
||||
|
||||
// Add global functions
|
||||
code += ReadResourceFile(":/scripts/media.asm").toStdString();
|
||||
|
|
@ -235,8 +267,14 @@ void MainWindow::BuildAndRun()
|
|||
m_scriptEditorDock->setScript(code.c_str());
|
||||
|
||||
// 3. Compile the assembly to machine binary
|
||||
// buildScript();
|
||||
BuildScript();
|
||||
|
||||
// 4. Run the VM code!
|
||||
if (m_dbg.run_result == VM_OK)
|
||||
{
|
||||
m_dbg.running = true;
|
||||
m_runTimer->start(100);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -406,7 +444,7 @@ void MainWindow::updateAll()
|
|||
m_ramView->SetMemory(m_ram_data, m_chip32_ctx.ram.size);
|
||||
}
|
||||
|
||||
QString MainWindow::GetFileName(uint32_t addr)
|
||||
QString MainWindow::GetFileNameFromMemory(uint32_t addr)
|
||||
{
|
||||
char strBuf[100];
|
||||
bool isRam = addr & 0x80000000;
|
||||
|
|
@ -452,19 +490,21 @@ bool MainWindow::event(QEvent *event)
|
|||
|
||||
uint8_t MainWindow::Syscall(uint8_t code)
|
||||
{
|
||||
uint8_t retCode = 0;
|
||||
uint8_t retCode = SYSCALL_RET_OK;
|
||||
qDebug() << "SYSCALL: " << (int)code;
|
||||
|
||||
// Media
|
||||
if (code == 1)
|
||||
{
|
||||
// image file name address is in R0
|
||||
QString imageFile = GetFileName(m_chip32_ctx.registers[R0]);
|
||||
QString imageFile = m_model.BuildFullImagePath(GetFileNameFromMemory(m_chip32_ctx.registers[R0]));
|
||||
// sound file name address is in R1
|
||||
QString soundFile = GetFileName(m_chip32_ctx.registers[R1]);
|
||||
QString soundFile = m_model.BuildFullSoundPath(GetFileNameFromMemory(m_chip32_ctx.registers[R1]));
|
||||
|
||||
qDebug() << "Image: " << imageFile << ", Sound: " << soundFile;
|
||||
m_ostHmiDock->SetImage(imageFile);
|
||||
m_model.PlaySound(soundFile);
|
||||
retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause
|
||||
}
|
||||
// WAIT EVENT bits:
|
||||
// 0: block
|
||||
|
|
@ -478,7 +518,7 @@ uint8_t MainWindow::Syscall(uint8_t code)
|
|||
// Event mask is located in R0
|
||||
// optional timeout is located in R1
|
||||
// if timeout is set to zero, wait for infinite and beyond
|
||||
retCode = 1; // set the VM in pause
|
||||
retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -491,8 +531,11 @@ void MainWindow::stepInstruction()
|
|||
updateAll();
|
||||
}
|
||||
|
||||
void MainWindow::buildScript()
|
||||
void MainWindow::BuildScript()
|
||||
{
|
||||
m_dbg.run_result = VM_FINISHED;
|
||||
m_dbg.running = false;
|
||||
|
||||
if (m_assembler.Parse(m_scriptEditorDock->getScript().toStdString()) == true )
|
||||
{
|
||||
if (m_assembler.BuildBinary(m_program, m_result) == true)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <QLabel>
|
||||
#include <QMainWindow>
|
||||
#include <QDockWidget>
|
||||
#include <QTimer>
|
||||
|
||||
#include <QtNodes/ConnectionStyle>
|
||||
#include <QtNodes/GraphicsView>
|
||||
|
|
@ -136,6 +137,7 @@ private:
|
|||
GraphicsView *m_view{nullptr};
|
||||
|
||||
// Qt stuff
|
||||
QTimer *m_runTimer{nullptr};
|
||||
ToolBar *m_toolbar{nullptr};
|
||||
OstHmiDock *m_ostHmiDock{nullptr};
|
||||
ResourcesDock *m_resourcesDock{nullptr};
|
||||
|
|
@ -166,12 +168,12 @@ private:
|
|||
void createStatusBar();
|
||||
void SaveProject();
|
||||
void DisplayNode(StoryNode *m_tree, QtNodes::NodeId parentId);
|
||||
void buildScript();
|
||||
void BuildScript();
|
||||
void highlightNextLine();
|
||||
void readSettings();
|
||||
void updateAll();
|
||||
uint8_t Syscall(uint8_t code);
|
||||
QString GetFileName(uint32_t addr);
|
||||
QString GetFileNameFromMemory(uint32_t addr);
|
||||
|
||||
bool event(QEvent *event);
|
||||
void MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
|
|
|
|||
|
|
@ -148,6 +148,9 @@
|
|||
<item>
|
||||
<widget class="QSpinBox" name="spinBox">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -129,10 +129,10 @@ std::string MediaNodeModel::GenerateConstants()
|
|||
}
|
||||
if (sound.size() > 0)
|
||||
{
|
||||
s = StoryProject::FileToConstant(sound);
|
||||
s += StoryProject::FileToConstant(sound);
|
||||
}
|
||||
|
||||
// Generate choice table if needed (out ports > 1)
|
||||
// FIXME: Generate choice table if needed (out ports > 1)
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
@ -142,8 +142,8 @@ std::string MediaNodeModel::Build()
|
|||
std::stringstream ss;
|
||||
|
||||
ss << R"(; ---------------- )" << GetNodeTitle() << "\n";
|
||||
std::string image = m_mediaData["image"].get<std::string>();
|
||||
std::string sound = m_mediaData["sound"].get<std::string>();
|
||||
std::string image = StoryProject::RemoveFileExtension(m_mediaData["image"].get<std::string>());
|
||||
std::string sound = StoryProject::RemoveFileExtension(m_mediaData["sound"].get<std::string>());
|
||||
if (image.size() > 0)
|
||||
{
|
||||
ss << "lcons r0, $" << image << "\n";
|
||||
|
|
@ -161,6 +161,38 @@ std::string MediaNodeModel::Build()
|
|||
{
|
||||
ss << "lcons r1, 0\n";
|
||||
}
|
||||
// Call the media executor (image, sound)
|
||||
ss << "syscall 1\n";
|
||||
|
||||
|
||||
std::unordered_set<ConnectionId> conns = m_model.allConnectionIds(getNodeId());
|
||||
|
||||
int nb_out_ports = 0;
|
||||
|
||||
for (auto & c : conns)
|
||||
{
|
||||
if (c.outNodeId > 0)
|
||||
{
|
||||
nb_out_ports++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nb_out_ports == 0)
|
||||
{
|
||||
ss << "halt\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Check output connections number
|
||||
// == 0: end, generate halt
|
||||
// == 1: jump directly to the other node
|
||||
// > 1 : call the node choice manager
|
||||
|
||||
// lcons r0, $ChoiceObject
|
||||
// jump .media ; no return possible, so a jump is enough
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -26,7 +26,13 @@
|
|||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>200</height>
|
||||
<height>240</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>320</width>
|
||||
<height>240</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
|
|
@ -35,6 +41,9 @@
|
|||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
|
|
|
|||
|
|
@ -12,6 +12,13 @@ StoryGraphModel::StoryGraphModel(StoryProject &project)
|
|||
m_player = new QMediaPlayer;
|
||||
m_audioOutput = new QAudioOutput;
|
||||
m_player->setAudioOutput(m_audioOutput);
|
||||
|
||||
connect(m_player, &QMediaPlayer::playbackStateChanged, this, [&](QMediaPlayer::PlaybackState newState) {
|
||||
if (newState == QMediaPlayer::PlaybackState::StoppedState) {
|
||||
m_player->stop();
|
||||
emit sigAudioStopped();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
StoryGraphModel::~StoryGraphModel()
|
||||
|
|
@ -173,6 +180,9 @@ QVariant StoryGraphModel::nodeData(NodeId nodeId, NodeRole role) const
|
|||
result = QVariant::fromValue(w);
|
||||
break;
|
||||
}
|
||||
case NodeRole::Id:
|
||||
result = model->getNodeId();
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ public:
|
|||
NodeId FindFirstNode() const;
|
||||
signals:
|
||||
void sigChooseFile(NodeId id, const QString &type);
|
||||
void sigAudioStopped();
|
||||
|
||||
private:
|
||||
StoryProject &m_project;
|
||||
|
|
|
|||
|
|
@ -247,13 +247,18 @@ void StoryProject::ReplaceCharacter(std::string &theString, const std::string &t
|
|||
while (found != std::string::npos);
|
||||
}
|
||||
|
||||
std::string StoryProject::RemoveFileExtension(const std::string &FileName)
|
||||
{
|
||||
std::string f = GetFileName(FileName);
|
||||
std::string ext = GetFileExtension(f);
|
||||
EraseString(f, "." + ext);
|
||||
return f;
|
||||
}
|
||||
|
||||
std::string StoryProject::FileToConstant(const std::string &FileName)
|
||||
{
|
||||
std::string fileName = GetFileName(FileName);
|
||||
std::string ext = GetFileExtension(fileName);
|
||||
EraseString(fileName, "." + ext); // on retire l'extension du pack
|
||||
|
||||
return "$" + fileName + " DC8 \"" + fileName + "." + ext + "\", 8\r\n";
|
||||
std::string f = RemoveFileExtension(FileName);
|
||||
return "$" + f + " DC8 \"" + FileName + "\", 8\r\n";
|
||||
}
|
||||
|
||||
void StoryProject::AppendResource(const Resource &res)
|
||||
|
|
@ -292,24 +297,6 @@ std::string StoryProject::GetFileExtension(const std::string &fileName)
|
|||
return "";
|
||||
}
|
||||
|
||||
std::string StoryProject::BuildResources()
|
||||
{
|
||||
std::stringstream chip32;
|
||||
|
||||
chip32 << "\tjump .entry\r\n";
|
||||
|
||||
for (auto & r : m_resources)
|
||||
{
|
||||
std::string fileName = GetFileName(r.file);
|
||||
std::string ext = GetFileExtension(fileName);
|
||||
EraseString(fileName, "." + ext); // on retire l'extension du pack
|
||||
|
||||
chip32 << "$" << fileName << " DC8 \"" << fileName + "." + ext << "\", 8\r\n";
|
||||
}
|
||||
chip32 << ".entry:\r\n";
|
||||
|
||||
return chip32.str();
|
||||
}
|
||||
|
||||
void StoryProject::SetImageFormat(ImageFormat format)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ struct StoryProject
|
|||
m_initialized = false;
|
||||
}
|
||||
|
||||
std::string BuildResources();
|
||||
void SetImageFormat(ImageFormat format);
|
||||
void SetSoundFormat(SoundFormat format);
|
||||
void SetDisplayFormat(int w, int h);
|
||||
|
|
@ -85,6 +84,7 @@ struct StoryProject
|
|||
|
||||
static std::string GetFileExtension(const std::string &FileName);
|
||||
static std::string GetFileName(const std::string &path);
|
||||
static std::string RemoveFileExtension(const std::string &FileName);
|
||||
static void ReplaceCharacter(std::string &theString, const std::string &toFind, const std::string &toReplace);
|
||||
static std::string FileToConstant(const std::string &FileName);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue