Adds comments on codes.
This commit is contained in:
parent
7688f38dab
commit
c9a9f79a7c
@ -27,8 +27,11 @@ 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_);
|
||||
|
||||
/* iterates all of effects and applies them to the current frame */
|
||||
for (auto fx : dev->effects_) {
|
||||
fx->Apply(reinterpret_cast<float*>(out), framecnt);
|
||||
}
|
||||
|
||||
/* count up the time */
|
||||
dev->time_.fetch_add(framecnt);
|
||||
}
|
@ -29,13 +29,20 @@ class ElementStore {
|
||||
void Schedule(UniqPtr<iElement>&& e) {
|
||||
const uint64_t st = e->period.start;
|
||||
|
||||
/* finds an iterator of an element
|
||||
* that will perform right after the element which is trying to add */
|
||||
auto insert_pos = std::find_if(pending_.begin(), pending_.end(),
|
||||
[st](auto& x) { return x->period.start > st; });
|
||||
|
||||
/* inserts the new element right before the found element,
|
||||
* this means pending_ stays sorted by time that each element's performance will start */
|
||||
pending_.insert(insert_pos, std::move(e));
|
||||
}
|
||||
|
||||
void Update(Frame& frame, uint64_t now) {
|
||||
/* finds elements whose period is started and
|
||||
* move these elements to performing_ from pending_.
|
||||
* such elements are always on head of pending_ because it's sorted */
|
||||
auto pending_beg = pending_.begin();
|
||||
auto pending_end = pending_.end();
|
||||
auto pending_itr = pending_beg;
|
||||
@ -48,6 +55,7 @@ class ElementStore {
|
||||
}
|
||||
pending_.erase(pending_beg, pending_itr);
|
||||
|
||||
/* updates elements currently performing and deletes expired ones by assigning nullptr */
|
||||
for (auto& eptr : performing_) {
|
||||
iElement* e = eptr.get();
|
||||
if (e->period.end <= now) {
|
||||
|
@ -9,7 +9,7 @@ gj::Colorbuffer gj::Font::RenderGlyphs(const std::wstring& str, uint32_t fontsiz
|
||||
|
||||
const int baseline = static_cast<int>(ascent * s);
|
||||
|
||||
/* calculate bitmap size */
|
||||
/* calculate bitmap size by getting geometries of all chars */
|
||||
float h = 0, w = 2;
|
||||
for (auto c : str) {
|
||||
int advance, lsb;
|
||||
@ -32,6 +32,7 @@ gj::Colorbuffer gj::Font::RenderGlyphs(const std::wstring& str, uint32_t fontsiz
|
||||
|
||||
float* dst = buf.ptr();
|
||||
|
||||
/* renders all glyphs and blits the results to the actual buffer */
|
||||
float x = 2;
|
||||
for (auto c : str) {
|
||||
int advance, lsb;
|
||||
|
@ -33,9 +33,11 @@ class Font {
|
||||
const size_t size = ifs.tellg();
|
||||
ifs.seekg(0);
|
||||
|
||||
/* reads all contents from the file */
|
||||
buf_ = alloc_->MakeUniqArray<uint8_t>(size);
|
||||
ifs.read(reinterpret_cast<char*>(buf_.get()), size);
|
||||
|
||||
/* creates stb_trutype context */
|
||||
const int offset = stbtt_GetFontOffsetForIndex(buf_.get(), 0);
|
||||
if (!stbtt_InitFont(&stb_, buf_.get(), offset)) {
|
||||
Abort("invalid font: "+path);
|
||||
@ -52,6 +54,7 @@ class Font {
|
||||
Colorbuffer ret(alloc_, w, h);
|
||||
float* dst = ret.ptr();
|
||||
|
||||
/* blits all rendered glyphs */
|
||||
for (int y = 0; y < h; ++y) {
|
||||
for (int x = 0; x < w; ++x) {
|
||||
*dst = static_cast<float>(*src*1./UINT8_MAX);
|
||||
|
@ -27,18 +27,22 @@ class GlitchPosteffect : public iDrawable {
|
||||
float* ptr = fb.ptr();
|
||||
|
||||
for (int32_t y = 0; y < h; ++y) {
|
||||
/* glitch happens with 10% of chance */
|
||||
if (XorShift(seed+y)%10 == 0) continue;
|
||||
|
||||
/* calculates how many pixels shift the line */
|
||||
const double shift = (XorShift(seed+y+h)%100/100.*2-1)*maxShift;
|
||||
if (std::abs(shift) > 1) continue;
|
||||
|
||||
const int32_t s = static_cast<int32_t>(w*shift);
|
||||
const int32_t as = std::abs(s);
|
||||
|
||||
/* get pointers to actual data */
|
||||
float* src = ptr + static_cast<size_t>(y) * w;
|
||||
float* dst = src + as;
|
||||
if (s < 0) std::swap(src, dst);
|
||||
|
||||
/* shifts pixels */
|
||||
std::memmove(dst, src, (static_cast<size_t>(w) - as)*sizeof(*ptr));
|
||||
}
|
||||
}
|
||||
|
@ -29,9 +29,11 @@ class GlyphElementFactory : public iElementFactory {
|
||||
const std::string name = std::get<std::string>(param.custom[1]);
|
||||
const uint32_t size = static_cast<uint32_t>(std::get<double>(param.custom[2]));
|
||||
|
||||
/* finds font from cache and renders text */
|
||||
auto& font = FindOrCreateFont(name);
|
||||
auto tex = std::move(font.RenderGlyphs(ConvertStrToWstr(text), size)); /* TODO */
|
||||
|
||||
/* pass TextureElement the rendered texture */
|
||||
return alloc_->MakeUniq<TextureElement>(
|
||||
param.period, std::move(tex), std::move(param.driver));
|
||||
}
|
||||
|
@ -191,12 +191,15 @@ bool gj::HiraganaMatcher::Input_(wchar_t c, bool force_cut) {
|
||||
bool accept = false;
|
||||
size_t part_match = 0;
|
||||
size_t comp_match = 0;
|
||||
|
||||
/* finds the longest pattern that matches to the remained char */
|
||||
for (size_t i = 1; i <= pattern_len; ++i) {
|
||||
const auto& p = kPatterns.find(remain.substr(0, i));
|
||||
if (p == kPatterns.end()) continue;
|
||||
|
||||
const auto& preds = p->second;
|
||||
for (const auto& itr : preds) {
|
||||
/* checks if there's a candidate which matches the newbuf */
|
||||
const auto& candidates = p->second;
|
||||
for (const auto& itr : candidates) {
|
||||
if (newbuf.size() == 0 || itr.size() < newbuf.size()) {
|
||||
continue;
|
||||
}
|
||||
@ -224,6 +227,8 @@ bool gj::HiraganaMatcher::Input_(wchar_t c, bool force_cut) {
|
||||
return Input_(c, true);
|
||||
}
|
||||
|
||||
/* if there's a pattern completely matched with newbuf and
|
||||
* it's longer than any patterns partly matched, the pattern is determined */
|
||||
if (comp_match > part_match) {
|
||||
buffer_ = L"";
|
||||
state_.match += comp_match;
|
||||
@ -244,12 +249,16 @@ void gj::HiraganaMatcher::UpdateExpects_() {
|
||||
bool first = true;
|
||||
while (remain.size()) {
|
||||
const size_t prev = remain.size();
|
||||
|
||||
/* finds the longest pattern that matches to the remained char */
|
||||
for (size_t len = std::min(kPatternMax, remain.size()); len > 0; --len) {
|
||||
const auto& p = kPatterns.find(remain.substr(0, len));
|
||||
if (p == kPatterns.end()) continue;
|
||||
|
||||
const auto& preds = p->second;
|
||||
if (first) {
|
||||
/* the first matched pattern may be partly-determined already,
|
||||
* so it's necessary to find the possible input examples */
|
||||
for (const auto& itr : preds) {
|
||||
if (itr.size() < buffer_.size()) continue;
|
||||
if (itr.substr(0, buffer_.size()) == buffer_) {
|
||||
@ -260,10 +269,13 @@ void gj::HiraganaMatcher::UpdateExpects_() {
|
||||
}
|
||||
if (first) continue;
|
||||
} else {
|
||||
/* first example is always the shortest */
|
||||
expects_ += preds[0];
|
||||
}
|
||||
remain = remain.substr(len);
|
||||
}
|
||||
|
||||
/* if 'remain' is not consumed by this iteration, this means it includes unknown patterns */
|
||||
if (prev == remain.size()) {
|
||||
Abort(L"invalid pattern: "+remain);
|
||||
}
|
||||
|
@ -45,17 +45,20 @@ public:
|
||||
|
||||
auto h = reinterpret_cast<Header*>(ptr_);
|
||||
|
||||
/* finds block that has enough unused space at the tail */
|
||||
while (h->next) {
|
||||
const size_t remain = h->next - h->size;
|
||||
if (remain >= whole_size) {
|
||||
auto hprev = h;
|
||||
auto hnext = reinterpret_cast<Header*>(reinterpret_cast<uint8_t*>(hprev) + hprev->next);
|
||||
|
||||
/* creates new block */
|
||||
h = reinterpret_cast<Header*>(reinterpret_cast<uint8_t*>(hprev) + hprev->size);
|
||||
h->prev = hprev->size;
|
||||
h->next = remain;
|
||||
h->size = whole_size;
|
||||
|
||||
/* links the created block with prev and next */
|
||||
hprev->next = h->prev;
|
||||
hnext->prev = h->next;
|
||||
|
||||
@ -74,11 +77,9 @@ public:
|
||||
auto hprev = reinterpret_cast<Header*>(uptr - h->prev);
|
||||
auto hnext = reinterpret_cast<Header*>(uptr + h->next);
|
||||
|
||||
/* unlinks and drops the block */
|
||||
hprev->next += h->next;
|
||||
hnext->prev += h->prev;
|
||||
|
||||
// chaos test
|
||||
// std::memset(h, 0xFF, h->next);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -10,6 +10,8 @@ gj::LoadScene::LoadScene(Param&& p) :
|
||||
}
|
||||
|
||||
gj::UniqPtr<gj::iScene> gj::LoadScene::Update(Frame& frame) {
|
||||
/* if PlayScene is prepared and orphan_ is not busy now,
|
||||
* transition to PlayScene by returning its instance */
|
||||
if (prod_->HasPrepared() && !(orphan_ && orphan_->IsBusy())) {
|
||||
prod_->Start();
|
||||
return std::move(prod_);
|
||||
@ -17,6 +19,7 @@ gj::UniqPtr<gj::iScene> gj::LoadScene::Update(Frame& frame) {
|
||||
|
||||
const uint64_t now = clock_->now();
|
||||
|
||||
/* displays blinking 'Loading...' text */
|
||||
if (XorShift(now+1)%10) {
|
||||
loading_.SetPosition((frame.w - loading_.width())/2, frame.h/2);
|
||||
frame.Add(&loading_);
|
||||
|
13
src/Lua.cc
13
src/Lua.cc
@ -3,6 +3,7 @@
|
||||
#include "thirdparty/lualib.h"
|
||||
|
||||
|
||||
/* pushes variant to Lua stack */
|
||||
struct LuaPusher {
|
||||
LuaPusher() = delete;
|
||||
LuaPusher(lua_State* L) : L(L) {
|
||||
@ -21,6 +22,8 @@ struct LuaPusher {
|
||||
private:
|
||||
lua_State* L;
|
||||
};
|
||||
|
||||
/* takes a value in Lua stack to variant */
|
||||
struct LuaTaker {
|
||||
LuaTaker() = delete;
|
||||
LuaTaker(lua_State* L, int index) : L(L), index_(index) {
|
||||
@ -52,6 +55,7 @@ class LuaFunc : public gj::iElementDriver {
|
||||
LuaFunc& operator=(const LuaFunc&) = delete;
|
||||
|
||||
LuaFunc(lua_State* L, int index) : L(L) {
|
||||
/* registers function and param table*/
|
||||
lua_pushvalue(L, index);
|
||||
func_ = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
@ -63,10 +67,13 @@ class LuaFunc : public gj::iElementDriver {
|
||||
}
|
||||
|
||||
void Update(Param& param, double t) override {
|
||||
/* pushes registered func */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, func_);
|
||||
|
||||
/* pushes current time as the first argument */
|
||||
lua_pushnumber(L, t);
|
||||
|
||||
/* pushes param table as the second argument */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, table_);
|
||||
for (const auto& p : param) {
|
||||
lua_pushstring(L, p.first.c_str());
|
||||
@ -74,11 +81,13 @@ class LuaFunc : public gj::iElementDriver {
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
|
||||
/* calls the function */
|
||||
const int ret = lua_pcall(L, 2, 0, 0);
|
||||
if (ret) {
|
||||
gj::Abort(std::string("Lua error: ")+lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
/* copies values from Lua stack into the param map */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, table_);
|
||||
for (auto& p : param) {
|
||||
lua_pushstring(L, p.first.c_str());
|
||||
@ -107,6 +116,7 @@ static int CallFactory_(lua_State* L) {
|
||||
|
||||
const int n = lua_gettop(L);
|
||||
|
||||
/* takes and validates arguments */
|
||||
const lua_Integer st = luaL_checkinteger(L, 1);
|
||||
const lua_Integer ed = luaL_checkinteger(L, 2);
|
||||
if (st >= ed) {
|
||||
@ -120,6 +130,7 @@ static int CallFactory_(lua_State* L) {
|
||||
param.period = gj::Period(st, ed);
|
||||
param.driver = alloc->MakeUniq<LuaFunc>(L, n);
|
||||
|
||||
/* takes custom params from Lua stack */
|
||||
for (int i = 3; i < n; ++i) {
|
||||
gj::iElementFactory::Param::CustomValue v;
|
||||
if (lua_isnumber(L, i)) {
|
||||
@ -146,6 +157,7 @@ gj::Lua::Lua(iAllocator* alloc, ElementStore* store, const FactoryMap& factory,
|
||||
}
|
||||
luaopen_math(L);
|
||||
|
||||
/* registers all factories as Lua function */
|
||||
for (const auto& f : factory) {
|
||||
lua_pushstring(L, f.first.c_str());
|
||||
|
||||
@ -157,6 +169,7 @@ gj::Lua::Lua(iAllocator* alloc, ElementStore* store, const FactoryMap& factory,
|
||||
lua_rawset(L, LUA_GLOBALSINDEX);
|
||||
}
|
||||
|
||||
/* executes the Lua script */
|
||||
if (0 != luaL_loadfile(L, path.c_str())) {
|
||||
const char* msg = lua_tostring(L, -1);
|
||||
Abort(std::string("luaL_loadfile failure: ") + msg);
|
||||
|
@ -52,6 +52,7 @@ class Music : public iAudioEffect {
|
||||
}
|
||||
seeking_.store(true);
|
||||
|
||||
/* executes seek function in new thread */
|
||||
const size_t frame = static_cast<size_t>(srate_*sec);
|
||||
seeker_ = std::thread([this, frame]() {
|
||||
if (ma_decoder_seek_to_pcm_frame(&dec_, frame) != MA_SUCCESS) {
|
||||
@ -82,6 +83,7 @@ class Music : public iAudioEffect {
|
||||
|
||||
const float volume = volume_.load();
|
||||
|
||||
/* applies volume and LPF */
|
||||
const size_t n = frames * ch_;
|
||||
for (size_t i = 0; i < frames; ++i) {
|
||||
volume_actual_ = volume_actual_*kVolumeLpf + volume*(1-kVolumeLpf);
|
||||
|
@ -18,13 +18,15 @@ gj::UniqPtr<gj::iScene> gj::PlayScene::Update(Frame& f) {
|
||||
|
||||
gj::PlayScene::PlayScene(const Param& p, const std::string& title, const std::string& path) :
|
||||
param_(p), clock_(p.clock), store_(256) {
|
||||
sb_.title = ConvertStrToWstr(title);
|
||||
|
||||
/* creates factory instances and pass them to the Lua.
|
||||
* actually these factories are used in only Lua's constructor,
|
||||
* so it's no problem that they're on stack */
|
||||
GlyphElementFactory glyph(p.alloc);
|
||||
InputWindowElementFactory inputWin(p.alloc, &sb_);
|
||||
MusicElementFactory music(p.alloc, p.audio);
|
||||
|
||||
sb_.title = ConvertStrToWstr(title);
|
||||
|
||||
Lua::FactoryMap map = {
|
||||
{ "Glyph", &glyph },
|
||||
{ "InputWin", &inputWin },
|
||||
|
@ -23,6 +23,7 @@ gj::UniqPtr<gj::iScene> gj::ResultScene::Update(Frame& f) {
|
||||
const int32_t correct_y = static_cast<int32_t>(h * .35);
|
||||
const int32_t line_y = static_cast<int32_t>(h * .45);
|
||||
|
||||
/* calculates geometries of all objects to be displayed */
|
||||
title_.SetPosition((w-title_.width())/2, title_y);
|
||||
f.Add(&title_);
|
||||
|
||||
@ -53,6 +54,7 @@ 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 the input includes ' ', transitions to TitleScene */
|
||||
if (f.input.find(' ') != std::string::npos) {
|
||||
return param_.alloc->MakeUniq<TitleScene>(param_);
|
||||
}
|
||||
|
@ -31,12 +31,15 @@ class Text : public WritableBase {
|
||||
int32_t x = x_, y = y_;
|
||||
if (y >= h) return;
|
||||
|
||||
/* copies text to the textbuffer */
|
||||
const size_t len = entity_.size();
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (x < 0) continue;
|
||||
if (x >= w) return;
|
||||
|
||||
ptr[x+y*w] = entity_[i];
|
||||
|
||||
/* multi-byte chars requires space of two chars */
|
||||
x += (entity_[i] > UINT8_MAX)? 2: 1;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ void gj::Texture::Draw(Colorbuffer& fb) const {
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
p[i] = ::linalg::mul(mat_, p[i]);
|
||||
}
|
||||
|
||||
/* calculates coordinates of each edge of rect covering the draw area in dst */
|
||||
const double pl = std::min({p[0].x, p[1].x, p[2].x, p[3].x})-.1;
|
||||
const double pr = std::max({p[0].x, p[1].x, p[2].x, p[3].x})+.1;
|
||||
const double pu = std::max({p[0].y, p[1].y, p[2].y, p[3].y})+.1;
|
||||
@ -25,6 +27,7 @@ void gj::Texture::Draw(Colorbuffer& fb) const {
|
||||
const double pw = pr - pl;
|
||||
const double ph = pu - pb;
|
||||
|
||||
/* converts the dst edge coordinates to integers */
|
||||
const int32_t pli = static_cast<int32_t>((pl + 1) / 2 * w);
|
||||
const int32_t pri = static_cast<int32_t>((pr + 1) / 2 * w);
|
||||
const int32_t pui = static_cast<int32_t>((pu + 1) / 2 * h);
|
||||
@ -42,11 +45,14 @@ void gj::Texture::Draw(Colorbuffer& fb) const {
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
q[i] = ::linalg::mul(invmat_, q[i]);
|
||||
}
|
||||
|
||||
/* calculates coordinates of each edge of rect covering the draw area in src */
|
||||
const double ql = std::min({q[0].x, q[1].x, q[2].x, q[3].x});
|
||||
const double qr = std::max({q[0].x, q[1].x, q[2].x, q[3].x});
|
||||
const double qu = std::max({q[0].y, q[1].y, q[2].y, q[3].y});
|
||||
const double qb = std::min({q[0].y, q[1].y, q[2].y, q[3].y});
|
||||
|
||||
/* converts the src edge coordinates to integers */
|
||||
const double qldx = q[0].x - q[1].x;
|
||||
const double qrdx = q[3].x - q[2].x;
|
||||
const double qldy = q[0].y - q[1].y;
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
const double c = std::cos(rota);
|
||||
const double s = std::sin(rota);
|
||||
|
||||
/* calculates matrix */
|
||||
auto Ms = mat3{
|
||||
{ scaleX, 0, 0 },
|
||||
{ 0, scaleY, 0 },
|
||||
@ -59,6 +60,7 @@ public:
|
||||
M = ::linalg::mul(M, Mr);
|
||||
M = ::linalg::mul(M, Ms);
|
||||
|
||||
/* applies calculated results */
|
||||
tex_.SetMatrix(M);
|
||||
tex_.SetAlpha(static_cast<float>(alpha));
|
||||
|
||||
|
@ -29,6 +29,7 @@ gj::TitleScene::TitleScene(const Param& p) :
|
||||
|
||||
if (err.size()) Abort(std::string(kListPath)+": "+err);
|
||||
|
||||
/* iterates all json objects */
|
||||
std::string line;
|
||||
auto& list = root.get<::picojson::array>();
|
||||
for (auto& e : list) {
|
||||
@ -122,6 +123,8 @@ gj::UniqPtr<gj::iScene> gj::TitleScene::Update(Frame& frame) {
|
||||
{0, 0, 1},
|
||||
};
|
||||
M = ::linalg::mul(Mr, M);
|
||||
|
||||
/* applies calculation results */
|
||||
logo_.SetMatrix(M);
|
||||
frame.Add(&logo_);
|
||||
|
||||
|
@ -42,6 +42,7 @@ class Win32Console : public iConsole {
|
||||
gj::Abort("GetStdHandle returned nullptr");
|
||||
}
|
||||
|
||||
/* resizes the window */
|
||||
CONSOLE_SCREEN_BUFFER_INFOEX size;
|
||||
size.cbSize = sizeof(size);
|
||||
|
||||
@ -57,8 +58,11 @@ class Win32Console : public iConsole {
|
||||
size.srWindow.Bottom = h_ + 1;
|
||||
SetConsoleScreenBufferInfoEx(screen_, &size);
|
||||
|
||||
ShowWindow(win_, FALSE);
|
||||
/* restricts resizing by user and maximizing */
|
||||
SetWindowLong(win_, GWL_STYLE, GetWindowLong(win_, GWL_STYLE) & ~(WS_SIZEBOX | WS_MAXIMIZEBOX));
|
||||
|
||||
/* shows window */
|
||||
ShowWindow(win_, FALSE);
|
||||
}
|
||||
~Win32Console() {
|
||||
alive_.store(false);
|
||||
|
Reference in New Issue
Block a user