mirror of https://github.com/AxioDL/metaforce.git
CMoviePlayer initial implementation
This commit is contained in:
parent
9cfe73d278
commit
6e160560fa
|
@ -41,11 +41,12 @@ target_link_libraries(urde
|
||||||
RuntimeCommonInput
|
RuntimeCommonInput
|
||||||
RuntimeCommonParticle
|
RuntimeCommonParticle
|
||||||
RuntimeCommonGraphics
|
RuntimeCommonGraphics
|
||||||
|
RuntimeCommonAudio
|
||||||
RuntimeCommon
|
RuntimeCommon
|
||||||
DNAMP3 DNAMP2 DNAMP1
|
DNAMP3 DNAMP2 DNAMP1
|
||||||
DNACommon specter specter-fonts freetype ${DATA_SPEC_LIBS}
|
DNACommon specter specter-fonts freetype ${DATA_SPEC_LIBS}
|
||||||
hecl-database hecl-backend hecl-frontend hecl-blender hecl-runtime hecl-common athena-core nod
|
hecl-database hecl-backend hecl-frontend hecl-blender hecl-runtime hecl-common athena-core nod
|
||||||
logvisor athena-libyaml boo ${PNG_LIB} squish xxhash zeus
|
logvisor athena-libyaml boo ${PNG_LIB} libjpeg-turbo squish xxhash zeus
|
||||||
${ZLIB_LIBRARIES} ${LZO_LIB}
|
${ZLIB_LIBRARIES} ${LZO_LIB}
|
||||||
${BOO_SYS_LIBS})
|
${BOO_SYS_LIBS})
|
||||||
|
|
||||||
|
|
|
@ -47,9 +47,13 @@ bool ProjectManager::newProject(const hecl::SystemString& path)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_vm.ProjectChanged(*m_proj);
|
||||||
m_vm.SetupEditorView();
|
m_vm.SetupEditorView();
|
||||||
saveProject();
|
saveProject();
|
||||||
m_vm.m_mainWindow->setTitle(m_proj->getProjectRootPath().getLastComponent());
|
|
||||||
|
hecl::SystemString windowTitle(m_proj->getProjectRootPath().getLastComponent());
|
||||||
|
windowTitle += _S(" - URDE");
|
||||||
|
m_vm.m_mainWindow->setTitle(windowTitle.c_str());
|
||||||
m_vm.DismissSplash();
|
m_vm.DismissSplash();
|
||||||
m_vm.FadeInEditors();
|
m_vm.FadeInEditors();
|
||||||
|
|
||||||
|
@ -96,11 +100,17 @@ bool ProjectManager::openProject(const hecl::SystemString& path)
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
m_vm.ProjectChanged(*m_proj);
|
||||||
m_vm.SetupEditorView(r);
|
m_vm.SetupEditorView(r);
|
||||||
|
|
||||||
IndexMP1Resources();
|
IndexMP1Resources();
|
||||||
m_vm.BuildTestPART(m_objStore);
|
m_vm.BuildTestPART(m_objStore);
|
||||||
m_vm.m_mainWindow->setTitle(m_proj->getProjectRootPath().getLastComponent());
|
|
||||||
|
{
|
||||||
|
hecl::SystemString windowTitle(m_proj->getProjectRootPath().getLastComponent());
|
||||||
|
windowTitle += _S(" - URDE");
|
||||||
|
m_vm.m_mainWindow->setTitle(windowTitle.c_str());
|
||||||
|
}
|
||||||
m_vm.DismissSplash();
|
m_vm.DismissSplash();
|
||||||
m_vm.FadeInEditors();
|
m_vm.FadeInEditors();
|
||||||
|
|
||||||
|
@ -109,12 +119,15 @@ bool ProjectManager::openProject(const hecl::SystemString& path)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
makeDefault:
|
makeDefault:
|
||||||
|
m_vm.ProjectChanged(*m_proj);
|
||||||
m_vm.SetupEditorView();
|
m_vm.SetupEditorView();
|
||||||
saveProject();
|
saveProject();
|
||||||
|
|
||||||
hecl::SystemString windowTitle(m_proj->getProjectRootPath().getLastComponent());
|
{
|
||||||
windowTitle += _S(" - URDE");
|
hecl::SystemString windowTitle(m_proj->getProjectRootPath().getLastComponent());
|
||||||
m_vm.m_mainWindow->setTitle(windowTitle.c_str());
|
windowTitle += _S(" - URDE");
|
||||||
|
m_vm.m_mainWindow->setTitle(windowTitle.c_str());
|
||||||
|
}
|
||||||
m_vm.DismissSplash();
|
m_vm.DismissSplash();
|
||||||
m_vm.FadeInEditors();
|
m_vm.FadeInEditors();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -21,13 +21,17 @@ namespace urde
|
||||||
void ViewManager::BuildTestPART(urde::IObjectStore& objStore)
|
void ViewManager::BuildTestPART(urde::IObjectStore& objStore)
|
||||||
{
|
{
|
||||||
//m_partGenDesc = objStore.GetObj({hecl::FOURCC('PART'), 0x972A5CD2});
|
//m_partGenDesc = objStore.GetObj({hecl::FOURCC('PART'), 0x972A5CD2});
|
||||||
|
/*
|
||||||
m_partGenDesc = objStore.GetObj("BusterSparks");
|
m_partGenDesc = objStore.GetObj("BusterSparks");
|
||||||
m_partGen.reset(new urde::CElementGen(m_partGenDesc,
|
m_partGen.reset(new urde::CElementGen(m_partGenDesc,
|
||||||
urde::CElementGen::EModelOrientationType::Normal,
|
urde::CElementGen::EModelOrientationType::Normal,
|
||||||
urde::CElementGen::EOptionalSystemFlags::None));
|
urde::CElementGen::EOptionalSystemFlags::None));
|
||||||
m_partGen->SetGlobalScale({5.f, 5.f, 5.f});
|
m_partGen->SetGlobalScale({5.f, 5.f, 5.f});
|
||||||
m_particleView.reset(new ParticleView(*this, m_viewResources, *m_rootView));
|
|
||||||
m_lineRenderer.reset(new urde::CLineRenderer(urde::CLineRenderer::EPrimitiveMode::LineStrip, 4, nullptr, true));
|
m_lineRenderer.reset(new urde::CLineRenderer(urde::CLineRenderer::EPrimitiveMode::LineStrip, 4, nullptr, true));
|
||||||
|
*/
|
||||||
|
m_particleView.reset(new ParticleView(*this, m_viewResources, *m_rootView));
|
||||||
|
hecl::ProjectPath thpPath(m_projManager.project()->getProjectWorkingPath(), _S("out/MP1/Video/creditBG.thp"));
|
||||||
|
m_moviePlayer.reset(new CMoviePlayer(thpPath.getAbsolutePathUTF8().c_str(), 0.f, true, true));
|
||||||
|
|
||||||
//m_rootView->accessContentViews().clear();
|
//m_rootView->accessContentViews().clear();
|
||||||
m_rootView->accessContentViews().push_back(m_particleView.get());
|
m_rootView->accessContentViews().push_back(m_particleView.get());
|
||||||
|
@ -98,6 +102,12 @@ void ViewManager::RootSpaceViewBuilt(specter::View *view)
|
||||||
m_rootView->updateSize();
|
m_rootView->updateSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewManager::ProjectChanged(hecl::Database::Project& proj)
|
||||||
|
{
|
||||||
|
CDvdFile::Shutdown();
|
||||||
|
CDvdFile::Initialize(hecl::ProjectPath(proj.getProjectWorkingPath(), _S("out/MP1")));
|
||||||
|
}
|
||||||
|
|
||||||
void ViewManager::SetupEditorView()
|
void ViewManager::SetupEditorView()
|
||||||
{
|
{
|
||||||
m_rootSpace.reset(new RootSpace(*this));
|
m_rootSpace.reset(new RootSpace(*this));
|
||||||
|
@ -224,9 +234,10 @@ void ViewManager::init(boo::IApplication* app)
|
||||||
|
|
||||||
m_mainWindow->setWaitCursor(false);
|
m_mainWindow->setWaitCursor(false);
|
||||||
|
|
||||||
urde::CGraphics::InitializeBoo(gf, m_mainWindow->getCommandQueue(), root->renderTex());
|
CGraphics::InitializeBoo(gf, m_mainWindow->getCommandQueue(), root->renderTex());
|
||||||
urde::CElementGen::Initialize();
|
CElementGen::Initialize();
|
||||||
urde::CLineRenderer::Initialize();
|
CMoviePlayer::Initialize();
|
||||||
|
CLineRenderer::Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ViewManager::proc()
|
bool ViewManager::proc()
|
||||||
|
@ -277,8 +288,9 @@ bool ViewManager::proc()
|
||||||
|
|
||||||
void ViewManager::stop()
|
void ViewManager::stop()
|
||||||
{
|
{
|
||||||
urde::CElementGen::Shutdown();
|
CElementGen::Shutdown();
|
||||||
urde::CLineRenderer::Shutdown();
|
CMoviePlayer::Shutdown();
|
||||||
|
CLineRenderer::Shutdown();
|
||||||
m_iconsToken.doDestroy();
|
m_iconsToken.doDestroy();
|
||||||
m_viewResources.destroyResData();
|
m_viewResources.destroyResData();
|
||||||
m_fontCache.destroyAtlases();
|
m_fontCache.destroyAtlases();
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "Runtime/Particle/CElementGen.hpp"
|
#include "Runtime/Particle/CElementGen.hpp"
|
||||||
#include "Runtime/Graphics/CLineRenderer.hpp"
|
#include "Runtime/Graphics/CLineRenderer.hpp"
|
||||||
|
#include "Runtime/Graphics/CMoviePlayer.hpp"
|
||||||
|
|
||||||
namespace urde
|
namespace urde
|
||||||
{
|
{
|
||||||
|
@ -47,6 +48,7 @@ class ViewManager : public specter::IViewManager
|
||||||
urde::TLockedToken<urde::CGenDescription> m_partGenDesc;
|
urde::TLockedToken<urde::CGenDescription> m_partGenDesc;
|
||||||
std::unique_ptr<urde::CElementGen> m_partGen;
|
std::unique_ptr<urde::CElementGen> m_partGen;
|
||||||
std::unique_ptr<urde::CLineRenderer> m_lineRenderer;
|
std::unique_ptr<urde::CLineRenderer> m_lineRenderer;
|
||||||
|
std::unique_ptr<urde::CMoviePlayer> m_moviePlayer;
|
||||||
|
|
||||||
hecl::SystemString m_recentProjectsPath;
|
hecl::SystemString m_recentProjectsPath;
|
||||||
std::vector<hecl::SystemString> m_recentProjects;
|
std::vector<hecl::SystemString> m_recentProjects;
|
||||||
|
@ -60,6 +62,7 @@ class ViewManager : public specter::IViewManager
|
||||||
specter::RootView* SetupRootView();
|
specter::RootView* SetupRootView();
|
||||||
SplashScreen* SetupSplashView();
|
SplashScreen* SetupSplashView();
|
||||||
void RootSpaceViewBuilt(specter::View* view);
|
void RootSpaceViewBuilt(specter::View* view);
|
||||||
|
void ProjectChanged(hecl::Database::Project& proj);
|
||||||
void SetupEditorView();
|
void SetupEditorView();
|
||||||
void SetupEditorView(ConfigReader& r);
|
void SetupEditorView(ConfigReader& r);
|
||||||
void SaveEditorView(ConfigWriter& w);
|
void SaveEditorView(ConfigWriter& w);
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 2015 PathShagged Contributors
|
Copyright (c) 2015-2016 URDE Contributors
|
||||||
Original Authors: Jack Andersen and Phillip "Antidote" Stephens
|
Original Authors: Jack Andersen and Phillip "Antidote" Stephens
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
|
|
@ -2,4 +2,6 @@ add_library(RuntimeCommonAudio
|
||||||
CAudioSys.hpp CAudioSys.cpp
|
CAudioSys.hpp CAudioSys.cpp
|
||||||
CAudioStateWin.hpp CAudioStateWin.cpp
|
CAudioStateWin.hpp CAudioStateWin.cpp
|
||||||
CSfxManager.hpp CSfxManager.cpp
|
CSfxManager.hpp CSfxManager.cpp
|
||||||
CSfxHandle.hpp CSfxHandle.cpp)
|
CSfxHandle.hpp CSfxHandle.cpp
|
||||||
|
dsp.c dsp.h
|
||||||
|
g721.c g721.h)
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include "dsp.h"
|
||||||
|
|
||||||
|
static const int NibbleToInt[16] = {0,1,2,3,4,5,6,7,-8,-7,-6,-5,-4,-3,-2,-1};
|
||||||
|
|
||||||
|
static inline short SampClamp(int val)
|
||||||
|
{
|
||||||
|
if (val < -32768) val = -32768;
|
||||||
|
if (val > 32767) val = 32767;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDecompressFrame(int16_t* out, const uint8_t* in,
|
||||||
|
const int16_t coefs[8][2], int16_t* prev1, int16_t* prev2,
|
||||||
|
unsigned lastSample)
|
||||||
|
{
|
||||||
|
uint8_t cIdx = (in[0]>>4) & 0xf;
|
||||||
|
int16_t factor1 = coefs[cIdx][0];
|
||||||
|
int16_t factor2 = coefs[cIdx][1];
|
||||||
|
uint8_t exp = in[0] & 0xf;
|
||||||
|
for (int s=0 ; s<14 && s<lastSample ; ++s)
|
||||||
|
{
|
||||||
|
int sampleData = (s&1)?
|
||||||
|
NibbleToInt[(in[s/2+1])&0xf]:
|
||||||
|
NibbleToInt[(in[s/2+1]>>4)&0xf];
|
||||||
|
sampleData <<= exp;
|
||||||
|
sampleData <<= 11;
|
||||||
|
sampleData += 1024;
|
||||||
|
sampleData +=
|
||||||
|
factor1 * *prev1 +
|
||||||
|
factor2 * *prev2;
|
||||||
|
sampleData >>= 11;
|
||||||
|
sampleData = SampClamp(sampleData);
|
||||||
|
out[s] = sampleData;
|
||||||
|
*prev2 = *prev1;
|
||||||
|
*prev1 = sampleData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDecompressFrameStereoStride(int16_t* out, const uint8_t* in,
|
||||||
|
const int16_t coefs[8][2], int16_t* prev1, int16_t* prev2,
|
||||||
|
unsigned lastSample)
|
||||||
|
{
|
||||||
|
uint8_t cIdx = (in[0]>>4) & 0xf;
|
||||||
|
int16_t factor1 = coefs[cIdx][0];
|
||||||
|
int16_t factor2 = coefs[cIdx][1];
|
||||||
|
uint8_t exp = in[0] & 0xf;
|
||||||
|
for (int s=0 ; s<14 && s<lastSample ; ++s)
|
||||||
|
{
|
||||||
|
int sampleData = (s&1)?
|
||||||
|
NibbleToInt[(in[s/2+1])&0xf]:
|
||||||
|
NibbleToInt[(in[s/2+1]>>4)&0xf];
|
||||||
|
sampleData <<= exp;
|
||||||
|
sampleData <<= 11;
|
||||||
|
sampleData += 1024;
|
||||||
|
sampleData +=
|
||||||
|
factor1 * *prev1 +
|
||||||
|
factor2 * *prev2;
|
||||||
|
sampleData >>= 11;
|
||||||
|
sampleData = SampClamp(sampleData);
|
||||||
|
out[s*2] = sampleData;
|
||||||
|
*prev2 = *prev1;
|
||||||
|
*prev1 = sampleData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDecompressFrameStereoDupe(int16_t* out, const uint8_t* in,
|
||||||
|
const int16_t coefs[8][2], int16_t* prev1, int16_t* prev2,
|
||||||
|
unsigned lastSample)
|
||||||
|
{
|
||||||
|
uint8_t cIdx = (in[0]>>4) & 0xf;
|
||||||
|
int16_t factor1 = coefs[cIdx][0];
|
||||||
|
int16_t factor2 = coefs[cIdx][1];
|
||||||
|
uint8_t exp = in[0] & 0xf;
|
||||||
|
for (int s=0 ; s<14 && s<lastSample ; ++s)
|
||||||
|
{
|
||||||
|
int sampleData = (s&1)?
|
||||||
|
NibbleToInt[(in[s/2+1])&0xf]:
|
||||||
|
NibbleToInt[(in[s/2+1]>>4)&0xf];
|
||||||
|
sampleData <<= exp;
|
||||||
|
sampleData <<= 11;
|
||||||
|
sampleData += 1024;
|
||||||
|
sampleData +=
|
||||||
|
factor1 * *prev1 +
|
||||||
|
factor2 * *prev2;
|
||||||
|
sampleData >>= 11;
|
||||||
|
sampleData = SampClamp(sampleData);
|
||||||
|
out[s*2] = sampleData;
|
||||||
|
out[s*2+1] = sampleData;
|
||||||
|
*prev2 = *prev1;
|
||||||
|
*prev1 = sampleData;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef _DSP_h
|
||||||
|
#define _DSP_h
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void DSPDecompressFrame(int16_t* out, const uint8_t* in,
|
||||||
|
const int16_t coefs[8][2], int16_t* prev1, int16_t* prev2,
|
||||||
|
unsigned lastSample);
|
||||||
|
void DSPDecompressFrameStereoStride(int16_t* out, const uint8_t* in,
|
||||||
|
const int16_t coefs[8][2], int16_t* prev1, int16_t* prev2,
|
||||||
|
unsigned lastSample);
|
||||||
|
void DSPDecompressFrameStereoDupe(int16_t* out, const uint8_t* in,
|
||||||
|
const int16_t coefs[8][2], int16_t* prev1, int16_t* prev2,
|
||||||
|
unsigned lastSample);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _DSP_h
|
|
@ -0,0 +1,457 @@
|
||||||
|
/* G.721 decoder, from Sun's public domain CCITT-ADPCM sources,
|
||||||
|
* retrieved from ftp://ftp.cwi.nl/pub/audio/ccitt-adpcm.tar.gz
|
||||||
|
*
|
||||||
|
* For reference, here's the original license:
|
||||||
|
*
|
||||||
|
* This source code is a product of Sun Microsystems, Inc. and is provided
|
||||||
|
* for unrestricted use. Users may copy or modify this source code without
|
||||||
|
* charge.
|
||||||
|
*
|
||||||
|
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
|
||||||
|
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
|
||||||
|
*
|
||||||
|
* Sun source code is provided with no support and without any obligation on
|
||||||
|
* the part of Sun Microsystems, Inc. to assist in its use, correction,
|
||||||
|
* modification or enhancement.
|
||||||
|
*
|
||||||
|
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
|
||||||
|
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
|
||||||
|
* OR ANY PART THEREOF.
|
||||||
|
*
|
||||||
|
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
|
||||||
|
* or profits or other special, indirect and consequential damages, even if
|
||||||
|
* Sun has been advised of the possibility of such damages.
|
||||||
|
*
|
||||||
|
* Sun Microsystems, Inc.
|
||||||
|
* 2550 Garcia Avenue
|
||||||
|
* Mountain View, California 94043
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "g721.h"
|
||||||
|
|
||||||
|
static short power2[15] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
|
||||||
|
0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* quan()
|
||||||
|
*
|
||||||
|
* quantizes the input val against the table of size short integers.
|
||||||
|
* It returns i if table[i - 1] <= val < table[i].
|
||||||
|
*
|
||||||
|
* Using linear search for simple coding.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
quan(
|
||||||
|
int val,
|
||||||
|
short *table,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
if (val < *table++)
|
||||||
|
break;
|
||||||
|
return (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fmult()
|
||||||
|
*
|
||||||
|
* returns the integer product of the 14-bit integer "an" and
|
||||||
|
* "floating point" representation (4-bit exponent, 6-bit mantessa) "srn".
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
fmult(
|
||||||
|
int an,
|
||||||
|
int srn)
|
||||||
|
{
|
||||||
|
short anmag, anexp, anmant;
|
||||||
|
short wanexp, wanmant;
|
||||||
|
short retval;
|
||||||
|
|
||||||
|
anmag = (an > 0) ? an : ((-an) & 0x1FFF);
|
||||||
|
anexp = quan(anmag, power2, 15) - 6;
|
||||||
|
anmant = (anmag == 0) ? 32 :
|
||||||
|
(anexp >= 0) ? anmag >> anexp : anmag << -anexp;
|
||||||
|
wanexp = anexp + ((srn >> 6) & 0xF) - 13;
|
||||||
|
|
||||||
|
wanmant = (anmant * (srn & 077) + 0x30) >> 4;
|
||||||
|
retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) :
|
||||||
|
(wanmant >> -wanexp);
|
||||||
|
|
||||||
|
return (((an ^ srn) < 0) ? -retval : retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* g72x_init_state()
|
||||||
|
*
|
||||||
|
* This routine initializes and/or resets the g72x_state structure
|
||||||
|
* pointed to by 'state_ptr'.
|
||||||
|
* All the initial state values are specified in the CCITT G.721 document.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
g72x_init_state(struct g72x_state *state_ptr)
|
||||||
|
{
|
||||||
|
int cnta;
|
||||||
|
|
||||||
|
state_ptr->yl = 34816;
|
||||||
|
state_ptr->yu = 544;
|
||||||
|
state_ptr->dms = 0;
|
||||||
|
state_ptr->dml = 0;
|
||||||
|
state_ptr->ap = 0;
|
||||||
|
for (cnta = 0; cnta < 2; cnta++) {
|
||||||
|
state_ptr->a[cnta] = 0;
|
||||||
|
state_ptr->pk[cnta] = 0;
|
||||||
|
state_ptr->sr[cnta] = 32;
|
||||||
|
}
|
||||||
|
for (cnta = 0; cnta < 6; cnta++) {
|
||||||
|
state_ptr->b[cnta] = 0;
|
||||||
|
state_ptr->dq[cnta] = 32;
|
||||||
|
}
|
||||||
|
state_ptr->td = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* predictor_zero()
|
||||||
|
*
|
||||||
|
* computes the estimated signal from 6-zero predictor.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
predictor_zero(
|
||||||
|
struct g72x_state *state_ptr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int sezi;
|
||||||
|
|
||||||
|
sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]);
|
||||||
|
for (i = 1; i < 6; i++) /* ACCUM */
|
||||||
|
sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);
|
||||||
|
return (sezi);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* predictor_pole()
|
||||||
|
*
|
||||||
|
* computes the estimated signal from 2-pole predictor.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
predictor_pole(
|
||||||
|
struct g72x_state *state_ptr)
|
||||||
|
{
|
||||||
|
return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +
|
||||||
|
fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* step_size()
|
||||||
|
*
|
||||||
|
* computes the quantization step size of the adaptive quantizer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static long
|
||||||
|
step_size(
|
||||||
|
struct g72x_state *state_ptr)
|
||||||
|
{
|
||||||
|
long y;
|
||||||
|
long dif;
|
||||||
|
long al;
|
||||||
|
|
||||||
|
if (state_ptr->ap >= 256)
|
||||||
|
return (state_ptr->yu);
|
||||||
|
else {
|
||||||
|
y = state_ptr->yl >> 6;
|
||||||
|
dif = state_ptr->yu - y;
|
||||||
|
al = state_ptr->ap >> 2;
|
||||||
|
if (dif > 0)
|
||||||
|
y += (dif * al) >> 6;
|
||||||
|
else if (dif < 0)
|
||||||
|
y += (dif * al + 0x3F) >> 6;
|
||||||
|
return (y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reconstruct()
|
||||||
|
*
|
||||||
|
* Returns reconstructed difference signal 'dq' obtained from
|
||||||
|
* codeword 'i' and quantization step size scale factor 'y'.
|
||||||
|
* Multiplication is performed in log base 2 domain as addition.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
reconstruct(
|
||||||
|
int sign, /* 0 for non-negative value */
|
||||||
|
int dqln, /* G.72x codeword */
|
||||||
|
int y) /* Step size multiplier */
|
||||||
|
{
|
||||||
|
short dql; /* Log of 'dq' magnitude */
|
||||||
|
short dex; /* Integer part of log */
|
||||||
|
short dqt;
|
||||||
|
short dq; /* Reconstructed difference signal sample */
|
||||||
|
|
||||||
|
dql = dqln + (y >> 2); /* ADDA */
|
||||||
|
|
||||||
|
if (dql < 0) {
|
||||||
|
return ((sign) ? -0x8000 : 0);
|
||||||
|
} else { /* ANTILOG */
|
||||||
|
dex = (dql >> 7) & 15;
|
||||||
|
dqt = 128 + (dql & 127);
|
||||||
|
dq = (dqt << 7) >> (14 - dex);
|
||||||
|
return ((sign) ? (dq - 0x8000) : dq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* update()
|
||||||
|
*
|
||||||
|
* updates the state variables for each output code
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
update(
|
||||||
|
/*int code_size,*/ /* distinguish 723_40 with others */
|
||||||
|
int y, /* quantizer step size */
|
||||||
|
int wi, /* scale factor multiplier */
|
||||||
|
int fi, /* for long/short term energies */
|
||||||
|
int dq, /* quantized prediction difference */
|
||||||
|
int sr, /* reconstructed signal */
|
||||||
|
int dqsez, /* difference from 2-pole predictor */
|
||||||
|
struct g72x_state *state_ptr) /* coder state pointer */
|
||||||
|
{
|
||||||
|
int cnt;
|
||||||
|
short mag, exp; /* Adaptive predictor, FLOAT A */
|
||||||
|
short a2p; /* LIMC */
|
||||||
|
short a1ul; /* UPA1 */
|
||||||
|
short pks1; /* UPA2 */
|
||||||
|
short fa1;
|
||||||
|
char tr; /* tone/transition detector */
|
||||||
|
short ylint, thr2, dqthr;
|
||||||
|
short ylfrac, thr1;
|
||||||
|
short pk0;
|
||||||
|
|
||||||
|
pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */
|
||||||
|
|
||||||
|
mag = dq & 0x7FFF; /* prediction difference magnitude */
|
||||||
|
/* TRANS */
|
||||||
|
ylint = state_ptr->yl >> 15; /* exponent part of yl */
|
||||||
|
ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */
|
||||||
|
thr1 = (32 + ylfrac) << ylint; /* threshold */
|
||||||
|
thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */
|
||||||
|
dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */
|
||||||
|
if (state_ptr->td == 0) /* signal supposed voice */
|
||||||
|
tr = 0;
|
||||||
|
else if (mag <= dqthr) /* supposed data, but small mag */
|
||||||
|
tr = 0; /* treated as voice */
|
||||||
|
else /* signal is data (modem) */
|
||||||
|
tr = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Quantizer scale factor adaptation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FUNCTW & FILTD & DELAY */
|
||||||
|
/* update non-steady state step size multiplier */
|
||||||
|
state_ptr->yu = y + ((wi - y) >> 5);
|
||||||
|
|
||||||
|
/* LIMB */
|
||||||
|
if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */
|
||||||
|
state_ptr->yu = 544;
|
||||||
|
else if (state_ptr->yu > 5120)
|
||||||
|
state_ptr->yu = 5120;
|
||||||
|
|
||||||
|
/* FILTE & DELAY */
|
||||||
|
/* update steady state step size multiplier */
|
||||||
|
state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adaptive predictor coefficients.
|
||||||
|
*/
|
||||||
|
if (tr == 1) { /* reset a's and b's for modem signal */
|
||||||
|
state_ptr->a[0] = 0;
|
||||||
|
state_ptr->a[1] = 0;
|
||||||
|
state_ptr->b[0] = 0;
|
||||||
|
state_ptr->b[1] = 0;
|
||||||
|
state_ptr->b[2] = 0;
|
||||||
|
state_ptr->b[3] = 0;
|
||||||
|
state_ptr->b[4] = 0;
|
||||||
|
state_ptr->b[5] = 0;
|
||||||
|
a2p=0; /* won't be used, clear warning */
|
||||||
|
} else { /* update a's and b's */
|
||||||
|
pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */
|
||||||
|
|
||||||
|
/* update predictor pole a[1] */
|
||||||
|
a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);
|
||||||
|
if (dqsez != 0) {
|
||||||
|
fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];
|
||||||
|
if (fa1 < -8191) /* a2p = function of fa1 */
|
||||||
|
a2p -= 0x100;
|
||||||
|
else if (fa1 > 8191)
|
||||||
|
a2p += 0xFF;
|
||||||
|
else
|
||||||
|
a2p += fa1 >> 5;
|
||||||
|
|
||||||
|
if (pk0 ^ state_ptr->pk[1])
|
||||||
|
/* LIMC */
|
||||||
|
if (a2p <= -12160)
|
||||||
|
a2p = -12288;
|
||||||
|
else if (a2p >= 12416)
|
||||||
|
a2p = 12288;
|
||||||
|
else
|
||||||
|
a2p -= 0x80;
|
||||||
|
else if (a2p <= -12416)
|
||||||
|
a2p = -12288;
|
||||||
|
else if (a2p >= 12160)
|
||||||
|
a2p = 12288;
|
||||||
|
else
|
||||||
|
a2p += 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TRIGB & DELAY */
|
||||||
|
state_ptr->a[1] = a2p;
|
||||||
|
|
||||||
|
/* UPA1 */
|
||||||
|
/* update predictor pole a[0] */
|
||||||
|
state_ptr->a[0] -= state_ptr->a[0] >> 8;
|
||||||
|
if (dqsez != 0) {
|
||||||
|
if (pks1 == 0)
|
||||||
|
state_ptr->a[0] += 192;
|
||||||
|
else
|
||||||
|
state_ptr->a[0] -= 192;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LIMD */
|
||||||
|
a1ul = 15360 - a2p;
|
||||||
|
if (state_ptr->a[0] < -a1ul)
|
||||||
|
state_ptr->a[0] = -a1ul;
|
||||||
|
else if (state_ptr->a[0] > a1ul)
|
||||||
|
state_ptr->a[0] = a1ul;
|
||||||
|
|
||||||
|
/* UPB : update predictor zeros b[6] */
|
||||||
|
for (cnt = 0; cnt < 6; cnt++) {
|
||||||
|
/*if (code_size == 5)*/ /* for 40Kbps G.723 */
|
||||||
|
/* state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;*/
|
||||||
|
/*else*/ /* for G.721 and 24Kbps G.723 */
|
||||||
|
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;
|
||||||
|
if (dq & 0x7FFF) { /* XOR */
|
||||||
|
if ((dq ^ state_ptr->dq[cnt]) >= 0)
|
||||||
|
state_ptr->b[cnt] += 128;
|
||||||
|
else
|
||||||
|
state_ptr->b[cnt] -= 128;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cnt = 5; cnt > 0; cnt--)
|
||||||
|
state_ptr->dq[cnt] = state_ptr->dq[cnt-1];
|
||||||
|
/* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
|
||||||
|
if (mag == 0) {
|
||||||
|
state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20;
|
||||||
|
} else {
|
||||||
|
exp = quan(mag, power2, 15);
|
||||||
|
state_ptr->dq[0] = (dq >= 0) ?
|
||||||
|
(exp << 6) + ((mag << 6) >> exp) :
|
||||||
|
(exp << 6) + ((mag << 6) >> exp) - 0x400;
|
||||||
|
}
|
||||||
|
|
||||||
|
state_ptr->sr[1] = state_ptr->sr[0];
|
||||||
|
/* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
|
||||||
|
if (sr == 0) {
|
||||||
|
state_ptr->sr[0] = 0x20;
|
||||||
|
} else if (sr > 0) {
|
||||||
|
exp = quan(sr, power2, 15);
|
||||||
|
state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp);
|
||||||
|
} else if (sr > -32768) {
|
||||||
|
mag = -sr;
|
||||||
|
exp = quan(mag, power2, 15);
|
||||||
|
state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400;
|
||||||
|
} else
|
||||||
|
state_ptr->sr[0] = 0xFC20;
|
||||||
|
|
||||||
|
/* DELAY A */
|
||||||
|
state_ptr->pk[1] = state_ptr->pk[0];
|
||||||
|
state_ptr->pk[0] = pk0;
|
||||||
|
|
||||||
|
/* TONE */
|
||||||
|
if (tr == 1) /* this sample has been treated as data */
|
||||||
|
state_ptr->td = 0; /* next one will be treated as voice */
|
||||||
|
else if (a2p < -11776) /* small sample-to-sample correlation */
|
||||||
|
state_ptr->td = 1; /* signal may be data */
|
||||||
|
else /* signal is voice */
|
||||||
|
state_ptr->td = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adaptation speed control.
|
||||||
|
*/
|
||||||
|
state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */
|
||||||
|
state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */
|
||||||
|
|
||||||
|
if (tr == 1)
|
||||||
|
state_ptr->ap = 256;
|
||||||
|
else if (y < 1536) /* SUBTC */
|
||||||
|
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
|
||||||
|
else if (state_ptr->td == 1)
|
||||||
|
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
|
||||||
|
else if (abs((state_ptr->dms << 2) - state_ptr->dml) >=
|
||||||
|
(state_ptr->dml >> 3))
|
||||||
|
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
|
||||||
|
else
|
||||||
|
state_ptr->ap += (-state_ptr->ap) >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maps G.721 code word to reconstructed scale factor normalized log
|
||||||
|
* magnitude values.
|
||||||
|
*/
|
||||||
|
static short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425,
|
||||||
|
425, 373, 323, 273, 213, 135, 4, -2048};
|
||||||
|
|
||||||
|
/* Maps G.721 code word to log of scale factor multiplier. */
|
||||||
|
static short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122,
|
||||||
|
1122, 355, 198, 112, 64, 41, 18, -12};
|
||||||
|
/*
|
||||||
|
* Maps G.721 code words to a set of values whose long and short
|
||||||
|
* term averages are computed and then compared to give an indication
|
||||||
|
* how stationary (steady state) the signal is.
|
||||||
|
*/
|
||||||
|
static short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00,
|
||||||
|
0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0};
|
||||||
|
/*
|
||||||
|
* g721_decoder()
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Decodes a 4-bit code of G.721 encoded data of i and
|
||||||
|
* returns the resulting linear PCM, A-law or u-law value.
|
||||||
|
* return -1 for unknown out_coding value.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
g721_decoder(int i,
|
||||||
|
struct g72x_state *state_ptr)
|
||||||
|
{
|
||||||
|
short sezi, sei, sez, se; /* ACCUM */
|
||||||
|
short y; /* MIX */
|
||||||
|
short sr; /* ADDB */
|
||||||
|
short dq;
|
||||||
|
short dqsez;
|
||||||
|
|
||||||
|
i &= 0x0f; /* mask to get proper bits */
|
||||||
|
sezi = predictor_zero(state_ptr);
|
||||||
|
sez = sezi >> 1;
|
||||||
|
sei = sezi + predictor_pole(state_ptr);
|
||||||
|
se = sei >> 1; /* se = estimated signal */
|
||||||
|
|
||||||
|
y = step_size(state_ptr); /* dynamic quantizer step size */
|
||||||
|
|
||||||
|
dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */
|
||||||
|
|
||||||
|
sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */
|
||||||
|
|
||||||
|
dqsez = sr - se + sez; /* pole prediction diff. */
|
||||||
|
|
||||||
|
update(y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
|
||||||
|
|
||||||
|
return (sr << 2); /* sr was 14-bit dynamic range */
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef _g721_h
|
||||||
|
#define _g721_h
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct g72x_state {
|
||||||
|
long yl; /* Locked or steady state step size multiplier. */
|
||||||
|
short yu; /* Unlocked or non-steady state step size multiplier. */
|
||||||
|
short dms; /* Short term energy estimate. */
|
||||||
|
short dml; /* Long term energy estimate. */
|
||||||
|
short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */
|
||||||
|
|
||||||
|
short a[2]; /* Coefficients of pole portion of prediction filter. */
|
||||||
|
short b[6]; /* Coefficients of zero portion of prediction filter. */
|
||||||
|
short pk[2]; /*
|
||||||
|
* Signs of previous two samples of a partially
|
||||||
|
* reconstructed signal.
|
||||||
|
*/
|
||||||
|
short dq[6]; /*
|
||||||
|
* Previous 6 samples of the quantized difference
|
||||||
|
* signal represented in an internal floating point
|
||||||
|
* format.
|
||||||
|
*/
|
||||||
|
short sr[2]; /*
|
||||||
|
* Previous 2 samples of the quantized difference
|
||||||
|
* signal represented in an internal floating point
|
||||||
|
* format.
|
||||||
|
*/
|
||||||
|
char td; /* delayed tone detect, new in 1988 version */
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
g72x_init_state(struct g72x_state *state_ptr);
|
||||||
|
|
||||||
|
int
|
||||||
|
g721_decoder(int i,
|
||||||
|
struct g72x_state *state_ptr);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,118 @@
|
||||||
|
#include "CDvdFile.hpp"
|
||||||
|
#include "CDvdRequest.hpp"
|
||||||
|
|
||||||
|
namespace urde
|
||||||
|
{
|
||||||
|
|
||||||
|
hecl::ProjectPath CDvdFile::m_DvdRoot;
|
||||||
|
|
||||||
|
class CFileDvdRequest : public IDvdRequest
|
||||||
|
{
|
||||||
|
CDvdFile& m_dvdFile;
|
||||||
|
void* m_buf;
|
||||||
|
u32 m_len;
|
||||||
|
ESeekOrigin m_whence;
|
||||||
|
int m_offset;
|
||||||
|
bool m_cancel = false;
|
||||||
|
bool m_complete = false;
|
||||||
|
public:
|
||||||
|
~CFileDvdRequest()
|
||||||
|
{
|
||||||
|
PostCancelRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitUntilComplete()
|
||||||
|
{
|
||||||
|
while (!m_complete && !m_cancel)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(CDvdFile::m_WorkerMutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool IsComplete() {return m_complete;}
|
||||||
|
void PostCancelRequest()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(CDvdFile::m_WorkerMutex);
|
||||||
|
m_cancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EMediaType GetMediaType() const
|
||||||
|
{
|
||||||
|
return EMediaType::File;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFileDvdRequest(CDvdFile& file, void* buf, u32 len, ESeekOrigin whence, int off)
|
||||||
|
: m_dvdFile(file), m_buf(buf), m_len(len), m_whence(whence), m_offset(off) {}
|
||||||
|
|
||||||
|
void DoRequest()
|
||||||
|
{
|
||||||
|
if (m_cancel)
|
||||||
|
return;
|
||||||
|
if (m_whence == ESeekOrigin::Cur && m_offset == 0)
|
||||||
|
m_dvdFile.m_reader.readBytesToBuf(m_buf, m_len);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_dvdFile.m_reader.seek(m_offset, athena::SeekOrigin(m_whence));
|
||||||
|
m_dvdFile.m_reader.readBytesToBuf(m_buf, m_len);
|
||||||
|
}
|
||||||
|
m_complete = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::thread CDvdFile::m_WorkerThread;
|
||||||
|
std::mutex CDvdFile::m_WorkerMutex;
|
||||||
|
std::condition_variable CDvdFile::m_WorkerCV;
|
||||||
|
bool CDvdFile::m_WorkerRun = false;
|
||||||
|
std::vector<std::shared_ptr<IDvdRequest>> CDvdFile::m_RequestQueue;
|
||||||
|
void CDvdFile::WorkerProc()
|
||||||
|
{
|
||||||
|
while (m_WorkerRun)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(CDvdFile::m_WorkerMutex);
|
||||||
|
if (CDvdFile::m_RequestQueue.size())
|
||||||
|
{
|
||||||
|
std::vector<std::shared_ptr<IDvdRequest>> swapQueue;
|
||||||
|
swapQueue.swap(CDvdFile::m_RequestQueue);
|
||||||
|
lk.unlock();
|
||||||
|
for (std::shared_ptr<IDvdRequest>& req : swapQueue)
|
||||||
|
{
|
||||||
|
CFileDvdRequest& concreteReq = static_cast<CFileDvdRequest&>(*req);
|
||||||
|
concreteReq.DoRequest();
|
||||||
|
}
|
||||||
|
lk.lock();
|
||||||
|
}
|
||||||
|
m_WorkerCV.wait(lk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<IDvdRequest> CDvdFile::AsyncSeekRead(void* buf, u32 len, ESeekOrigin whence, int off)
|
||||||
|
{
|
||||||
|
CFileDvdRequest* req = new CFileDvdRequest(*this, buf, len, whence, off);
|
||||||
|
std::shared_ptr<IDvdRequest> ret(req);
|
||||||
|
std::unique_lock<std::mutex> lk(CDvdFile::m_WorkerMutex);
|
||||||
|
m_RequestQueue.emplace_back(ret);
|
||||||
|
lk.unlock();
|
||||||
|
m_WorkerCV.notify_one();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDvdFile::Initialize(const hecl::ProjectPath& path)
|
||||||
|
{
|
||||||
|
m_DvdRoot = path;
|
||||||
|
if (m_WorkerRun)
|
||||||
|
return;
|
||||||
|
m_WorkerRun = true;
|
||||||
|
m_WorkerThread = std::thread(WorkerProc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDvdFile::Shutdown()
|
||||||
|
{
|
||||||
|
if (!m_WorkerRun)
|
||||||
|
return;
|
||||||
|
m_WorkerRun = false;
|
||||||
|
m_WorkerCV.notify_one();
|
||||||
|
if (m_WorkerThread.joinable())
|
||||||
|
m_WorkerThread.join();
|
||||||
|
m_RequestQueue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,6 +3,10 @@
|
||||||
|
|
||||||
#include "RetroTypes.hpp"
|
#include "RetroTypes.hpp"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
namespace urde
|
namespace urde
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -24,18 +28,51 @@ class IDvdRequest;
|
||||||
class CDvdFile
|
class CDvdFile
|
||||||
{
|
{
|
||||||
friend class CResLoader;
|
friend class CResLoader;
|
||||||
std::string x18_name;
|
friend class CFileDvdRequest;
|
||||||
|
static hecl::ProjectPath m_DvdRoot;
|
||||||
|
static std::thread m_WorkerThread;
|
||||||
|
static std::mutex m_WorkerMutex;
|
||||||
|
static std::condition_variable m_WorkerCV;
|
||||||
|
static bool m_WorkerRun;
|
||||||
|
static std::vector<std::shared_ptr<IDvdRequest>> m_RequestQueue;
|
||||||
|
static void WorkerProc();
|
||||||
|
|
||||||
|
std::string x18_path;
|
||||||
|
athena::io::FileReader m_reader;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CDvdFile(const char*) {}
|
static void Initialize(const hecl::ProjectPath& path);
|
||||||
void UpdateFilePos(int) {}
|
static void Shutdown();
|
||||||
void CalcFileOffset(int, ESeekOrigin) {}
|
|
||||||
|
CDvdFile(const char* path)
|
||||||
|
: x18_path(path), m_reader(hecl::ProjectPath(m_DvdRoot, path).getAbsolutePath()) {}
|
||||||
|
void UpdateFilePos(int pos)
|
||||||
|
{
|
||||||
|
m_reader.seek(pos, athena::SeekOrigin::Begin);
|
||||||
|
}
|
||||||
static void internalCallback(s32, DVDFileInfo*) {}
|
static void internalCallback(s32, DVDFileInfo*) {}
|
||||||
static bool FileExists(const char*) {return false;}
|
static bool FileExists(const char* path)
|
||||||
void CloseFile() {}
|
{
|
||||||
IDvdRequest* AsyncSeekRead(void*, u32, ESeekOrigin, int) {return nullptr;}
|
return hecl::ProjectPath(m_DvdRoot, path).getPathType() != hecl::ProjectPath::Type::File;
|
||||||
void SyncSeekRead(void*, u32, ESeekOrigin, int) {}
|
}
|
||||||
IDvdRequest* AsyncRead(void*, u32) {return nullptr;}
|
void CloseFile()
|
||||||
void SyncRead(void*, u32) {}
|
{
|
||||||
|
m_reader.close();
|
||||||
|
}
|
||||||
|
std::shared_ptr<IDvdRequest> AsyncSeekRead(void* buf, u32 len, ESeekOrigin whence, int off);
|
||||||
|
void SyncSeekRead(void* buf, u32 len, ESeekOrigin whence, int offset)
|
||||||
|
{
|
||||||
|
m_reader.seek(offset, athena::SeekOrigin(whence));
|
||||||
|
m_reader.readBytesToBuf(buf, len);
|
||||||
|
}
|
||||||
|
std::shared_ptr<IDvdRequest> AsyncRead(void* buf, u32 len)
|
||||||
|
{
|
||||||
|
return AsyncSeekRead(buf, len, ESeekOrigin::Cur, 0);
|
||||||
|
}
|
||||||
|
void SyncRead(void* buf, u32 len)
|
||||||
|
{
|
||||||
|
m_reader.readBytesToBuf(buf, len);
|
||||||
|
}
|
||||||
void StallForARAMFile() {}
|
void StallForARAMFile() {}
|
||||||
void StartARAMFileLoad() {}
|
void StartARAMFileLoad() {}
|
||||||
void PopARAMFileLoad() {}
|
void PopARAMFileLoad() {}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
#include "CDvdRequest.hpp"
|
|
||||||
|
|
||||||
namespace urde
|
|
||||||
{
|
|
||||||
|
|
||||||
void CDvdRequest::WaitUntilComplete()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
bool CDvdRequest::IsComplete()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void CDvdRequest::PostCancelRequest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -7,6 +7,8 @@ namespace urde
|
||||||
class IDvdRequest
|
class IDvdRequest
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~IDvdRequest() = default;
|
||||||
|
|
||||||
virtual void WaitUntilComplete()=0;
|
virtual void WaitUntilComplete()=0;
|
||||||
virtual bool IsComplete()=0;
|
virtual bool IsComplete()=0;
|
||||||
virtual void PostCancelRequest()=0;
|
virtual void PostCancelRequest()=0;
|
||||||
|
@ -15,28 +17,12 @@ public:
|
||||||
{
|
{
|
||||||
ARAM = 0,
|
ARAM = 0,
|
||||||
Real = 1,
|
Real = 1,
|
||||||
NOD = 2
|
File = 2,
|
||||||
|
NOD = 3
|
||||||
};
|
};
|
||||||
virtual EMediaType GetMediaType() const=0;
|
virtual EMediaType GetMediaType() const=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CNODDvdRequest : public IDvdRequest
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void WaitUntilComplete();
|
|
||||||
bool IsComplete();
|
|
||||||
void PostCancelRequest();
|
|
||||||
EMediaType GetMediaType() const {return EMediaType::NOD;}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CDvdRequest : public IDvdRequest
|
|
||||||
{
|
|
||||||
void WaitUntilComplete();
|
|
||||||
bool IsComplete();
|
|
||||||
void PostCancelRequest();
|
|
||||||
EMediaType GetMediaType() const { return EMediaType::Real; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __PSHAG_CDVDREQUEST_HPP__
|
#endif // __PSHAG_CDVDREQUEST_HPP__
|
||||||
|
|
|
@ -32,8 +32,8 @@ add_library(RuntimeCommon
|
||||||
CRandom16.hpp CRandom16.cpp
|
CRandom16.hpp CRandom16.cpp
|
||||||
CResFactory.hpp CResFactory.cpp
|
CResFactory.hpp CResFactory.cpp
|
||||||
CResLoader.hpp CResLoader.cpp
|
CResLoader.hpp CResLoader.cpp
|
||||||
CDvdRequest.hpp CNODDvdRequest.cpp
|
CDvdRequest.hpp
|
||||||
CDvdFile.hpp CNODDvdFile.cpp
|
CDvdFile.hpp CDvdFile.cpp
|
||||||
CVirtualDvdFile.hpp CVirtualDvdFile.cpp
|
CVirtualDvdFile.hpp CVirtualDvdFile.cpp
|
||||||
IObjectStore.hpp
|
IObjectStore.hpp
|
||||||
CSimplePool.hpp CSimplePool.cpp
|
CSimplePool.hpp CSimplePool.cpp
|
||||||
|
@ -63,7 +63,6 @@ add_library(RuntimeCommon
|
||||||
CMFGameBase.hpp
|
CMFGameBase.hpp
|
||||||
CInGameTweakManagerBase.hpp
|
CInGameTweakManagerBase.hpp
|
||||||
CPlayMovieBase.hpp
|
CPlayMovieBase.hpp
|
||||||
CMoviePlayer.hpp CMoviePlayer.cpp
|
|
||||||
CGameDebug.hpp CGameDebug.cpp
|
CGameDebug.hpp CGameDebug.cpp
|
||||||
rstl.hpp rstl.cpp
|
rstl.hpp rstl.cpp
|
||||||
GameGlobalObjects.hpp
|
GameGlobalObjects.hpp
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
#include "CMoviePlayer.hpp"
|
|
||||||
|
|
||||||
namespace urde
|
|
||||||
{
|
|
||||||
|
|
||||||
CMoviePlayer::CMoviePlayer(const char* path, float startTime, bool flag)
|
|
||||||
: CDvdFile(path)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMoviePlayer::VerifyCallbackStatus()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::DisableStaticAudio()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::SetStaticAudioVolume(int vol)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::SetStaticAudio(const void* data, u32 length, u32 loopStart, u32 loopEnd)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::MixAudio(short* out, const short* in, u32 length)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::MixStaticAudio(short* out, const short* in, u32 length)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::StaticMyAudioCallback()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::Rewind()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CMoviePlayer::GetIsMovieFinishedPlaying() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool CMoviePlayer::GetIsFullyCached() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
float CMoviePlayer::GetPlayedSeconds() const
|
|
||||||
{
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
float CMoviePlayer::GetTotalSeconds() const
|
|
||||||
{
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
void CMoviePlayer::SetPlayMode(EPlayMode mode)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::DrawFrame(const CVector3f& a, const CVector3f& b,
|
|
||||||
const CVector3f& c, const CVector3f& d)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::Update(float dt)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::DecodeFromRead(const void* data)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::ReadCompleted()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::PostDVDReadRequestIfNeeded()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void CMoviePlayer::InitializeTextures()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
#ifndef __PSHAG_CMOVIEPLAYER_HPP__
|
|
||||||
#define __PSHAG_CMOVIEPLAYER_HPP__
|
|
||||||
|
|
||||||
#include "RetroTypes.hpp"
|
|
||||||
#include "CDvdFile.hpp"
|
|
||||||
|
|
||||||
namespace urde
|
|
||||||
{
|
|
||||||
class CVector3f;
|
|
||||||
|
|
||||||
class CMoviePlayer : public CDvdFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class EPlayMode
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
CMoviePlayer(const char* path, float startTime, bool flag);
|
|
||||||
|
|
||||||
static void VerifyCallbackStatus();
|
|
||||||
static void DisableStaticAudio();
|
|
||||||
static void SetStaticAudioVolume(int vol);
|
|
||||||
static void SetStaticAudio(const void* data, u32 length, u32 loopStart, u32 loopEnd);
|
|
||||||
void MixAudio(short* out, const short* in, u32 length);
|
|
||||||
static void MixStaticAudio(short* out, const short* in, u32 length);
|
|
||||||
static void StaticMyAudioCallback();
|
|
||||||
void Rewind();
|
|
||||||
|
|
||||||
bool GetIsMovieFinishedPlaying() const;
|
|
||||||
bool GetIsFullyCached() const;
|
|
||||||
float GetPlayedSeconds() const;
|
|
||||||
float GetTotalSeconds() const;
|
|
||||||
void SetPlayMode(EPlayMode);
|
|
||||||
void DrawFrame(const CVector3f& a, const CVector3f& b, const CVector3f& c, const CVector3f& d);
|
|
||||||
void Update(float dt);
|
|
||||||
void DecodeFromRead(const void* data);
|
|
||||||
void ReadCompleted();
|
|
||||||
void PostDVDReadRequestIfNeeded();
|
|
||||||
void InitializeTextures();
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __PSHAG_CMOVIEPLAYER_HPP__
|
|
|
@ -1,17 +0,0 @@
|
||||||
#include "CDvdRequest.hpp"
|
|
||||||
|
|
||||||
namespace urde
|
|
||||||
{
|
|
||||||
|
|
||||||
void CNODDvdRequest::WaitUntilComplete()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
bool CNODDvdRequest::IsComplete()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void CNODDvdRequest::PostCancelRequest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define __PSHAG_CPLAYMOVIEBASE_HPP__
|
#define __PSHAG_CPLAYMOVIEBASE_HPP__
|
||||||
|
|
||||||
#include "CIOWin.hpp"
|
#include "CIOWin.hpp"
|
||||||
#include "CMoviePlayer.hpp"
|
#include "Graphics/CMoviePlayer.hpp"
|
||||||
|
|
||||||
namespace urde
|
namespace urde
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@ class CPlayMovieBase : public CIOWin
|
||||||
CMoviePlayer x18_moviePlayer;
|
CMoviePlayer x18_moviePlayer;
|
||||||
public:
|
public:
|
||||||
CPlayMovieBase(const char* iowName, const char* path)
|
CPlayMovieBase(const char* iowName, const char* path)
|
||||||
: CIOWin(iowName), x18_moviePlayer(path, 0.0, false) {}
|
: CIOWin(iowName), x18_moviePlayer(path, 0.0, false, false) {}
|
||||||
EMessageReturn OnMessage(const CArchitectureMessage&, CArchitectureQueue&) {return EMessageReturn::Normal;}
|
EMessageReturn OnMessage(const CArchitectureMessage&, CArchitectureQueue&) {return EMessageReturn::Normal;}
|
||||||
void Draw() const {}
|
void Draw() const {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ const std::vector<u32>* CResLoader::GetTagListForFile(const std::string& name) c
|
||||||
{
|
{
|
||||||
std::string namePak = name + ".pak";
|
std::string namePak = name + ".pak";
|
||||||
for (const std::unique_ptr<CPakFile>& pak : x1c_pakLoadedList)
|
for (const std::unique_ptr<CPakFile>& pak : x1c_pakLoadedList)
|
||||||
if (!CStringExtras::CompareCaseInsensitive(namePak, pak->x18_name))
|
if (!CStringExtras::CompareCaseInsensitive(namePak, pak->x18_path))
|
||||||
return &pak->GetDepList();
|
return &pak->GetDepList();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -100,13 +100,13 @@ CInputStream* CResLoader::LoadNewResourceSync(const SObjectTag& tag, void* extBu
|
||||||
return newStrm;
|
return newStrm;
|
||||||
}
|
}
|
||||||
|
|
||||||
IDvdRequest* CResLoader::LoadResourcePartAsync(const SObjectTag& tag, int offset, int length, void* buf)
|
std::shared_ptr<IDvdRequest> CResLoader::LoadResourcePartAsync(const SObjectTag& tag, int offset, int length, void* buf)
|
||||||
{
|
{
|
||||||
return FindResourceForLoad(tag.id)->AsyncSeekRead(buf, length,
|
return FindResourceForLoad(tag.id)->AsyncSeekRead(buf, length,
|
||||||
ESeekOrigin::Begin, x50_cachedResInfo->x4_offset + offset);
|
ESeekOrigin::Begin, x50_cachedResInfo->x4_offset + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
IDvdRequest* CResLoader::LoadResourceAsync(const SObjectTag& tag, void* buf)
|
std::shared_ptr<IDvdRequest> CResLoader::LoadResourceAsync(const SObjectTag& tag, void* buf)
|
||||||
{
|
{
|
||||||
return FindResourceForLoad(tag.id)->AsyncSeekRead(buf, ROUND_UP_32(x50_cachedResInfo->x8_size),
|
return FindResourceForLoad(tag.id)->AsyncSeekRead(buf, ROUND_UP_32(x50_cachedResInfo->x8_size),
|
||||||
ESeekOrigin::Begin, x50_cachedResInfo->x4_offset);
|
ESeekOrigin::Begin, x50_cachedResInfo->x4_offset);
|
||||||
|
|
|
@ -29,8 +29,8 @@ public:
|
||||||
void LoadMemResourceSync(const SObjectTag& tag, void** bufOut, int* sizeOut);
|
void LoadMemResourceSync(const SObjectTag& tag, void** bufOut, int* sizeOut);
|
||||||
CInputStream* LoadResourceFromMemorySync(const SObjectTag& tag, const void* buf);
|
CInputStream* LoadResourceFromMemorySync(const SObjectTag& tag, const void* buf);
|
||||||
CInputStream* LoadNewResourceSync(const SObjectTag& tag, void* extBuf=nullptr);
|
CInputStream* LoadNewResourceSync(const SObjectTag& tag, void* extBuf=nullptr);
|
||||||
IDvdRequest* LoadResourcePartAsync(const SObjectTag& tag, int offset, int length, void* buf);
|
std::shared_ptr<IDvdRequest> LoadResourcePartAsync(const SObjectTag& tag, int offset, int length, void* buf);
|
||||||
IDvdRequest* LoadResourceAsync(const SObjectTag& tag, void* buf);
|
std::shared_ptr<IDvdRequest> LoadResourceAsync(const SObjectTag& tag, void* buf);
|
||||||
bool GetResourceCompression(const SObjectTag& tag);
|
bool GetResourceCompression(const SObjectTag& tag);
|
||||||
u32 ResourceSize(const SObjectTag& tag);
|
u32 ResourceSize(const SObjectTag& tag);
|
||||||
bool ResourceExists(const SObjectTag& tag);
|
bool ResourceExists(const SObjectTag& tag);
|
||||||
|
|
|
@ -10,6 +10,10 @@ namespace urde
|
||||||
CGraphics::CProjectionState CGraphics::g_Proj;
|
CGraphics::CProjectionState CGraphics::g_Proj;
|
||||||
float CGraphics::g_ProjAspect = 1.f;
|
float CGraphics::g_ProjAspect = 1.f;
|
||||||
u32 CGraphics::g_NumLightsActive = 0;
|
u32 CGraphics::g_NumLightsActive = 0;
|
||||||
|
u32 CGraphics::g_NumBreakpointsWaiting = 0;
|
||||||
|
u32 CGraphics::g_FlippingState;
|
||||||
|
bool CGraphics::g_LastFrameUsedAbove = false;
|
||||||
|
bool CGraphics::g_InterruptLastFrameUsedAbove = false;
|
||||||
ERglLight CGraphics::g_LightActive = ERglLight::None;
|
ERglLight CGraphics::g_LightActive = ERglLight::None;
|
||||||
ERglLight CGraphics::g_LightsWereOn = ERglLight::None;
|
ERglLight CGraphics::g_LightsWereOn = ERglLight::None;
|
||||||
zeus::CTransform CGraphics::g_GXModelView;
|
zeus::CTransform CGraphics::g_GXModelView;
|
||||||
|
@ -61,6 +65,15 @@ void CGraphics::SetCullMode(ERglCullMode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGraphics::EndScene()
|
||||||
|
{
|
||||||
|
/* Spinwait until g_NumBreakpointsWaiting is 0 */
|
||||||
|
/* ++g_NumBreakpointsWaiting; */
|
||||||
|
/* GXCopyDisp to g_CurrenFrameBuf with clear enabled */
|
||||||
|
/* Register next breakpoint with GP FIFO */
|
||||||
|
/* g_LastFrameUsedAbove = g_InterruptLastFrameUsedAbove; */
|
||||||
|
}
|
||||||
|
|
||||||
void CGraphics::SetAlphaCompare(ERglAlphaFunc comp0, u8 ref0, ERglAlphaOp op, ERglAlphaFunc comp1, u8 ref1)
|
void CGraphics::SetAlphaCompare(ERglAlphaFunc comp0, u8 ref0, ERglAlphaOp op, ERglAlphaFunc comp1, u8 ref1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,6 +150,10 @@ public:
|
||||||
static CProjectionState g_Proj;
|
static CProjectionState g_Proj;
|
||||||
static float g_ProjAspect;
|
static float g_ProjAspect;
|
||||||
static u32 g_NumLightsActive;
|
static u32 g_NumLightsActive;
|
||||||
|
static u32 g_NumBreakpointsWaiting;
|
||||||
|
static u32 g_FlippingState;
|
||||||
|
static bool g_LastFrameUsedAbove;
|
||||||
|
static bool g_InterruptLastFrameUsedAbove;
|
||||||
static ERglLight g_LightActive;
|
static ERglLight g_LightActive;
|
||||||
static ERglLight g_LightsWereOn;
|
static ERglLight g_LightsWereOn;
|
||||||
static zeus::CTransform g_GXModelView;
|
static zeus::CTransform g_GXModelView;
|
||||||
|
@ -169,6 +173,7 @@ public:
|
||||||
static void SetDepthWriteMode(bool test, ERglEnum comp, bool write);
|
static void SetDepthWriteMode(bool test, ERglEnum comp, bool write);
|
||||||
static void SetBlendMode(ERglBlendMode, ERglBlendFactor, ERglBlendFactor, ERglLogicOp);
|
static void SetBlendMode(ERglBlendMode, ERglBlendFactor, ERglBlendFactor, ERglLogicOp);
|
||||||
static void SetCullMode(ERglCullMode);
|
static void SetCullMode(ERglCullMode);
|
||||||
|
static void EndScene();
|
||||||
static void SetAlphaCompare(ERglAlphaFunc comp0, u8 ref0, ERglAlphaOp op, ERglAlphaFunc comp1, u8 ref1);
|
static void SetAlphaCompare(ERglAlphaFunc comp0, u8 ref0, ERglAlphaOp op, ERglAlphaFunc comp1, u8 ref1);
|
||||||
static void SetViewPointMatrix(const zeus::CTransform& xf);
|
static void SetViewPointMatrix(const zeus::CTransform& xf);
|
||||||
static void SetViewMatrix();
|
static void SetViewMatrix();
|
||||||
|
|
|
@ -4,6 +4,8 @@ elseif(APPLE)
|
||||||
set(PLAT_SRCS CLineRendererShadersMetal.cpp)
|
set(PLAT_SRCS CLineRendererShadersMetal.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
include_directories(${LIBJPEG_INCLUDE_DIR})
|
||||||
|
|
||||||
add_library(RuntimeCommonGraphics
|
add_library(RuntimeCommonGraphics
|
||||||
IRenderer.hpp
|
IRenderer.hpp
|
||||||
CBooRenderer.hpp CBooRenderer.cpp
|
CBooRenderer.hpp CBooRenderer.cpp
|
||||||
|
@ -13,5 +15,6 @@ add_library(RuntimeCommonGraphics
|
||||||
CLight.hpp CLight.cpp
|
CLight.hpp CLight.cpp
|
||||||
CTexture.hpp CTextureBoo.cpp
|
CTexture.hpp CTextureBoo.cpp
|
||||||
CModel.hpp CModelBoo.cpp
|
CModel.hpp CModelBoo.cpp
|
||||||
|
CMoviePlayer.hpp CMoviePlayer.cpp
|
||||||
CGraphics.hpp CGraphics.cpp
|
CGraphics.hpp CGraphics.cpp
|
||||||
${PLAT_SRCS})
|
${PLAT_SRCS})
|
||||||
|
|
|
@ -0,0 +1,665 @@
|
||||||
|
#include "CMoviePlayer.hpp"
|
||||||
|
#include "boo/graphicsdev/GLSLMacros.hpp"
|
||||||
|
#include "specter/View.hpp"
|
||||||
|
#include "CGraphics.hpp"
|
||||||
|
#include "Audio/g721.h"
|
||||||
|
#include "Audio/dsp.h"
|
||||||
|
#include "CDvdRequest.hpp"
|
||||||
|
#include <turbojpeg.h>
|
||||||
|
|
||||||
|
#define THP_BUFFER_FRAMES 30
|
||||||
|
|
||||||
|
namespace urde
|
||||||
|
{
|
||||||
|
|
||||||
|
static const char* VS_GLSL_YUV =
|
||||||
|
"#version 330\n"
|
||||||
|
BOO_GLSL_BINDING_HEAD
|
||||||
|
"layout(location=0) in vec3 posIn;\n"
|
||||||
|
"layout(location=1) in vec2 uvIn;\n"
|
||||||
|
SPECTER_GLSL_VIEW_VERT_BLOCK
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" vec4 color;\n"
|
||||||
|
" vec2 uv;\n"
|
||||||
|
"};\n"
|
||||||
|
"out VertToFrag vtf;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" vtf.uv = uvIn;\n"
|
||||||
|
" vtf.color = mulColor;\n"
|
||||||
|
" gl_Position = mv * vec4(posIn, 1.0);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static const char* FS_GLSL_YUV =
|
||||||
|
"#version 330\n"
|
||||||
|
BOO_GLSL_BINDING_HEAD
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" vec4 color;\n"
|
||||||
|
" vec2 uv;\n"
|
||||||
|
"};\n"
|
||||||
|
"in VertToFrag vtf;\n"
|
||||||
|
"TBINDING0 uniform sampler2D texs[3];\n"
|
||||||
|
"layout(location=0) out vec4 colorOut;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" vec3 yuv;\n"
|
||||||
|
" yuv.r = texture(texs[0], vtf.uv).r;\n"
|
||||||
|
" yuv.g = texture(texs[1], vtf.uv).r;\n"
|
||||||
|
" yuv.b = texture(texs[2], vtf.uv).r;\n"
|
||||||
|
" yuv.r = 1.1643*(yuv.r-0.0625);\n"
|
||||||
|
" yuv.g = yuv.g-0.5;\n"
|
||||||
|
" yuv.b = yuv.b-0.5;\n"
|
||||||
|
" colorOut = vec4(yuv.r+1.5958*yuv.b, yuv.r-0.39173*yuv.g-0.81290*yuv.b, yuv.r+2.017*yuv.g, 1.0) * vtf.color;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static const char* VS_HLSL_YUV =
|
||||||
|
"struct VertData\n"
|
||||||
|
"{\n"
|
||||||
|
" float3 posIn : POSITION;\n"
|
||||||
|
" float2 uvIn : UV;\n"
|
||||||
|
"};\n"
|
||||||
|
SPECTER_HLSL_VIEW_VERT_BLOCK
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" float4 position : SV_Position;\n"
|
||||||
|
" float4 color : COLOR;\n"
|
||||||
|
" float2 uv : UV;\n"
|
||||||
|
"};\n"
|
||||||
|
"VertToFrag main(in VertData v)\n"
|
||||||
|
"{\n"
|
||||||
|
" VertToFrag vtf;\n"
|
||||||
|
" vtf.uv = v.uvIn;\n"
|
||||||
|
" vtf.color = mulColor;\n"
|
||||||
|
" vtf.position = mul(mv, float4(v.posIn, 1.0));\n"
|
||||||
|
" return vtf;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static const char* FS_HLSL_YUV =
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" float4 position : SV_Position;\n"
|
||||||
|
" float4 color : COLOR;\n"
|
||||||
|
" float2 uv : UV;\n"
|
||||||
|
"};\n"
|
||||||
|
"Texture2D texs[3] : register(t0);\n"
|
||||||
|
"SamplerState samp : register(s0);\n"
|
||||||
|
"float4 main(in VertToFrag vtf) : SV_Target0\n"
|
||||||
|
"{\n"
|
||||||
|
" float3 yuv;\n"
|
||||||
|
" yuv.r = texs[0].Sample(samp, vtf.uv).r;\n"
|
||||||
|
" yuv.g = texs[1].Sample(samp, vtf.uv).r;\n"
|
||||||
|
" yuv.b = texs[2].Sample(samp, vtf.uv).r;\n"
|
||||||
|
" yuv.r = 1.1643*(yuv.r-0.0625);\n"
|
||||||
|
" yuv.g = yuv.g-0.5;\n"
|
||||||
|
" yuv.b = yuv.b-0.5;\n"
|
||||||
|
" return float4(yuv.r+1.5958*yuv.b, yuv.r-0.39173*yuv.g-0.81290*yuv.b, yuv.r+2.017*yuv.g, 1.0) * vtf.color;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static const char* VS_METAL_YUV =
|
||||||
|
"#include <metal_stdlib>\n"
|
||||||
|
"using namespace metal;\n"
|
||||||
|
"struct VertData\n"
|
||||||
|
"{\n"
|
||||||
|
" float3 posIn [[ attribute(0) ]];\n"
|
||||||
|
" float2 uvIn [[ attribute(1) ]];\n"
|
||||||
|
"};\n"
|
||||||
|
SPECTER_METAL_VIEW_VERT_BLOCK
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" float4 position [[ position ]];\n"
|
||||||
|
" float4 color;\n"
|
||||||
|
" float2 uv;\n"
|
||||||
|
"};\n"
|
||||||
|
"vertex VertToFrag vmain(VertData v [[ stage_in ]], constant SpecterViewBlock& view [[ buffer(2) ]])\n"
|
||||||
|
"{\n"
|
||||||
|
" VertToFrag vtf;\n"
|
||||||
|
" vtf.uv = v.uvIn;\n"
|
||||||
|
" vtf.color = view.mulColor;\n"
|
||||||
|
" vtf.position = view.mv * float4(v.posIn, 1.0);\n"
|
||||||
|
" return vtf;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static const char* FS_METAL_YUV =
|
||||||
|
"#include <metal_stdlib>\n"
|
||||||
|
"using namespace metal;\n"
|
||||||
|
"constexpr sampler samp(address::repeat);\n"
|
||||||
|
"struct VertToFrag\n"
|
||||||
|
"{\n"
|
||||||
|
" float4 position [[ position ]];\n"
|
||||||
|
" float4 color;\n"
|
||||||
|
" float2 uv;\n"
|
||||||
|
"};\n"
|
||||||
|
"fragment float4 fmain(VertToFrag vtf [[ stage_in ]],"
|
||||||
|
" texture2d<float> tex0 [[ texture(0) ]],\n"
|
||||||
|
" texture2d<float> tex1 [[ texture(1) ]],\n"
|
||||||
|
" texture2d<float> tex2 [[ texture(2) ]])\n"
|
||||||
|
"{\n"
|
||||||
|
" float3 yuv;\n"
|
||||||
|
" yuv.r = tex0.sample(samp, vtf.uv).r;\n"
|
||||||
|
" yuv.g = tex1.sample(samp, vtf.uv).r;\n"
|
||||||
|
" yuv.b = tex2.sample(samp, vtf.uv).r;\n"
|
||||||
|
" yuv.r = 1.1643*(yuv.r-0.0625);\n"
|
||||||
|
" yuv.g = yuv.g-0.5;\n"
|
||||||
|
" yuv.b = yuv.b-0.5;\n"
|
||||||
|
" return float4(yuv.r+1.5958*yuv.b, yuv.r-0.39173*yuv.g-0.81290*yuv.b, yuv.r+2.017*yuv.g, 1.0) * vtf.color;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static boo::GraphicsDataToken GraphicsData;
|
||||||
|
static boo::IVertexFormat* YUVVTXFmt = nullptr;
|
||||||
|
static boo::IShaderPipeline* YUVShaderPipeline = nullptr;
|
||||||
|
static tjhandle TjHandle = nullptr;
|
||||||
|
|
||||||
|
void CMoviePlayer::Initialize()
|
||||||
|
{
|
||||||
|
static const char* BlockNames[] = {"SpecterViewBlock"};
|
||||||
|
|
||||||
|
if (!CGraphics::g_BooFactory->bindingNeedsVertexFormat())
|
||||||
|
{
|
||||||
|
boo::VertexElementDescriptor texvdescs[] =
|
||||||
|
{
|
||||||
|
{nullptr, nullptr, boo::VertexSemantic::Position4},
|
||||||
|
{nullptr, nullptr, boo::VertexSemantic::UV4}
|
||||||
|
};
|
||||||
|
YUVVTXFmt = CGraphics::g_BooFactory->newVertexFormat(2, texvdescs);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (CGraphics::g_BooFactory->platform())
|
||||||
|
{
|
||||||
|
case boo::IGraphicsDataFactory::Platform::OGL:
|
||||||
|
YUVShaderPipeline = static_cast<boo::GLDataFactory*>(CGraphics::g_BooFactory)->newShaderPipeline
|
||||||
|
(VS_GLSL_YUV, FS_GLSL_YUV, 3, "texs", 1, BlockNames,
|
||||||
|
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||||
|
false, false, false);
|
||||||
|
break;
|
||||||
|
#if _WIN32
|
||||||
|
case boo::IGraphicsDataFactory::Platform::D3D11:
|
||||||
|
case boo::IGraphicsDataFactory::Platform::D3D12:
|
||||||
|
YUVShaderPipeline = static_cast<boo::ID3DDataFactory*>(CGraphics::g_BooFactory)->newShaderPipeline
|
||||||
|
(VS_HLSL_YUV, FS_HLSL_YUV, ComPtr<ID3DBlob>(), ComPtr<ID3DBlob>(), ComPtr<ID3DBlob>(), YUVVTXFmt,
|
||||||
|
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||||
|
false, false, false);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if BOO_HAS_METAL
|
||||||
|
case boo::IGraphicsDataFactory::Platform::Metal:
|
||||||
|
YUVShaderPipeline = static_cast<boo::MetalDataFactory*>(CGraphics::g_BooFactory)->newShaderPipeline
|
||||||
|
(VS_METAL_YUV, FS_METAL_YUV, YUVVTXFmt, 1,
|
||||||
|
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||||
|
false, false, false);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if BOO_HAS_VULKAN
|
||||||
|
case boo::IGraphicsDataFactory::Platform::Vulkan:
|
||||||
|
YUVShaderPipeline = static_cast<boo::VulkanDataFactory*>(CGraphics::g_BooFactory)->newShaderPipeline
|
||||||
|
(VS_GLSL_YUV, FS_GLSL_YUV, YUVVTXFmt,
|
||||||
|
boo::BlendFactor::SrcAlpha, boo::BlendFactor::InvSrcAlpha,
|
||||||
|
false, false, false);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphicsData = CGraphics::CommitResources();
|
||||||
|
TjHandle = tjInitDecompress();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::Shutdown()
|
||||||
|
{
|
||||||
|
GraphicsData.doDestroy();
|
||||||
|
tjDestroy(TjHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::THPHeader::swapBig()
|
||||||
|
{
|
||||||
|
magic = hecl::SBig(magic);
|
||||||
|
version = hecl::SBig(version);
|
||||||
|
maxBufferSize = hecl::SBig(maxBufferSize);
|
||||||
|
maxAudioSamples = hecl::SBig(maxAudioSamples);
|
||||||
|
fps = hecl::SBig(fps);
|
||||||
|
numFrames = hecl::SBig(numFrames);
|
||||||
|
firstFrameSize = hecl::SBig(firstFrameSize);
|
||||||
|
dataSize = hecl::SBig(dataSize);
|
||||||
|
componentDataOffset = hecl::SBig(componentDataOffset);
|
||||||
|
offsetsDataOffset = hecl::SBig(offsetsDataOffset);
|
||||||
|
firstFrameOffset = hecl::SBig(firstFrameOffset);
|
||||||
|
lastFrameOffset = hecl::SBig(lastFrameOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::THPComponents::swapBig()
|
||||||
|
{
|
||||||
|
numComponents = hecl::SBig(numComponents);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::THPVideoInfo::swapBig()
|
||||||
|
{
|
||||||
|
width = hecl::SBig(width);
|
||||||
|
height = hecl::SBig(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::THPAudioInfo::swapBig()
|
||||||
|
{
|
||||||
|
numChannels = hecl::SBig(numChannels);
|
||||||
|
sampleRate = hecl::SBig(sampleRate);
|
||||||
|
numSamples = hecl::SBig(numSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::THPFrameHeader::swapBig()
|
||||||
|
{
|
||||||
|
nextSize = hecl::SBig(nextSize);
|
||||||
|
prevSize = hecl::SBig(prevSize);
|
||||||
|
imageSize = hecl::SBig(imageSize);
|
||||||
|
audioSize = hecl::SBig(audioSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::THPAudioFrameHeader::swapBig()
|
||||||
|
{
|
||||||
|
channelSize = hecl::SBig(channelSize);
|
||||||
|
numSamples = hecl::SBig(numSamples);
|
||||||
|
for (int i=0 ; i<2 ; ++i)
|
||||||
|
{
|
||||||
|
for (int j=0 ; j<8 ; ++j)
|
||||||
|
{
|
||||||
|
channelCoefs[i][j][0] = hecl::SBig(channelCoefs[i][j][0]);
|
||||||
|
channelCoefs[i][j][1] = hecl::SBig(channelCoefs[i][j][1]);
|
||||||
|
}
|
||||||
|
channelPrevs[i][0] = hecl::SBig(channelPrevs[i][0]);
|
||||||
|
channelPrevs[i][1] = hecl::SBig(channelPrevs[i][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Slightly modified THPAudioDecode present in SDK, always interleaves */
|
||||||
|
u32 CMoviePlayer::THPAudioDecode(s16* buffer, const u8* audioFrame, bool stereo)
|
||||||
|
{
|
||||||
|
THPAudioFrameHeader header = *((const THPAudioFrameHeader*)audioFrame);
|
||||||
|
header.swapBig();
|
||||||
|
audioFrame += sizeof(THPAudioFrameHeader);
|
||||||
|
|
||||||
|
if (stereo)
|
||||||
|
{
|
||||||
|
for (int i=0 ; i<2 ; ++i)
|
||||||
|
{
|
||||||
|
unsigned samples = header.numSamples;
|
||||||
|
s16* bufferCur = buffer+i;
|
||||||
|
const u8* audioFrameCur = audioFrame;
|
||||||
|
int16_t prev1 = header.channelPrevs[i][0];
|
||||||
|
int16_t prev2 = header.channelPrevs[i][1];
|
||||||
|
for (int f=0 ; f<header.channelSize/8 ; ++f)
|
||||||
|
{
|
||||||
|
DSPDecompressFrameStereoStride(bufferCur, audioFrameCur,
|
||||||
|
header.channelCoefs[i], &prev1, &prev2, samples);
|
||||||
|
samples -= 14;
|
||||||
|
bufferCur += 28;
|
||||||
|
audioFrameCur += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned samples = header.numSamples;
|
||||||
|
s16* bufferCur = buffer;
|
||||||
|
const u8* audioFrameCur = audioFrame;
|
||||||
|
int16_t prev1 = header.channelPrevs[0][0];
|
||||||
|
int16_t prev2 = header.channelPrevs[0][1];
|
||||||
|
for (int f=0 ; f<header.channelSize/8 ; ++f)
|
||||||
|
{
|
||||||
|
DSPDecompressFrameStereoDupe(bufferCur, audioFrameCur,
|
||||||
|
header.channelCoefs[0], &prev1, &prev2, samples);
|
||||||
|
samples -= 14;
|
||||||
|
bufferCur += 28;
|
||||||
|
audioFrameCur += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return header.numSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMoviePlayer::CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bool deinterlace)
|
||||||
|
: CDvdFile(path), xec_preLoadSeconds(preLoadSeconds), xf4_24_loop(loop), m_deinterlace(deinterlace)
|
||||||
|
{
|
||||||
|
u8 buf[64];
|
||||||
|
SyncRead(buf, 64);
|
||||||
|
memcpy(&x28_thpHead, buf, 48);
|
||||||
|
x28_thpHead.swapBig();
|
||||||
|
|
||||||
|
u32 cur = x28_thpHead.componentDataOffset;
|
||||||
|
SyncSeekRead(buf, 32, ESeekOrigin::Begin, cur);
|
||||||
|
memcpy(&x58_thpComponents, buf, 20);
|
||||||
|
cur += 20;
|
||||||
|
x58_thpComponents.swapBig();
|
||||||
|
|
||||||
|
for (int i=0 ; i<x58_thpComponents.numComponents ; ++i)
|
||||||
|
{
|
||||||
|
switch (x58_thpComponents.comps[i])
|
||||||
|
{
|
||||||
|
case THPComponents::Type::Video:
|
||||||
|
SyncSeekRead(buf, 32, ESeekOrigin::Begin, cur);
|
||||||
|
memcpy(&x6c_videoInfo, buf, 8);
|
||||||
|
cur += 8;
|
||||||
|
x6c_videoInfo.swapBig();
|
||||||
|
break;
|
||||||
|
case THPComponents::Type::Audio:
|
||||||
|
SyncSeekRead(buf, 32, ESeekOrigin::Begin, cur);
|
||||||
|
memcpy(&x74_audioInfo, buf, 12);
|
||||||
|
cur += 12;
|
||||||
|
x74_audioInfo.swapBig();
|
||||||
|
xf4_25_hasAudio = true;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xe4_totalSeconds = x28_thpHead.numFrames / x28_thpHead.fps;
|
||||||
|
if (xec_preLoadSeconds < 0.f)
|
||||||
|
{
|
||||||
|
/* Load whole video */
|
||||||
|
xec_preLoadSeconds = xe4_totalSeconds;
|
||||||
|
xf0_preLoadFrames = x28_thpHead.numFrames;
|
||||||
|
}
|
||||||
|
else if (xec_preLoadSeconds > 0.f)
|
||||||
|
{
|
||||||
|
/* Pre-load video portion */
|
||||||
|
u32 frame = xec_preLoadSeconds * x28_thpHead.fps;
|
||||||
|
xf0_preLoadFrames = std::min(frame, x28_thpHead.numFrames);
|
||||||
|
xec_preLoadSeconds = std::min(xe4_totalSeconds, xec_preLoadSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xf0_preLoadFrames > 0)
|
||||||
|
xa0_bufferQueue.reserve(xf0_preLoadFrames);
|
||||||
|
|
||||||
|
m_blockBuf = CGraphics::g_BooFactory->newDynamicBuffer(boo::BufferUse::Vertex, sizeof(m_viewVertBlock), 1);
|
||||||
|
|
||||||
|
boo::IVertexFormat* vtxFmt = YUVVTXFmt;
|
||||||
|
if (CGraphics::g_BooFactory->bindingNeedsVertexFormat())
|
||||||
|
{
|
||||||
|
boo::VertexElementDescriptor texvdescs[] =
|
||||||
|
{
|
||||||
|
{m_blockBuf, nullptr, boo::VertexSemantic::Position4},
|
||||||
|
{m_blockBuf, nullptr, boo::VertexSemantic::UV4}
|
||||||
|
};
|
||||||
|
vtxFmt = CGraphics::g_BooFactory->newVertexFormat(2, texvdescs);
|
||||||
|
}
|
||||||
|
|
||||||
|
x80_textures.reserve(3);
|
||||||
|
for (int i=0 ; i<3 ; ++i)
|
||||||
|
{
|
||||||
|
x80_textures.emplace_back();
|
||||||
|
CTHPTextureSet& set = x80_textures.back();
|
||||||
|
if (deinterlace)
|
||||||
|
{
|
||||||
|
set.Y[0] = CGraphics::g_BooFactory->newDynamicTexture(x6c_videoInfo.width,
|
||||||
|
x6c_videoInfo.height / 2,
|
||||||
|
boo::TextureFormat::I8);
|
||||||
|
set.Y[1] = CGraphics::g_BooFactory->newDynamicTexture(x6c_videoInfo.width,
|
||||||
|
x6c_videoInfo.height / 2,
|
||||||
|
boo::TextureFormat::I8);
|
||||||
|
set.U = CGraphics::g_BooFactory->newDynamicTexture(x6c_videoInfo.width / 2,
|
||||||
|
x6c_videoInfo.height / 2,
|
||||||
|
boo::TextureFormat::I8);
|
||||||
|
set.V = CGraphics::g_BooFactory->newDynamicTexture(x6c_videoInfo.width / 2,
|
||||||
|
x6c_videoInfo.height / 2,
|
||||||
|
boo::TextureFormat::I8);
|
||||||
|
|
||||||
|
boo::IGraphicsBuffer* bufs[] = {m_blockBuf};
|
||||||
|
for (int j=0 ; j<2 ; ++j)
|
||||||
|
{
|
||||||
|
boo::ITexture* texs[] = {set.Y[j], set.U, set.V};
|
||||||
|
set.binding[j] = CGraphics::g_BooFactory->newShaderDataBinding(YUVShaderPipeline, vtxFmt, m_blockBuf,
|
||||||
|
nullptr, nullptr, 1, bufs, 3, texs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set.Y[0] = CGraphics::g_BooFactory->newDynamicTexture(x6c_videoInfo.width,
|
||||||
|
x6c_videoInfo.height,
|
||||||
|
boo::TextureFormat::I8);
|
||||||
|
set.U = CGraphics::g_BooFactory->newDynamicTexture(x6c_videoInfo.width / 2,
|
||||||
|
x6c_videoInfo.height / 2,
|
||||||
|
boo::TextureFormat::I8);
|
||||||
|
set.V = CGraphics::g_BooFactory->newDynamicTexture(x6c_videoInfo.width / 2,
|
||||||
|
x6c_videoInfo.height / 2,
|
||||||
|
boo::TextureFormat::I8);
|
||||||
|
|
||||||
|
boo::IGraphicsBuffer* bufs[] = {m_blockBuf};
|
||||||
|
boo::ITexture* texs[] = {set.Y[0], set.U, set.V};
|
||||||
|
set.binding[0] = CGraphics::g_BooFactory->newShaderDataBinding(YUVShaderPipeline, vtxFmt, m_blockBuf,
|
||||||
|
nullptr, nullptr, 1, bufs, 3, texs);
|
||||||
|
}
|
||||||
|
if (xf4_25_hasAudio)
|
||||||
|
set.audioBuf.reset(new s16[x28_thpHead.maxAudioSamples * 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_yuvBuf.reset(new uint8_t[tjBufSizeYUV(x6c_videoInfo.width, x6c_videoInfo.height, TJ_420)]);
|
||||||
|
|
||||||
|
m_token = CGraphics::CommitResources();
|
||||||
|
PostDVDReadRequestIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::VerifyCallbackStatus()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void CMoviePlayer::DisableStaticAudio()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void CMoviePlayer::SetStaticAudioVolume(int vol)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void CMoviePlayer::SetStaticAudio(const void* data, u32 length, u32 loopStart, u32 loopEnd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void CMoviePlayer::MixAudio(short* out, const short* in, u32 length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void CMoviePlayer::MixStaticAudio(short* out, const short* in, u32 length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void CMoviePlayer::StaticMyAudioCallback()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void CMoviePlayer::Rewind()
|
||||||
|
{
|
||||||
|
if (x98_request)
|
||||||
|
{
|
||||||
|
x98_request->PostCancelRequest();
|
||||||
|
x98_request.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
xb0_nextReadSize = x28_thpHead.firstFrameSize;
|
||||||
|
xb4_nextReadOff = x28_thpHead.firstFrameOffset;
|
||||||
|
xb8_readSize = x28_thpHead.firstFrameSize;
|
||||||
|
xbc_readOff = x28_thpHead.firstFrameOffset;
|
||||||
|
|
||||||
|
xc0_loadedFrames = 0;
|
||||||
|
xc4_ = 0;
|
||||||
|
xc8_curFrame = 0;
|
||||||
|
xcc_decodedTexSlot = 0;
|
||||||
|
xd0_ = -1;
|
||||||
|
xd4_ = -1;
|
||||||
|
xd8_ = 0;
|
||||||
|
xdc_frameRem = 0.f;
|
||||||
|
xe8_curSeconds = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::DrawFrame(const CVector3f& a, const CVector3f& b,
|
||||||
|
const CVector3f& c, const CVector3f& d)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::Update(float dt)
|
||||||
|
{
|
||||||
|
if (xc0_loadedFrames < xf0_preLoadFrames)
|
||||||
|
{
|
||||||
|
if (x98_request && x98_request->IsComplete())
|
||||||
|
{
|
||||||
|
ReadCompleted();
|
||||||
|
if (xc0_loadedFrames >= xa0_bufferQueue.size() &&
|
||||||
|
xc0_loadedFrames < xf0_preLoadFrames &&
|
||||||
|
xa0_bufferQueue.size() < x28_thpHead.numFrames)
|
||||||
|
{
|
||||||
|
PostDVDReadRequestIfNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (x98_request)
|
||||||
|
{
|
||||||
|
bool flag = false;
|
||||||
|
if (xc4_ >= xa0_bufferQueue.size() && xc0_loadedFrames >= xa0_bufferQueue.size())
|
||||||
|
flag = true;
|
||||||
|
if (x98_request->IsComplete() && xd8_ < 2 && flag)
|
||||||
|
{
|
||||||
|
DecodeFromRead(x90_requestBuf.get());
|
||||||
|
ReadCompleted();
|
||||||
|
PostDVDReadRequestIfNeeded();
|
||||||
|
++xd8_;
|
||||||
|
++xc4_;
|
||||||
|
if (xc4_ >= x28_thpHead.numFrames && xf4_24_loop)
|
||||||
|
xc4_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!x98_request && xe0_playMode == EPlayMode::Playing &&
|
||||||
|
xa0_bufferQueue.size() < x28_thpHead.numFrames)
|
||||||
|
{
|
||||||
|
PostDVDReadRequestIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xd8_ < 2)
|
||||||
|
{
|
||||||
|
if (xe0_playMode == EPlayMode::Playing && xc4_ < xf0_preLoadFrames)
|
||||||
|
{
|
||||||
|
u32 minFrame = std::min(u32(xa0_bufferQueue.size()) - 1, xc4_);
|
||||||
|
if (minFrame == -1)
|
||||||
|
return;
|
||||||
|
std::unique_ptr<uint8_t[]>& frameData = xa0_bufferQueue[minFrame];
|
||||||
|
DecodeFromRead(frameData.get());
|
||||||
|
++xd8_;
|
||||||
|
++xc4_;
|
||||||
|
if (xc4_ >= x28_thpHead.numFrames && xf4_24_loop)
|
||||||
|
xc4_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xd8_ <= 0 || xe0_playMode != EPlayMode::Playing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xe8_curSeconds += dt;
|
||||||
|
if (xf4_24_loop)
|
||||||
|
xe8_curSeconds = std::fmod(xe8_curSeconds, xe4_totalSeconds);
|
||||||
|
else
|
||||||
|
xe8_curSeconds = std::min(xe4_totalSeconds, xe8_curSeconds);
|
||||||
|
|
||||||
|
float frameDt = 1.f / x28_thpHead.fps;
|
||||||
|
float rem = xdc_frameRem - dt;
|
||||||
|
if (rem <= 0.f)
|
||||||
|
{
|
||||||
|
if (!xf4_26_fieldFlip)
|
||||||
|
{
|
||||||
|
++xd0_;
|
||||||
|
if (xd0_ >= x80_textures.size())
|
||||||
|
xd0_ = 0;
|
||||||
|
if (xd4_ == -1)
|
||||||
|
xd4_ = 0;
|
||||||
|
--xd8_;
|
||||||
|
++xc8_curFrame;
|
||||||
|
if (xc8_curFrame == x28_thpHead.numFrames && xf4_24_loop)
|
||||||
|
xc8_curFrame = 0;
|
||||||
|
rem += frameDt;
|
||||||
|
xfc_ = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rem += dt;
|
||||||
|
xf4_26_fieldFlip = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xdc_frameRem = rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::DecodeFromRead(const void* data)
|
||||||
|
{
|
||||||
|
const u8* inptr = (u8*)data;
|
||||||
|
CTHPTextureSet& tex = x80_textures[xcc_decodedTexSlot];
|
||||||
|
|
||||||
|
THPFrameHeader frameHeader = *static_cast<const THPFrameHeader*>(data);
|
||||||
|
frameHeader.swapBig();
|
||||||
|
inptr += 8 + x58_thpComponents.numComponents * 4;
|
||||||
|
|
||||||
|
for (int i=0 ; i<x58_thpComponents.numComponents ; ++i)
|
||||||
|
{
|
||||||
|
switch (x58_thpComponents.comps[i])
|
||||||
|
{
|
||||||
|
case THPComponents::Type::Video:
|
||||||
|
{
|
||||||
|
tjDecompressToYUV(TjHandle, (u8*)inptr, frameHeader.imageSize, m_yuvBuf.get(), 0);
|
||||||
|
inptr += frameHeader.imageSize;
|
||||||
|
|
||||||
|
uintptr_t planeSize = x6c_videoInfo.width * x6c_videoInfo.height;
|
||||||
|
uintptr_t planeSizeHalf = planeSize / 2;
|
||||||
|
uintptr_t planeSizeQuarter = planeSizeHalf / 2;
|
||||||
|
|
||||||
|
if (m_deinterlace)
|
||||||
|
{
|
||||||
|
/* Deinterlace into 2 discrete 60-fps half-res textures */
|
||||||
|
u8* mappedData = (u8*)tex.Y[0]->map(planeSizeHalf);
|
||||||
|
for (unsigned y=0 ; y<x6c_videoInfo.height/2 ; ++y)
|
||||||
|
{
|
||||||
|
memcpy(mappedData + x6c_videoInfo.width*y,
|
||||||
|
m_yuvBuf.get() + x6c_videoInfo.width*(y*2),
|
||||||
|
x6c_videoInfo.width);
|
||||||
|
}
|
||||||
|
tex.Y[0]->unmap();
|
||||||
|
|
||||||
|
mappedData = (u8*)tex.Y[1]->map(planeSizeHalf);
|
||||||
|
for (unsigned y=0 ; y<x6c_videoInfo.height/2 ; ++y)
|
||||||
|
{
|
||||||
|
memcpy(mappedData + x6c_videoInfo.width*y,
|
||||||
|
m_yuvBuf.get() + x6c_videoInfo.width*(y*2+1),
|
||||||
|
x6c_videoInfo.width);
|
||||||
|
}
|
||||||
|
tex.Y[1]->unmap();
|
||||||
|
|
||||||
|
tex.U->load(m_yuvBuf.get() + planeSize, planeSizeQuarter);
|
||||||
|
tex.V->load(m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Direct planar load */
|
||||||
|
tex.Y[0]->load(m_yuvBuf.get(), planeSize);
|
||||||
|
tex.U->load(m_yuvBuf.get() + planeSize, planeSizeQuarter);
|
||||||
|
tex.V->load(m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case THPComponents::Type::Audio:
|
||||||
|
THPAudioDecode(tex.audioBuf.get(), (u8*)inptr, x74_audioInfo.numChannels == 2);
|
||||||
|
inptr += frameHeader.audioSize;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++xcc_decodedTexSlot;
|
||||||
|
if (xcc_decodedTexSlot == x80_textures.size())
|
||||||
|
xcc_decodedTexSlot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::ReadCompleted()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMoviePlayer::PostDVDReadRequestIfNeeded()
|
||||||
|
{
|
||||||
|
if (xc0_loadedFrames < x28_thpHead.numFrames)
|
||||||
|
{
|
||||||
|
x90_requestBuf.reset(new uint8_t[xb0_nextReadSize]);
|
||||||
|
x98_request = AsyncSeekRead(x90_requestBuf.get(), xb0_nextReadSize,
|
||||||
|
ESeekOrigin::Begin, xb4_nextReadOff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
#ifndef __PSHAG_CMOVIEPLAYER_HPP__
|
||||||
|
#define __PSHAG_CMOVIEPLAYER_HPP__
|
||||||
|
|
||||||
|
#include "RetroTypes.hpp"
|
||||||
|
#include "CDvdFile.hpp"
|
||||||
|
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
|
||||||
|
#include "specter/View.hpp"
|
||||||
|
|
||||||
|
namespace urde
|
||||||
|
{
|
||||||
|
class CVector3f;
|
||||||
|
|
||||||
|
class CMoviePlayer : public CDvdFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class EPlayMode
|
||||||
|
{
|
||||||
|
Stopped,
|
||||||
|
Playing
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
struct THPHeader
|
||||||
|
{
|
||||||
|
u32 magic;
|
||||||
|
u32 version;
|
||||||
|
u32 maxBufferSize;
|
||||||
|
u32 maxAudioSamples;
|
||||||
|
float fps;
|
||||||
|
u32 numFrames;
|
||||||
|
u32 firstFrameSize;
|
||||||
|
u32 dataSize;
|
||||||
|
u32 componentDataOffset;
|
||||||
|
u32 offsetsDataOffset;
|
||||||
|
u32 firstFrameOffset;
|
||||||
|
u32 lastFrameOffset;
|
||||||
|
void swapBig();
|
||||||
|
} x28_thpHead;
|
||||||
|
|
||||||
|
struct THPComponents
|
||||||
|
{
|
||||||
|
u32 numComponents;
|
||||||
|
enum class Type : u8
|
||||||
|
{
|
||||||
|
Video = 0x0,
|
||||||
|
Audio = 0x1,
|
||||||
|
None = 0xff
|
||||||
|
} comps[16];
|
||||||
|
void swapBig();
|
||||||
|
} x58_thpComponents;
|
||||||
|
|
||||||
|
struct THPVideoInfo
|
||||||
|
{
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
void swapBig();
|
||||||
|
} x6c_videoInfo;
|
||||||
|
|
||||||
|
struct THPAudioInfo
|
||||||
|
{
|
||||||
|
u32 numChannels;
|
||||||
|
u32 sampleRate;
|
||||||
|
u32 numSamples;
|
||||||
|
void swapBig();
|
||||||
|
} x74_audioInfo;
|
||||||
|
|
||||||
|
struct THPFrameHeader
|
||||||
|
{
|
||||||
|
u32 nextSize;
|
||||||
|
u32 prevSize;
|
||||||
|
u32 imageSize;
|
||||||
|
u32 audioSize;
|
||||||
|
void swapBig();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct THPAudioFrameHeader
|
||||||
|
{
|
||||||
|
u32 channelSize;
|
||||||
|
u32 numSamples;
|
||||||
|
s16 channelCoefs[2][8][2];
|
||||||
|
s16 channelPrevs[2][2];
|
||||||
|
void swapBig();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CTHPTextureSet
|
||||||
|
{
|
||||||
|
boo::ITextureD* Y[2] = {};
|
||||||
|
boo::ITextureD* U = nullptr;
|
||||||
|
boo::ITextureD* V = nullptr;
|
||||||
|
std::unique_ptr<s16[]> audioBuf;
|
||||||
|
boo::IShaderDataBinding* binding[2] = {};
|
||||||
|
};
|
||||||
|
std::vector<CTHPTextureSet> x80_textures;
|
||||||
|
std::unique_ptr<uint8_t[]> x90_requestBuf;
|
||||||
|
std::shared_ptr<IDvdRequest> x98_request;
|
||||||
|
std::vector<std::unique_ptr<uint8_t[]>> xa0_bufferQueue;
|
||||||
|
|
||||||
|
u32 xb0_nextReadSize = 0;
|
||||||
|
u32 xb4_nextReadOff = 0;
|
||||||
|
u32 xb8_readSize = 0;
|
||||||
|
u32 xbc_readOff = 0;
|
||||||
|
u32 xc0_loadedFrames = 0;
|
||||||
|
u32 xc4_ = 0;
|
||||||
|
u32 xc8_curFrame = 0;
|
||||||
|
u32 xcc_decodedTexSlot = 0;
|
||||||
|
u32 xd0_ = 0;
|
||||||
|
u32 xd4_ = 0;
|
||||||
|
s32 xd8_ = 0;
|
||||||
|
float xdc_frameRem = 0.f;
|
||||||
|
EPlayMode xe0_playMode = EPlayMode::Playing;
|
||||||
|
float xe4_totalSeconds = 0.f;
|
||||||
|
float xe8_curSeconds = 0.f;
|
||||||
|
float xec_preLoadSeconds;
|
||||||
|
u32 xf0_preLoadFrames = 0;
|
||||||
|
u32 xf8_ = 0;
|
||||||
|
u32 xfc_ = 0;
|
||||||
|
|
||||||
|
boo::GraphicsDataToken m_token;
|
||||||
|
std::unique_ptr<uint8_t[]> m_yuvBuf;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
bool xf4_24_loop : 1; bool xf4_25_hasAudio : 1;
|
||||||
|
bool xf4_26_fieldFlip : 1; bool m_deinterlace : 1;
|
||||||
|
};
|
||||||
|
u8 m_dummy = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ViewBlock
|
||||||
|
{
|
||||||
|
zeus::CMatrix4f m_mv;
|
||||||
|
zeus::CColor m_color = zeus::CColor::skWhite;
|
||||||
|
} m_viewVertBlock;
|
||||||
|
boo::IGraphicsBufferD* m_blockBuf;
|
||||||
|
|
||||||
|
uint64_t m_loadedFrameCount = 0;
|
||||||
|
uint64_t m_playedFrameCount = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bool deinterlace);
|
||||||
|
|
||||||
|
static u32 THPAudioDecode(s16* buffer, const u8* audioFrame, bool stereo);
|
||||||
|
static void VerifyCallbackStatus();
|
||||||
|
static void DisableStaticAudio();
|
||||||
|
static void SetStaticAudioVolume(int vol);
|
||||||
|
static void SetStaticAudio(const void* data, u32 length, u32 loopStart, u32 loopEnd);
|
||||||
|
void MixAudio(short* out, const short* in, u32 length);
|
||||||
|
static void MixStaticAudio(short* out, const short* in, u32 length);
|
||||||
|
static void StaticMyAudioCallback();
|
||||||
|
void Rewind();
|
||||||
|
|
||||||
|
bool GetIsMovieFinishedPlaying() const
|
||||||
|
{
|
||||||
|
if (xf4_24_loop)
|
||||||
|
return false;
|
||||||
|
return xc8_curFrame == x28_thpHead.numFrames;
|
||||||
|
}
|
||||||
|
bool GetIsFullyCached() const {return xa0_bufferQueue.size() >= xf0_preLoadFrames;}
|
||||||
|
float GetPlayedSeconds() const {return xdc_frameRem + xe8_curSeconds;}
|
||||||
|
float GetTotalSeconds() const {return xe4_totalSeconds;}
|
||||||
|
void SetPlayMode(EPlayMode mode) {xe0_playMode = mode;}
|
||||||
|
void DrawFrame(const CVector3f& a, const CVector3f& b, const CVector3f& c, const CVector3f& d);
|
||||||
|
void Update(float dt);
|
||||||
|
void DecodeFromRead(const void* data);
|
||||||
|
void ReadCompleted();
|
||||||
|
void PostDVDReadRequestIfNeeded();
|
||||||
|
|
||||||
|
static void Initialize();
|
||||||
|
static void Shutdown();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __PSHAG_CMOVIEPLAYER_HPP__
|
2
hecl
2
hecl
|
@ -1 +1 @@
|
||||||
Subproject commit 0df19b29fbc5024511d3bb444e9b9f7ef57d766d
|
Subproject commit 3e3e34414087d9427bf98cef992dad279ebd988e
|
2
nod
2
nod
|
@ -1 +1 @@
|
||||||
Subproject commit a98927d4a00926a04caca202a2da88763c08ac7c
|
Subproject commit 473607ebe7b4b30b5e9936fa572ae18e1a063e3f
|
2
specter
2
specter
|
@ -1 +1 @@
|
||||||
Subproject commit d6a6032dbaf4500acad4900b9e8ba172cf75788c
|
Subproject commit 3b1128bbfa4602888e7d08d1b58ed64737f12640
|
Loading…
Reference in New Issue