Enhances audio effects.Adds TitleScene.
This commit is contained in:
parent
ea6fbd572e
commit
55b64ffa45
@ -155,6 +155,7 @@
|
||||
<ClCompile Include="src\PlayScene.cc" />
|
||||
<ClCompile Include="src\ResultScene.cc" />
|
||||
<ClCompile Include="src\Texture.cc" />
|
||||
<ClCompile Include="src\TitleScene.cc" />
|
||||
<ClCompile Include="src\Win32Console.cc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -183,6 +184,7 @@
|
||||
<ClInclude Include="src\OffsetClock.h" />
|
||||
<ClInclude Include="src\Period.h" />
|
||||
<ClInclude Include="src\PlayScene.h" />
|
||||
<ClInclude Include="src\GlitchPosteffect.h" />
|
||||
<ClInclude Include="src\Rasterbuffer.h" />
|
||||
<ClInclude Include="src\iConsole.h" />
|
||||
<ClInclude Include="src\iAllocator.h" />
|
||||
@ -197,6 +199,7 @@
|
||||
<ClInclude Include="src\Texture.h" />
|
||||
<ClInclude Include="src\TextureElement.h" />
|
||||
<ClInclude Include="src\TickingClock.h" />
|
||||
<ClInclude Include="src\TitleScene.h" />
|
||||
<ClInclude Include="thirdparty\lauxlib.h" />
|
||||
<ClInclude Include="thirdparty\linalg.h" />
|
||||
<ClInclude Include="thirdparty\lua.h" />
|
||||
@ -204,6 +207,7 @@
|
||||
<ClInclude Include="thirdparty\luaconf.h" />
|
||||
<ClInclude Include="thirdparty\lualib.h" />
|
||||
<ClInclude Include="thirdparty\miniaudio.h" />
|
||||
<ClInclude Include="thirdparty\picojson.h" />
|
||||
<ClInclude Include="thirdparty\stb_truetype.h" />
|
||||
<ClInclude Include="src\Win32Console.h" />
|
||||
<ClInclude Include="thirdparty\utf8.h" />
|
||||
|
@ -48,6 +48,9 @@
|
||||
<ClCompile Include="src\AudioDevice.cc">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\TitleScene.cc">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\iConsole.h">
|
||||
@ -197,6 +200,15 @@
|
||||
<ClInclude Include="src\MusicElementFactory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\TitleScene.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="thirdparty\picojson.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\GlitchPosteffect.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Library Include="thirdparty\lua5.1.lib" />
|
||||
|
@ -29,7 +29,7 @@ gj::AudioDevice::~AudioDevice() {
|
||||
}
|
||||
}
|
||||
|
||||
void gj::AudioDevice::PlayMusic(const std::string& path) {
|
||||
void gj::AudioDevice::PlayMusic(const std::string& path, double offset) {
|
||||
std::lock_guard _(mtx_);
|
||||
|
||||
if (playing_) {
|
||||
@ -39,6 +39,11 @@ void gj::AudioDevice::PlayMusic(const std::string& path) {
|
||||
if (ma_decoder_init_file(path.c_str(), &config, &dec_) != MA_SUCCESS) {
|
||||
Abort("AudioDevice decoder error: "+path);
|
||||
}
|
||||
|
||||
const uint64_t offset_frame = static_cast<uint64_t>(kSampleRate * offset);
|
||||
if (ma_decoder_seek_to_pcm_frame(&dec_, offset_frame) != MA_SUCCESS) {
|
||||
Abort("decoder seek failure");
|
||||
}
|
||||
playing_ = true;
|
||||
}
|
||||
|
||||
@ -54,6 +59,9 @@ void gj::AudioDevice::Callback_(ma_device* ma, void* out, const void* in, ma_uin
|
||||
AudioDevice* dev = reinterpret_cast<AudioDevice*>(ma->pUserData);
|
||||
std::lock_guard _(dev->mtx_);
|
||||
|
||||
const double amp = dev->amp_.load();
|
||||
const double lpf = dev->lpf_coe_.load();
|
||||
|
||||
float* dst = reinterpret_cast<float*>(out);
|
||||
|
||||
size_t wrote = 0;
|
||||
@ -65,5 +73,11 @@ void gj::AudioDevice::Callback_(ma_device* ma, void* out, const void* in, ma_uin
|
||||
}
|
||||
wrote += n;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < static_cast<size_t>(framecnt)*kChannel; ++i) {
|
||||
dst[i] = static_cast<float>(dst[i]*amp);
|
||||
dst[i] = static_cast<float>(dev->lpf_prev_*lpf + dst[i]*(1-lpf));
|
||||
dev->lpf_prev_ = dst[i];
|
||||
}
|
||||
dev->time_.fetch_add(framecnt);
|
||||
}
|
@ -32,9 +32,16 @@ class AudioDevice : public iAudioDevice, public iClock {
|
||||
AudioDevice();
|
||||
~AudioDevice();
|
||||
|
||||
void PlayMusic(const std::string& path) override;
|
||||
void PlayMusic(const std::string& path, double offset) override;
|
||||
void StopMusic() override;
|
||||
|
||||
void SetVolume(double amp) override {
|
||||
amp_.store(amp);
|
||||
}
|
||||
void SetLpfIntensity(double v) override {
|
||||
lpf_coe_.store(v);
|
||||
}
|
||||
|
||||
uint64_t now() const override {
|
||||
return time_.load() * 1000 / kSampleRate;
|
||||
}
|
||||
@ -47,6 +54,11 @@ class AudioDevice : public iAudioDevice, public iClock {
|
||||
bool playing_ = false;
|
||||
ma_decoder dec_{0};
|
||||
|
||||
std::atomic<double> amp_ = 1;
|
||||
|
||||
std::atomic<double> lpf_coe_ = 0;
|
||||
float lpf_prev_ = 0;
|
||||
|
||||
std::atomic<uint64_t> time_;
|
||||
|
||||
static void Callback_(ma_device* ma, void* out, const void* in, ma_uint32 framecnt);
|
||||
|
@ -14,7 +14,7 @@
|
||||
namespace gj {
|
||||
|
||||
|
||||
class Font {
|
||||
class Font {
|
||||
public:
|
||||
Font() = delete;
|
||||
Font(Font&&) = delete;
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "Game.h"
|
||||
#include "PlayScene.h"
|
||||
|
||||
#include "iScene.h"
|
||||
#include "TitleScene.h"
|
||||
|
||||
|
||||
gj::Game::Game(gj::Game::Param&& p) :
|
||||
@ -8,10 +10,9 @@ gj::Game::Game(gj::Game::Param&& p) :
|
||||
logger_(p.h),
|
||||
w_(p.w), h_(p.h),
|
||||
frame_(p.w, p.h, kReserveDrawable, kReserveWritable) {
|
||||
gj::PlayScene::Param param;
|
||||
gj::iScene::Param param;
|
||||
param.alloc = alloc_;
|
||||
param.clock = &clock_;
|
||||
param.audio = p.audio;
|
||||
param.score = "test"; /* TODO test */
|
||||
scene_ = alloc_->MakeUniq<gj::iScene, gj::PlayScene>(std::move(param));
|
||||
scene_ = alloc_->MakeUniq<gj::iScene, gj::TitleScene>(param);
|
||||
}
|
48
src/GlitchPosteffect.h
Normal file
48
src/GlitchPosteffect.h
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#include "iDrawable.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class GlitchPosteffect : public iDrawable {
|
||||
public:
|
||||
GlitchPosteffect(GlitchPosteffect&&) = delete;
|
||||
GlitchPosteffect(const GlitchPosteffect&) = delete;
|
||||
|
||||
GlitchPosteffect& operator=(GlitchPosteffect&&) = delete;
|
||||
GlitchPosteffect& operator=(const GlitchPosteffect&) = delete;
|
||||
|
||||
GlitchPosteffect() {
|
||||
}
|
||||
|
||||
void Draw(Colorbuffer& fb) const override {
|
||||
const int32_t w = static_cast<int32_t>(fb.width());
|
||||
const int32_t h = static_cast<int32_t>(fb.height());
|
||||
|
||||
float* ptr = fb.ptr();
|
||||
|
||||
for (int32_t y = 0; y < h; ++y) {
|
||||
const double shift = (XorShift(seed+y)%100/100.*2-1)*maxShift;
|
||||
const int32_t s = static_cast<int32_t>(w*shift);
|
||||
if (std::abs(shift) > 1) continue;
|
||||
|
||||
const size_t offset = static_cast<size_t>(y) * w;
|
||||
float* src = ptr + offset;
|
||||
float* dst = ptr + offset + s;
|
||||
if (src > dst) std::swap(src, dst);
|
||||
|
||||
std::memmove(dst, src, static_cast<size_t>(w) - std::abs(s));
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t seed = 1;
|
||||
double maxShift = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -42,7 +42,7 @@ class GlyphElementFactory : public iElementFactory {
|
||||
if (found != fonts_.end()) {
|
||||
return *found->second;
|
||||
}
|
||||
auto f = alloc_->MakeUniq<Font>(alloc_, "res/font/"+name);
|
||||
auto f = alloc_->MakeUniq<Font>(alloc_, name);
|
||||
auto ptr = f.get();
|
||||
fonts_[name] = std::move(f);
|
||||
return *ptr;
|
||||
|
@ -189,10 +189,9 @@ bool gj::HiraganaMatcher::Input_(wchar_t c, bool force_cut) {
|
||||
if (itr.size() == newbuf.size()) {
|
||||
comp_match = i;
|
||||
if (force_cut) {
|
||||
buffer_ = {c};
|
||||
buffer_ = L"";
|
||||
state_.match += i;
|
||||
UpdateExpects_();
|
||||
return true;
|
||||
return Input_(c, false);
|
||||
}
|
||||
} else {
|
||||
part_match = i;
|
||||
@ -248,6 +247,8 @@ void gj::HiraganaMatcher::UpdateExpects_() {
|
||||
}
|
||||
remain = remain.substr(len);
|
||||
}
|
||||
if (prev == remain.size()) Abort("invalid pattern for InputWin");
|
||||
if (prev == remain.size()) {
|
||||
Abort("invalid pattern for InputWin");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
#include "Lua.h"
|
||||
|
||||
#include "thirdparty/lualib.h"
|
||||
|
||||
|
||||
struct LuaPusher {
|
||||
LuaPusher() = delete;
|
||||
@ -142,6 +144,7 @@ gj::Lua::Lua(iAllocator* alloc, ElementStore* store, const FactoryMap& factory,
|
||||
if (L == nullptr) {
|
||||
Abort("lua_newstate failure");
|
||||
}
|
||||
luaopen_math(L);
|
||||
|
||||
for (const auto& f : factory) {
|
||||
lua_pushstring(L, f.first.c_str());
|
||||
|
@ -12,6 +12,17 @@ namespace gj {
|
||||
|
||||
class MusicElement : public iElement {
|
||||
public:
|
||||
struct Param {
|
||||
iAudioDevice* audio;
|
||||
|
||||
Period period;
|
||||
|
||||
std::string path;
|
||||
double offset;
|
||||
|
||||
UniqPtr<iElementDriver> driver;
|
||||
};
|
||||
|
||||
MusicElement() = delete;
|
||||
MusicElement(MusicElement&&) = delete;
|
||||
MusicElement(const MusicElement&) = delete;
|
||||
@ -19,13 +30,24 @@ public:
|
||||
MusicElement& operator=(MusicElement&&) = delete;
|
||||
MusicElement& operator=(const MusicElement&) = delete;
|
||||
|
||||
MusicElement(const Period& p, iAudioDevice* audio, const std::string& name) :
|
||||
iElement(p), audio_(audio), path_("res/music/"+name) {
|
||||
MusicElement(Param&& p) :
|
||||
iElement(p.period), audio_(p.audio), path_(p.path), offset_(p.offset),
|
||||
drv_(std::move(p.driver)) {
|
||||
param_["volume"] = 0.;
|
||||
param_["lpf"] = 0.;
|
||||
}
|
||||
|
||||
void Update(Frame& frame, double t) override {
|
||||
drv_->Update(param_, t);
|
||||
|
||||
const double volume = std::get<double>(param_["volume"]);
|
||||
const double lpf = std::get<double>(param_["lpf"]);
|
||||
|
||||
audio_->SetVolume(volume);
|
||||
audio_->SetLpfIntensity(lpf);
|
||||
|
||||
if (first_) {
|
||||
audio_->PlayMusic(path_);
|
||||
audio_->PlayMusic(path_, offset_);
|
||||
first_ = false;
|
||||
}
|
||||
}
|
||||
@ -41,6 +63,11 @@ public:
|
||||
std::string path_;
|
||||
|
||||
bool first_ = true;
|
||||
|
||||
double offset_;
|
||||
|
||||
UniqPtr<iElementDriver> drv_;
|
||||
iElementDriver::Param param_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -22,11 +22,18 @@ class MusicElementFactory : public iElementFactory {
|
||||
}
|
||||
|
||||
UniqPtr<iElement> Create(Param&& param) override {
|
||||
if (param.custom.size() != 1) return nullptr;
|
||||
if (param.custom.size() != 2) return nullptr;
|
||||
|
||||
const std::string name = std::get<std::string>(param.custom[0]);
|
||||
const std::string path = std::get<std::string>(param.custom[0]);
|
||||
const double offset = std::get<double>(param.custom[1]);
|
||||
|
||||
return alloc_->MakeUniq<iElement, MusicElement>(param.period, audio_, name);
|
||||
MusicElement::Param p;
|
||||
p.audio = audio_;
|
||||
p.period = param.period;
|
||||
p.path = path;
|
||||
p.offset = offset;
|
||||
p.driver = std::move(param.driver);
|
||||
return alloc_->MakeUniq<iElement, MusicElement>(std::move(p));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -7,29 +7,28 @@
|
||||
#include "ResultScene.h"
|
||||
|
||||
|
||||
gj::PlayScene::PlayScene(Param&& p) :
|
||||
alloc_(p.alloc), audio_(p.audio),
|
||||
clock_(p.clock), store_(&clock_, 256) {
|
||||
gj::PlayScene::PlayScene(const Param& p, const std::string& title, const std::string& path) :
|
||||
param_(p), clock_(p.clock), store_(&clock_, 256) {
|
||||
|
||||
GlyphElementFactory glyph(alloc_);
|
||||
InputWindowElementFactory inputWin(alloc_, &sb_);
|
||||
MusicElementFactory music(alloc_, audio_);
|
||||
GlyphElementFactory glyph(p.alloc);
|
||||
InputWindowElementFactory inputWin(p.alloc, &sb_);
|
||||
MusicElementFactory music(p.alloc, p.audio);
|
||||
|
||||
sb_.title = ConvertStrToWstr(p.score);
|
||||
sb_.title = ConvertStrToWstr(title);
|
||||
|
||||
Lua::FactoryMap map = {
|
||||
{ "Glyph", &glyph },
|
||||
{ "InputWin", &inputWin },
|
||||
{ "Music", &music },
|
||||
};
|
||||
lua_ = alloc_->MakeUniq<Lua>(
|
||||
alloc_, &store_, map, "res/score/" + p.score + ".lua");
|
||||
lua_ = p.alloc->MakeUniq<Lua>(
|
||||
p.alloc, &store_, map, path);
|
||||
}
|
||||
|
||||
|
||||
gj::UniqPtr<gj::iScene> gj::PlayScene::Update(Frame& f) {
|
||||
if (store_.IsEmpty()) {
|
||||
return alloc_->MakeUniq<iScene, ResultScene>(alloc_, clock_.parent(), sb_);
|
||||
return param_.alloc->MakeUniq<iScene, ResultScene>(param_, sb_);
|
||||
}
|
||||
|
||||
store_.Update(f);
|
||||
|
@ -2,10 +2,6 @@
|
||||
|
||||
|
||||
#include "ElementStore.h"
|
||||
#include "Frame.h"
|
||||
#include "iAllocator.h"
|
||||
#include "iAudioDevice.h"
|
||||
#include "iLogger.h"
|
||||
#include "iScene.h"
|
||||
#include "Lua.h"
|
||||
#include "OffsetClock.h"
|
||||
@ -17,14 +13,6 @@ namespace gj {
|
||||
|
||||
class PlayScene : public iScene {
|
||||
public:
|
||||
struct Param {
|
||||
iAllocator* alloc;
|
||||
iAudioDevice* audio;
|
||||
const iClock* clock;
|
||||
|
||||
std::string score;
|
||||
};
|
||||
|
||||
PlayScene() = delete;
|
||||
PlayScene(PlayScene&&) = delete;
|
||||
PlayScene(const PlayScene&) = delete;
|
||||
@ -32,13 +20,12 @@ class PlayScene : public iScene {
|
||||
PlayScene& operator=(PlayScene&&) = delete;
|
||||
PlayScene& operator=(const PlayScene&) = delete;
|
||||
|
||||
PlayScene(Param&& p);
|
||||
PlayScene(const Param& p, const std::string& title, const std::string& path);
|
||||
|
||||
UniqPtr<iScene> Update(Frame& f) override;
|
||||
|
||||
private:
|
||||
iAllocator* alloc_;
|
||||
iAudioDevice* audio_;
|
||||
Param param_;
|
||||
|
||||
OffsetClock clock_;
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
#include "ResultScene.h"
|
||||
|
||||
#include "TitleScene.h"
|
||||
|
||||
gj::ResultScene::ResultScene(iAllocator* alloc, const iClock* clock, const Scoreboard& sb) :
|
||||
alloc_(alloc), clock_(clock), sb_(sb),
|
||||
|
||||
gj::ResultScene::ResultScene(const Param& p, const Scoreboard& sb) :
|
||||
param_(p), clock_(p.clock), sb_(sb),
|
||||
title_(sb.title),
|
||||
correct_label_(L"CORRECT TYPES"),
|
||||
correct_num_(std::to_wstring(sb.correct)),
|
||||
@ -10,7 +12,7 @@ gj::ResultScene::ResultScene(iAllocator* alloc, const iClock* clock, const Score
|
||||
line_label_(L"COMPLETE LINES"),
|
||||
line_num_(std::to_wstring(sb.completeLines)),
|
||||
line_den_(std::to_wstring(sb.lines)),
|
||||
guide_(L"~ PRESS ENTER ~") {
|
||||
guide_(L"~ PRESS SPACE ~") {
|
||||
}
|
||||
|
||||
gj::UniqPtr<gj::iScene> gj::ResultScene::Update(Frame& f) {
|
||||
@ -51,5 +53,9 @@ gj::UniqPtr<gj::iScene> gj::ResultScene::Update(Frame& f) {
|
||||
guide_.SetPosition((w-guide_.width())/2, static_cast<int32_t>(h*.8));
|
||||
f.Add(&guide_);
|
||||
|
||||
if (f.input.find(' ') != std::string::npos) {
|
||||
return param_.alloc->MakeUniq<iScene, TitleScene>(param_);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "ElementStore.h"
|
||||
#include "Frame.h"
|
||||
#include "iAllocator.h"
|
||||
#include "iScene.h"
|
||||
#include "OffsetClock.h"
|
||||
#include "Scoreboard.h"
|
||||
@ -21,12 +18,13 @@ class ResultScene : public iScene {
|
||||
ResultScene& operator=(ResultScene&&) = delete;
|
||||
ResultScene& operator=(const ResultScene&) = delete;
|
||||
|
||||
ResultScene(iAllocator* alloc, const iClock* clock, const Scoreboard& sb);
|
||||
ResultScene(const Param& p, const Scoreboard& sb);
|
||||
|
||||
UniqPtr<iScene> Update(Frame& f) override;
|
||||
|
||||
private:
|
||||
iAllocator* alloc_;
|
||||
Param param_;
|
||||
|
||||
OffsetClock clock_;
|
||||
Scoreboard sb_;
|
||||
|
||||
|
@ -81,7 +81,7 @@ void gj::Texture::Draw(Colorbuffer& fb) const {
|
||||
if (dstx < 0 || w <= dstx) continue;
|
||||
if (dsty < 0 || h <= dsty) continue;
|
||||
|
||||
dst[dstx + w*dsty] = src[srcx + srcw*srcy] * alpha_;
|
||||
dst[dstx + w*dsty] += src[srcx + srcw*srcy] * alpha_;
|
||||
}
|
||||
}
|
||||
}
|
129
src/TitleScene.cc
Normal file
129
src/TitleScene.cc
Normal file
@ -0,0 +1,129 @@
|
||||
#include "TitleScene.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "thirdparty/picojson.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "Font.h"
|
||||
#include "PlayScene.h"
|
||||
|
||||
|
||||
gj::TitleScene::TitleScene(const Param& p) :
|
||||
param_(p),
|
||||
score_(L"penguin: you didn't see anything..."),
|
||||
next_(L"> L"), prev_(L"H <"),
|
||||
guide_(L"H:PREV / SPACE:PLAY / L:NEXT"),
|
||||
logo_(Colorbuffer(p.alloc, 1, 1)) {
|
||||
/* load score list */
|
||||
std::ifstream ifs(kListPath);
|
||||
if (!ifs) Abort(std::string(kListPath)+" is missing");
|
||||
|
||||
::picojson::value root;
|
||||
const std::string err = ::picojson::parse(root, ifs);
|
||||
ifs.close();
|
||||
|
||||
if (err.size()) Abort(std::string(kListPath)+": "+err);
|
||||
|
||||
std::string line;
|
||||
auto& list = root.get<::picojson::array>();
|
||||
for (auto& e : list) {
|
||||
auto& obj = e.get<::picojson::object>();
|
||||
|
||||
Score s;
|
||||
|
||||
s.displayName = obj["displayName"].get<std::string>();
|
||||
s.music = obj["music"].get<std::string>();
|
||||
s.score = obj["score"].get<std::string>();
|
||||
s.playOffset = static_cast<uint64_t>(obj["playOffset"].get<double>());
|
||||
|
||||
list_.push_back(s);
|
||||
}
|
||||
if (list_.size() == 0) Abort("no score is registered");
|
||||
|
||||
SelectScore_(0);
|
||||
|
||||
/* render logo */
|
||||
Font font(param_.alloc, "res/font/shippori.ttf");
|
||||
logo_ = Texture(font.RenderGlyphs(L"GlyphsJuke", 64));
|
||||
}
|
||||
|
||||
gj::UniqPtr<gj::iScene> gj::TitleScene::Update(Frame& frame) {
|
||||
for (const auto c : frame.input) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
SelectScore_(select_index_? select_index_-1: list_.size()-1);
|
||||
break;
|
||||
case 'l':
|
||||
SelectScore_((select_index_+1)%list_.size());
|
||||
break;
|
||||
case ' ':
|
||||
return param_.alloc->MakeUniq<iScene, PlayScene>(
|
||||
param_, list_[select_index_].displayName, list_[select_index_].score);
|
||||
}
|
||||
}
|
||||
|
||||
const uint64_t now = param_.clock->now();
|
||||
|
||||
const int32_t w = static_cast<int32_t>(frame.w);
|
||||
const int32_t h = static_cast<int32_t>(frame.h);
|
||||
|
||||
const int32_t selector_y = static_cast<int32_t>(h*.75);
|
||||
|
||||
const uint64_t period1 = XorShift(now/1000+1)%1000 + 500;
|
||||
const uint64_t period2 = XorShift(now/1000+5)%1000 + 500;
|
||||
logo_.SetAlpha(static_cast<float>(XorShift(now/period1+1)%100/100.*.4+.4));
|
||||
|
||||
const double shift_x = (XorShift(now/period1+1)%100/100.*2 - 1)*.05;
|
||||
const double shift_y = (XorShift(now/period2+3)%100/100.*2 - 1)*.05;
|
||||
const double scale_x = (XorShift(now/period1+3)%100/100.*2 - 1)*.1;
|
||||
|
||||
const double theta = (XorShift(now/period2+13)%100/100.*2 - 1)*.01*kPi*2;
|
||||
|
||||
const double c = cos(theta), s = sin(theta);
|
||||
auto M = mat3{
|
||||
{1+scale_x, 0, 0},
|
||||
{0, .8, 0},
|
||||
{shift_x, shift_y+.4, 1}
|
||||
};
|
||||
auto Mr = mat3{
|
||||
{c, -s, 0},
|
||||
{s, c, 0},
|
||||
{0, 0, 1},
|
||||
};
|
||||
M = ::linalg::mul(Mr, M);
|
||||
logo_.SetMatrix(M);
|
||||
frame.Add(&logo_);
|
||||
|
||||
next_.SetPosition(static_cast<int32_t>(w*.8-next_.width()), selector_y);
|
||||
frame.Add(&next_);
|
||||
|
||||
prev_.SetPosition(static_cast<int32_t>(w*.2), selector_y);
|
||||
frame.Add(&prev_);
|
||||
|
||||
score_.SetPosition((w-score_.width())/2, selector_y);
|
||||
frame.Add(&score_);
|
||||
|
||||
guide_.SetPosition((w-guide_.width())/2, selector_y+3);
|
||||
frame.Add(&guide_);
|
||||
|
||||
pe_.seed = XorShift(now/period1+10);
|
||||
pe_.maxShift = (XorShift(now/period1+7)%100/100.*2 - 1)*.1;
|
||||
frame.Add(&pe_);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void gj::TitleScene::SelectScore_(size_t index) {
|
||||
const auto& s = list_[index];
|
||||
score_ = Text(ConvertStrToWstr(s.displayName));
|
||||
select_index_ = index;
|
||||
|
||||
param_.audio->SetVolume(.2);
|
||||
param_.audio->SetLpfIntensity(.99);
|
||||
param_.audio->PlayMusic(s.music, s.playOffset);
|
||||
}
|
53
src/TitleScene.h
Normal file
53
src/TitleScene.h
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "GlitchPosteffect.h"
|
||||
#include "iScene.h"
|
||||
#include "Text.h"
|
||||
#include "Texture.h"
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class TitleScene : public iScene {
|
||||
public:
|
||||
static constexpr auto kListPath = "res/list.json";
|
||||
|
||||
TitleScene() = delete;
|
||||
TitleScene(TitleScene&&) = delete;
|
||||
TitleScene(const TitleScene&) = delete;
|
||||
|
||||
TitleScene& operator=(TitleScene&&) = delete;
|
||||
TitleScene& operator=(const TitleScene&) = delete;
|
||||
|
||||
TitleScene(const Param& p);
|
||||
|
||||
UniqPtr<iScene> Update(Frame& frame) override;
|
||||
|
||||
private:
|
||||
struct Score {
|
||||
std::string displayName;
|
||||
std::string score;
|
||||
std::string music;
|
||||
double playOffset;
|
||||
};
|
||||
|
||||
Param param_;
|
||||
|
||||
Text score_;
|
||||
Text next_;
|
||||
Text prev_;
|
||||
Text guide_;
|
||||
|
||||
Texture logo_;
|
||||
|
||||
size_t select_index_;
|
||||
std::vector<Score> list_;
|
||||
|
||||
GlitchPosteffect pe_;
|
||||
|
||||
void SelectScore_(size_t index);
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -17,6 +17,8 @@ namespace gj {
|
||||
using mat3 = ::linalg::mat<double, 3, 3>;
|
||||
using vec3 = ::linalg::vec<double, 3>;
|
||||
|
||||
constexpr double kPi = 3.14159265358979323846264338327950288;
|
||||
|
||||
|
||||
static inline std::wstring ConvertStrToWstr(const std::string& str) {
|
||||
std::wstring ret;
|
||||
@ -38,6 +40,12 @@ static inline size_t CountWstrBytes(const std::wstring& str) {
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline uint64_t XorShift(uint64_t x) {
|
||||
x = x ^ (x << 13);
|
||||
x = x ^ (x >> 7);
|
||||
return x ^ (x << 17);
|
||||
}
|
||||
|
||||
|
||||
[[noreturn]]
|
||||
static inline void Abort(const std::string& msg) {
|
||||
|
@ -18,8 +18,11 @@ public:
|
||||
|
||||
virtual ~iAudioDevice() = default;
|
||||
|
||||
virtual void PlayMusic(const std::string& path) = 0;
|
||||
virtual void PlayMusic(const std::string& path, double offset) = 0;
|
||||
virtual void StopMusic() = 0;
|
||||
|
||||
virtual void SetVolume(double amp) = 0;
|
||||
virtual void SetLpfIntensity(double v) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include "Frame.h"
|
||||
#include "iAllocator.h"
|
||||
#include "iAudioDevice.h"
|
||||
#include "iClock.h"
|
||||
#include "iDrawable.h"
|
||||
#include "iWritable.h"
|
||||
|
||||
@ -13,6 +15,12 @@ namespace gj {
|
||||
|
||||
class iScene {
|
||||
public:
|
||||
struct Param {
|
||||
iAllocator* alloc;
|
||||
iAudioDevice* audio;
|
||||
const iClock* clock;
|
||||
};
|
||||
|
||||
iScene() = default;
|
||||
iScene(iScene&&) = default;
|
||||
iScene(const iScene&) = default;
|
||||
|
1200
thirdparty/picojson.h
vendored
Normal file
1200
thirdparty/picojson.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user