Adds comments on codes.

This commit is contained in:
falsycat 2021-08-31 13:42:28 +09:00
parent 7688f38dab
commit c9a9f79a7c
18 changed files with 85 additions and 11 deletions

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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));
}
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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:

View File

@ -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_);

View File

@ -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);

View File

@ -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);

View File

@ -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 },

View File

@ -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_);
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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));

View File

@ -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_);

View File

@ -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);