diff --git a/src/AudioDevice.cc b/src/AudioDevice.cc index 07f74e6..34ccc24 100644 --- a/src/AudioDevice.cc +++ b/src/AudioDevice.cc @@ -27,8 +27,11 @@ void gj::AudioDevice::Callback_(ma_device* ma, void* out, const void* in, ma_uin AudioDevice* dev = reinterpret_cast(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(out), framecnt); } + + /* count up the time */ dev->time_.fetch_add(framecnt); } \ No newline at end of file diff --git a/src/ElementStore.h b/src/ElementStore.h index 5996912..1ecd8bf 100644 --- a/src/ElementStore.h +++ b/src/ElementStore.h @@ -29,13 +29,20 @@ class ElementStore { void Schedule(UniqPtr&& 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) { diff --git a/src/Font.cc b/src/Font.cc index 796bbc7..06eda12 100644 --- a/src/Font.cc +++ b/src/Font.cc @@ -9,7 +9,7 @@ gj::Colorbuffer gj::Font::RenderGlyphs(const std::wstring& str, uint32_t fontsiz const int baseline = static_cast(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; diff --git a/src/Font.h b/src/Font.h index 005d8f6..d85868c 100644 --- a/src/Font.h +++ b/src/Font.h @@ -33,9 +33,11 @@ class Font { const size_t size = ifs.tellg(); ifs.seekg(0); + /* reads all contents from the file */ buf_ = alloc_->MakeUniqArray(size); ifs.read(reinterpret_cast(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(*src*1./UINT8_MAX); diff --git a/src/GlitchPosteffect.h b/src/GlitchPosteffect.h index e34d44f..1c1c56d 100644 --- a/src/GlitchPosteffect.h +++ b/src/GlitchPosteffect.h @@ -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(w*shift); const int32_t as = std::abs(s); + /* get pointers to actual data */ float* src = ptr + static_cast(y) * w; float* dst = src + as; if (s < 0) std::swap(src, dst); + /* shifts pixels */ std::memmove(dst, src, (static_cast(w) - as)*sizeof(*ptr)); } } diff --git a/src/GlyphElementFactory.h b/src/GlyphElementFactory.h index aeda0de..5af97b2 100644 --- a/src/GlyphElementFactory.h +++ b/src/GlyphElementFactory.h @@ -29,9 +29,11 @@ class GlyphElementFactory : public iElementFactory { const std::string name = std::get(param.custom[1]); const uint32_t size = static_cast(std::get(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( param.period, std::move(tex), std::move(param.driver)); } diff --git a/src/HiraganaMatcher.cc b/src/HiraganaMatcher.cc index 9f4a6a4..5c66f5c 100644 --- a/src/HiraganaMatcher.cc +++ b/src/HiraganaMatcher.cc @@ -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); } diff --git a/src/LinearAllocator.h b/src/LinearAllocator.h index 3c79e72..388f9ae 100644 --- a/src/LinearAllocator.h +++ b/src/LinearAllocator.h @@ -45,17 +45,20 @@ public: auto h = reinterpret_cast(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(reinterpret_cast(hprev) + hprev->next); + /* creates new block */ h = reinterpret_cast(reinterpret_cast(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(uptr - h->prev); auto hnext = reinterpret_cast(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: diff --git a/src/LoadScene.cc b/src/LoadScene.cc index bf2009e..32ef8d1 100644 --- a/src/LoadScene.cc +++ b/src/LoadScene.cc @@ -10,6 +10,8 @@ gj::LoadScene::LoadScene(Param&& p) : } gj::UniqPtr 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::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_); diff --git a/src/Lua.cc b/src/Lua.cc index 54e2c40..e29b6bb 100644 --- a/src/Lua.cc +++ b/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(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); diff --git a/src/Music.h b/src/Music.h index 2c95fae..d6adbac 100644 --- a/src/Music.h +++ b/src/Music.h @@ -52,6 +52,7 @@ class Music : public iAudioEffect { } seeking_.store(true); + /* executes seek function in new thread */ const size_t frame = static_cast(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); diff --git a/src/PlayScene.cc b/src/PlayScene.cc index 274e102..c2e4c20 100644 --- a/src/PlayScene.cc +++ b/src/PlayScene.cc @@ -18,13 +18,15 @@ gj::UniqPtr 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 }, diff --git a/src/ResultScene.cc b/src/ResultScene.cc index f44d47d..ae5dfa7 100644 --- a/src/ResultScene.cc +++ b/src/ResultScene.cc @@ -23,6 +23,7 @@ gj::UniqPtr gj::ResultScene::Update(Frame& f) { const int32_t correct_y = static_cast(h * .35); const int32_t line_y = static_cast(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::ResultScene::Update(Frame& f) { guide_.SetPosition((w-guide_.width())/2, static_cast(h*.8)); f.Add(&guide_); + /* if the input includes ' ', transitions to TitleScene */ if (f.input.find(' ') != std::string::npos) { return param_.alloc->MakeUniq(param_); } diff --git a/src/Text.h b/src/Text.h index 74c7f5a..1f5c825 100644 --- a/src/Text.h +++ b/src/Text.h @@ -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; } } diff --git a/src/Texture.cc b/src/Texture.cc index 9b3588f..ea2e86e 100644 --- a/src/Texture.cc +++ b/src/Texture.cc @@ -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((pl + 1) / 2 * w); const int32_t pri = static_cast((pr + 1) / 2 * w); const int32_t pui = static_cast((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; diff --git a/src/TextureElement.h b/src/TextureElement.h index 4877a06..16ae03c 100644 --- a/src/TextureElement.h +++ b/src/TextureElement.h @@ -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(alpha)); diff --git a/src/TitleScene.cc b/src/TitleScene.cc index dae3bae..0bf6705 100644 --- a/src/TitleScene.cc +++ b/src/TitleScene.cc @@ -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::TitleScene::Update(Frame& frame) { {0, 0, 1}, }; M = ::linalg::mul(Mr, M); + + /* applies calculation results */ logo_.SetMatrix(M); frame.Add(&logo_); diff --git a/src/Win32Console.h b/src/Win32Console.h index 68f0388..432e2ca 100644 --- a/src/Win32Console.h +++ b/src/Win32Console.h @@ -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);