Implements calling Lua.
This commit is contained in:
4
src/Font.cc
Normal file
4
src/Font.cc
Normal file
@@ -0,0 +1,4 @@
|
||||
/* Because an implementation of stb_truetype is huge, compiles it separately. */
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "Font.h"
|
73
src/Font.h
Normal file
73
src/Font.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "thirdparty/stb_truetype.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "iAllocator.h"
|
||||
#include "Rasterbuffer.h"
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class Font {
|
||||
public:
|
||||
Font() = delete;
|
||||
Font(Font&&) = delete;
|
||||
Font(const Font&) = delete;
|
||||
|
||||
Font& operator=(Font&&) = delete;
|
||||
Font& operator=(const Font&) = delete;
|
||||
|
||||
Font(iAllocator* alloc, const std::string& path) : alloc_(alloc) {
|
||||
std::ifstream ifs(path, std::ios::binary);
|
||||
if (!ifs) {
|
||||
Abort("failed to open: "+path);
|
||||
}
|
||||
|
||||
ifs.seekg(0, std::ios::end);
|
||||
const size_t size = ifs.tellg();
|
||||
ifs.seekg(0);
|
||||
|
||||
buf_ = alloc_->MakeUniqArray<uint8_t>(size);
|
||||
ifs.read(reinterpret_cast<char*>(buf_.get()), size);
|
||||
|
||||
const int offset = stbtt_GetFontOffsetForIndex(buf_.get(), 0);
|
||||
if (!stbtt_InitFont(&stb_, buf_.get(), offset)) {
|
||||
Abort("invalid font: "+path);
|
||||
}
|
||||
}
|
||||
|
||||
Colorbuffer&& RenderGlyph(char16_t c, uint32_t fontsize = 32) {
|
||||
int w, h;
|
||||
|
||||
const float s = stbtt_ScaleForPixelHeight(&stb_, fontsize*1.f);
|
||||
|
||||
const uint8_t* src = stbtt_GetCodepointBitmap(&stb_, 0, s, c, &w, &h, 0, 0);
|
||||
|
||||
Colorbuffer ret(alloc_, w, h);
|
||||
float* dst = ret.ptr();
|
||||
|
||||
for (int y = 0; y < h; ++y) {
|
||||
for (int x = 0; x < w; ++x) {
|
||||
*dst = static_cast<float>(*src*1./UINT8_MAX);
|
||||
++dst, ++src;
|
||||
}
|
||||
}
|
||||
return std::move(ret);
|
||||
}
|
||||
|
||||
private:
|
||||
iAllocator* alloc_;
|
||||
|
||||
stbtt_fontinfo stb_;
|
||||
|
||||
UniqPtr<uint8_t> buf_;
|
||||
};
|
||||
|
||||
|
||||
}
|
55
src/Frame.h
Normal file
55
src/Frame.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "iDrawable.h"
|
||||
#include "iWritable.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class Frame : public iDrawable, public iWritable {
|
||||
public:
|
||||
Frame() = delete;
|
||||
Frame(Frame&&) = delete;
|
||||
Frame(const Frame&) = delete;
|
||||
|
||||
Frame& operator=(Frame&&) = delete;
|
||||
Frame& operator=(const Frame&) = delete;
|
||||
|
||||
Frame(size_t dres, size_t wres) {
|
||||
draw_.reserve(dres);
|
||||
write_.reserve(wres);
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
draw_.clear();
|
||||
write_.clear();
|
||||
}
|
||||
|
||||
void Add(const iDrawable* d) {
|
||||
draw_.push_back(d);
|
||||
}
|
||||
void Add(const iWritable* w) {
|
||||
write_.push_back(w);
|
||||
}
|
||||
|
||||
void Draw(Colorbuffer& fb) const override {
|
||||
for (auto d : draw_) {
|
||||
d->Draw(fb);
|
||||
}
|
||||
}
|
||||
void Write(Textbuffer& fb) const override {
|
||||
for (auto w : write_) {
|
||||
w->Write(fb);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<const iDrawable*> draw_;
|
||||
std::vector<const iWritable*> write_;
|
||||
};
|
||||
|
||||
|
||||
}
|
19
src/Game.cc
Normal file
19
src/Game.cc
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "Game.h"
|
||||
#include "PlayScene.h"
|
||||
|
||||
|
||||
gj::Game::Game(gj::Game::Param&& p) :
|
||||
alloc_(p.alloc),
|
||||
clock_(p.clock),
|
||||
logger_(p.h),
|
||||
w_(p.w), h_(p.h),
|
||||
frame_(kReserveDrawable, kReserveWritable) {
|
||||
gj::PlayScene::Param param;
|
||||
param.alloc = alloc_;
|
||||
param.clock = &clock_;
|
||||
param.logger = &logger_;
|
||||
param.w = w_;
|
||||
param.h = h_;
|
||||
param.score = "test"; /* TODO test */
|
||||
scene_ = alloc_->MakeUniq<gj::iScene, gj::PlayScene>(std::move(param));
|
||||
}
|
70
src/Game.h
Normal file
70
src/Game.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "Frame.h"
|
||||
#include "iDrawable.h"
|
||||
#include "iWritable.h"
|
||||
#include "iScene.h"
|
||||
#include "Logger.h"
|
||||
#include "TickingClock.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class Game : public iDrawable, public iWritable {
|
||||
public:
|
||||
static constexpr size_t kReserveDrawable = 256;
|
||||
static constexpr size_t kReserveWritable = 64;
|
||||
|
||||
struct Param {
|
||||
iAllocator* alloc;
|
||||
const iClock* clock;
|
||||
|
||||
uint32_t w, h;
|
||||
};
|
||||
|
||||
Game() = delete;
|
||||
Game(Game&&) = delete;
|
||||
Game(const Game&) = delete;
|
||||
|
||||
Game& operator=(Game&&) = delete;
|
||||
Game& operator=(const Game&) = delete;
|
||||
|
||||
Game(Param&& p);
|
||||
|
||||
void Update() {
|
||||
clock_.Tick();
|
||||
|
||||
frame_.Clear();
|
||||
UniqPtr<iScene> next = scene_->Update(frame_);
|
||||
if (next) {
|
||||
scene_ = std::move(next);
|
||||
}
|
||||
}
|
||||
|
||||
void Draw(Colorbuffer& fb) const override {
|
||||
frame_.Draw(fb);
|
||||
}
|
||||
void Write(Textbuffer& fb) const override {
|
||||
frame_.Write(fb);
|
||||
logger_.Write(fb);
|
||||
}
|
||||
|
||||
private:
|
||||
iAllocator* alloc_;
|
||||
TickingClock clock_;
|
||||
|
||||
Logger logger_;
|
||||
|
||||
uint32_t w_, h_;
|
||||
Frame frame_;
|
||||
|
||||
UniqPtr<iScene> scene_;
|
||||
};
|
||||
|
||||
|
||||
}
|
97
src/LinearAllocator.h
Normal file
97
src/LinearAllocator.h
Normal file
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "common.h"
|
||||
#include "iAllocator.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class LinearAllocator : public iAllocator {
|
||||
public:
|
||||
using iAllocator::Alloc;
|
||||
using iAllocator::MakeUniq;
|
||||
|
||||
LinearAllocator() = delete;
|
||||
LinearAllocator(LinearAllocator&&) = delete;
|
||||
LinearAllocator(const LinearAllocator&) = delete;
|
||||
|
||||
LinearAllocator& operator=(LinearAllocator&&) = delete;
|
||||
LinearAllocator& operator=(const LinearAllocator&) = delete;
|
||||
|
||||
LinearAllocator(void* ptr, const size_t size) :
|
||||
ptr_(static_cast<uint8_t*>(ptr)) {
|
||||
assert(size >= sizeof(Header)*2);
|
||||
|
||||
auto head = reinterpret_cast<Header*>(ptr_);
|
||||
head->prev = 0;
|
||||
head->next = size - sizeof(Header);
|
||||
head->size = sizeof(Header);
|
||||
|
||||
auto tail = reinterpret_cast<Header*>(ptr_+head->next);
|
||||
tail->prev = head->next;
|
||||
tail->next = 0;
|
||||
tail->size = sizeof(Header);
|
||||
}
|
||||
|
||||
void* Alloc(const size_t size) override {
|
||||
const size_t aligned_size = (((size >> 3) + !!(size & 0b111))) << 3;
|
||||
const size_t whole_size = sizeof(Header) + aligned_size;
|
||||
assert(aligned_size >= size);
|
||||
|
||||
auto h = reinterpret_cast<Header*>(ptr_);
|
||||
|
||||
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);
|
||||
|
||||
h = reinterpret_cast<Header*>(reinterpret_cast<uint8_t*>(hprev) + hprev->size);
|
||||
h->prev = hprev->size;
|
||||
h->next = remain;
|
||||
h->size = whole_size;
|
||||
|
||||
hprev->next = h->prev;
|
||||
hnext->prev = h->next;
|
||||
|
||||
return h + 1;
|
||||
}
|
||||
h = reinterpret_cast<Header*>(reinterpret_cast<uint8_t*>(h) + h->next);
|
||||
}
|
||||
Abort("LinearAllocator Allocation Failure");
|
||||
}
|
||||
|
||||
void Free(void* ptr) override {
|
||||
if (!ptr) return;
|
||||
uint8_t* uptr = reinterpret_cast<uint8_t*>(ptr) - sizeof(Header);
|
||||
|
||||
auto h = reinterpret_cast<Header*>(uptr);
|
||||
auto hprev = reinterpret_cast<Header*>(uptr - h->prev);
|
||||
auto hnext = reinterpret_cast<Header*>(uptr + h->next);
|
||||
|
||||
hprev->next += h->next;
|
||||
hnext->prev += h->prev;
|
||||
}
|
||||
|
||||
private:
|
||||
/* |------prev--------||--------next--------| */
|
||||
/* |----size-----| */
|
||||
/* memory: HHAAAAAAAAAAAAAAAAUUHHAAAAAAAAAAAAAUUUUUUUHHAAAAA */
|
||||
/* H: header, A: allocated area, U: unused area */
|
||||
struct Header {
|
||||
size_t prev;
|
||||
size_t next;
|
||||
size_t size;
|
||||
};
|
||||
static_assert(sizeof(Header) == sizeof(size_t)*3, "padding detected in memory header");
|
||||
|
||||
uint8_t* const ptr_;
|
||||
};
|
||||
|
||||
|
||||
}
|
52
src/Logger.h
Normal file
52
src/Logger.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "iDrawable.h"
|
||||
#include "iLogger.h"
|
||||
#include "Text.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class Logger : public iWritable, public iLogger {
|
||||
public:
|
||||
Logger(Logger&&) = delete;
|
||||
Logger(const Logger&) = delete;
|
||||
|
||||
Logger& operator=(Logger&&) = delete;
|
||||
Logger& operator=(const Logger&) = delete;
|
||||
|
||||
Logger(uint32_t height) : height_(height) {
|
||||
}
|
||||
|
||||
void Write(Textbuffer& fb) const override {
|
||||
for (const auto& text : lines_) {
|
||||
text.Write(fb);
|
||||
}
|
||||
}
|
||||
|
||||
void Print(const std::wstring& msg) override {
|
||||
size_t n = lines_.size();
|
||||
|
||||
if (n >= height_) {
|
||||
lines_.erase(lines_.begin());
|
||||
--n;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
lines_[i].SetPosition(0, static_cast<int32_t>(i));
|
||||
}
|
||||
}
|
||||
|
||||
Text text(msg, 0, static_cast<uint32_t>(n));
|
||||
lines_.push_back(std::move(text));
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t height_;
|
||||
|
||||
std::vector<Text> lines_;
|
||||
};
|
||||
|
||||
|
||||
}
|
119
src/Lua.cc
Normal file
119
src/Lua.cc
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "Lua.h"
|
||||
|
||||
|
||||
class LuaFunc : public gj::iElementDriver {
|
||||
public:
|
||||
LuaFunc() = delete;
|
||||
LuaFunc(LuaFunc&&) = delete;
|
||||
LuaFunc(const LuaFunc&) = delete;
|
||||
|
||||
LuaFunc& operator=(LuaFunc&&) = delete;
|
||||
LuaFunc& operator=(const LuaFunc&) = delete;
|
||||
|
||||
LuaFunc(lua_State* L) : L(L) {
|
||||
func_ = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
lua_createtable(L, 0, 0);
|
||||
table_ = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
~LuaFunc() {
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, func_);
|
||||
}
|
||||
|
||||
void Update(Param& param) override {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, func_);
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, table_);
|
||||
for (const auto& p : param) {
|
||||
lua_pushstring(L, p.first.c_str());
|
||||
if (std::holds_alternative<int64_t>(p.second)) {
|
||||
lua_pushinteger(L, std::get<int64_t>(p.second));
|
||||
} else if (std::holds_alternative<double>(p.second)) {
|
||||
lua_pushnumber(L, std::get<double>(p.second));
|
||||
} else if (std::holds_alternative<std::string>(p.second)) {
|
||||
const std::string str = std::get<std::string>(p.second);
|
||||
lua_pushstring(L, str.c_str());
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
|
||||
const int ret = lua_pcall(L, 1, 0, 0);
|
||||
if (ret) {
|
||||
gj::Abort(std::string("Lua error: ")+lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, table_);
|
||||
for (auto& p : param) {
|
||||
lua_pushstring(L, p.first.c_str());
|
||||
lua_rawget(L, -2);
|
||||
|
||||
if (std::holds_alternative<int64_t>(p.second)) {
|
||||
p.second = luaL_checkinteger(L, -1);
|
||||
} else if (std::holds_alternative<double>(p.second)) {
|
||||
p.second = luaL_checknumber(L, -1);
|
||||
} else if (std::holds_alternative<std::string>(p.second)) {
|
||||
p.second = luaL_checkstring(L, -1);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
private:
|
||||
lua_State* L;
|
||||
|
||||
int func_ = LUA_REFNIL;
|
||||
int table_ = LUA_REFNIL;
|
||||
};
|
||||
|
||||
|
||||
static int CallFactory_(lua_State* L) {
|
||||
gj::iAllocator* alloc =
|
||||
reinterpret_cast<gj::iAllocator*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
gj::iElementFactory* factory =
|
||||
reinterpret_cast<gj::iElementFactory*>(lua_touserdata(L, lua_upvalueindex(2)));
|
||||
|
||||
const lua_Integer st = luaL_checkinteger(L, 1);
|
||||
const lua_Integer ed = luaL_checkinteger(L, 2);
|
||||
if (st >= ed) {
|
||||
return luaL_error(L, "invalid period");
|
||||
}
|
||||
if (!lua_isfunction(L, 3)) {
|
||||
return luaL_error(L, "no driver specified");
|
||||
}
|
||||
|
||||
lua_pushvalue(L, 3);
|
||||
factory->Create(gj::Period(st, ed), alloc->MakeUniq<gj::iElementDriver, LuaFunc>(L));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
gj::Lua::Lua(iAllocator* alloc, const FactoryMap& factory, const std::string& path) {
|
||||
L = luaL_newstate();
|
||||
if (L == nullptr) {
|
||||
Abort("lua_newstate failure");
|
||||
}
|
||||
|
||||
for (const auto& f : factory) {
|
||||
lua_pushstring(L, f.first.c_str());
|
||||
|
||||
lua_pushlightuserdata(L, alloc);
|
||||
lua_pushlightuserdata(L, f.second);
|
||||
lua_pushcclosure(L, CallFactory_, 2);
|
||||
|
||||
lua_rawset(L, LUA_GLOBALSINDEX);
|
||||
}
|
||||
|
||||
if (0 != luaL_loadfile(L, path.c_str())) {
|
||||
const char* msg = lua_tostring(L, -1);
|
||||
Abort(std::string("luaL_loadfile failure: ") + msg);
|
||||
}
|
||||
const int ret = lua_pcall(L, 0, 0, 0);
|
||||
if (ret) {
|
||||
gj::Abort(std::string("Lua error: ") + lua_tostring(L, -1));
|
||||
}
|
||||
}
|
38
src/Lua.h
Normal file
38
src/Lua.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "thirdparty/lua.hpp"
|
||||
|
||||
#include "common.h"
|
||||
#include "iAllocator.h"
|
||||
#include "iElementFactory.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class Lua {
|
||||
public:
|
||||
using FactoryMap = std::map<std::string, iElementFactory*>;
|
||||
|
||||
Lua() = delete;
|
||||
Lua(Lua&&) = delete;
|
||||
Lua(const Lua&) = delete;
|
||||
|
||||
Lua& operator=(Lua&&) = delete;
|
||||
Lua& operator=(const Lua&) = delete;
|
||||
|
||||
Lua(iAllocator* alloc, const FactoryMap& factory, const std::string& path);
|
||||
|
||||
~Lua() {
|
||||
lua_close(L);
|
||||
}
|
||||
|
||||
private:
|
||||
lua_State* L = nullptr;
|
||||
};
|
||||
|
||||
|
||||
}
|
38
src/OffsetClock.h
Normal file
38
src/OffsetClock.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#undef NOMINMAX
|
||||
|
||||
#include "iClock.h"
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class OffsetClock : public iClock {
|
||||
public:
|
||||
OffsetClock(OffsetClock&&) = default;
|
||||
OffsetClock(const OffsetClock&) = default;
|
||||
|
||||
OffsetClock& operator=(OffsetClock&&) = default;
|
||||
OffsetClock& operator=(const OffsetClock&) = default;
|
||||
|
||||
OffsetClock(const iClock* parent, uint64_t offset) :
|
||||
parent_(parent), offset_(offset) {
|
||||
}
|
||||
OffsetClock(const iClock* parent) : OffsetClock(parent, parent->now()) {
|
||||
}
|
||||
|
||||
uint64_t now() const override {
|
||||
return parent_->now() - offset_;
|
||||
}
|
||||
|
||||
private:
|
||||
const iClock* parent_;
|
||||
uint64_t offset_;
|
||||
};
|
||||
|
||||
|
||||
}
|
29
src/Period.h
Normal file
29
src/Period.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
struct Period {
|
||||
public:
|
||||
Period() = delete;
|
||||
|
||||
Period(uint64_t st, uint64_t ed) : start(st), end(ed) {
|
||||
assert(st <= ed);
|
||||
}
|
||||
|
||||
bool isHit(uint64_t now) const {
|
||||
return start <= now && now < end;
|
||||
}
|
||||
|
||||
uint64_t duration() const {
|
||||
return end - start;
|
||||
}
|
||||
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
};
|
||||
|
||||
|
||||
}
|
10
src/PlayScene.cc
Normal file
10
src/PlayScene.cc
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "PlayScene.h"
|
||||
|
||||
|
||||
gj::PlayScene::PlayScene(gj::PlayScene::Param&& p) :
|
||||
alloc_(p.alloc), logger_(p.logger), w_(p.w), h_(p.h),
|
||||
clock_(p.clock) {
|
||||
lua_ = alloc_->MakeUniq<Lua>(alloc_, Lua::FactoryMap(), "res/score/"+p.score+".lua");
|
||||
|
||||
logger_->Print(L"PlayScene init");
|
||||
}
|
51
src/PlayScene.h
Normal file
51
src/PlayScene.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "Frame.h"
|
||||
#include "iAllocator.h"
|
||||
#include "iLogger.h"
|
||||
#include "iScene.h"
|
||||
#include "Lua.h"
|
||||
#include "OffsetClock.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class PlayScene : public iScene {
|
||||
public:
|
||||
struct Param {
|
||||
iAllocator* alloc;
|
||||
iLogger* logger;
|
||||
const iClock* clock;
|
||||
|
||||
uint32_t w, h;
|
||||
|
||||
std::string score;
|
||||
};
|
||||
|
||||
PlayScene() = delete;
|
||||
PlayScene(PlayScene&&) = delete;
|
||||
PlayScene(const PlayScene&) = delete;
|
||||
|
||||
PlayScene& operator=(PlayScene&&) = delete;
|
||||
PlayScene& operator=(const PlayScene&) = delete;
|
||||
|
||||
PlayScene(Param&& p);
|
||||
|
||||
UniqPtr<iScene> Update(Frame& f) override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
iAllocator* alloc_;
|
||||
iLogger* logger_;
|
||||
|
||||
uint32_t w_, h_;
|
||||
|
||||
OffsetClock clock_;
|
||||
|
||||
UniqPtr<Lua> lua_;
|
||||
};
|
||||
|
||||
|
||||
}
|
72
src/Rasterbuffer.h
Normal file
72
src/Rasterbuffer.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "iAllocator.h"
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
template <typename T>
|
||||
class Rasterbuffer {
|
||||
public:
|
||||
Rasterbuffer() = delete;
|
||||
Rasterbuffer(const Rasterbuffer&) = delete;
|
||||
Rasterbuffer& operator=(const Rasterbuffer&) = delete;
|
||||
|
||||
Rasterbuffer(iAllocator* alloc, uint32_t w, uint32_t h) :
|
||||
alloc_(alloc), w_(w), h_(h),
|
||||
buf_(alloc->Alloc<T>(static_cast<uint64_t>(w_)*h_)) {
|
||||
_ASSERT(buf_ != nullptr);
|
||||
}
|
||||
~Rasterbuffer() {
|
||||
alloc_->Free(buf_);
|
||||
}
|
||||
|
||||
Rasterbuffer(Rasterbuffer&& src) noexcept :
|
||||
alloc_(src.alloc_), w_(src.w_), h_(src.h_), buf_(src.buf_) {
|
||||
src.buf_ = nullptr;
|
||||
}
|
||||
Rasterbuffer& operator=(Rasterbuffer&& src) noexcept {
|
||||
if (this != &src) {
|
||||
alloc_ = src.alloc_;
|
||||
w_ = src.w_;
|
||||
h_ = src.h_;
|
||||
buf_ = src.buf_;
|
||||
src.buf_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void Clear() {
|
||||
memset(buf_, 0, static_cast<uint64_t>(w_) * h_ * sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
uint32_t width() const {
|
||||
return w_;
|
||||
}
|
||||
uint32_t height() const {
|
||||
return h_;
|
||||
}
|
||||
T* ptr() {
|
||||
return buf_;
|
||||
}
|
||||
const T* ptr() const {
|
||||
return buf_;
|
||||
}
|
||||
|
||||
private:
|
||||
iAllocator* alloc_;
|
||||
|
||||
uint32_t w_, h_;
|
||||
T* buf_;
|
||||
};
|
||||
|
||||
using Colorbuffer = Rasterbuffer<float>;
|
||||
using Textbuffer = Rasterbuffer<char16_t>;
|
||||
|
||||
|
||||
}
|
63
src/StackAllocator.h
Normal file
63
src/StackAllocator.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "iAllocator.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class StackAllocator : public iAllocator {
|
||||
public:
|
||||
using iAllocator::Alloc;
|
||||
using iAllocator::MakeUniq;
|
||||
|
||||
StackAllocator() = delete;
|
||||
StackAllocator(StackAllocator&&) = delete;
|
||||
StackAllocator(const StackAllocator&) = delete;
|
||||
|
||||
StackAllocator& operator=(StackAllocator&&) = delete;
|
||||
StackAllocator& operator=(const StackAllocator&) = delete;
|
||||
|
||||
StackAllocator(void* ptr, const size_t size) :
|
||||
begin_(static_cast<uint8_t*>(ptr)),
|
||||
end_ (begin_+size),
|
||||
next_ (begin_) {
|
||||
}
|
||||
~StackAllocator() {
|
||||
assert(refcnt_ == 0);
|
||||
}
|
||||
|
||||
void* Alloc(const size_t size) override {
|
||||
const size_t aligned_size = ((size >> 3) + !!(size & 0b111)) << 3;
|
||||
|
||||
void* ret = next_;
|
||||
next_ += aligned_size;
|
||||
if (next_ >= end_) {
|
||||
return nullptr;
|
||||
}
|
||||
++refcnt_;
|
||||
return ret;
|
||||
}
|
||||
void Free(void* ptr) override {
|
||||
if (!ptr) return;
|
||||
|
||||
assert(refcnt_);
|
||||
if (--refcnt_ == 0) {
|
||||
next_ = begin_;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t* const begin_;
|
||||
uint8_t* const end_;
|
||||
uint8_t* next_;
|
||||
|
||||
size_t refcnt_ = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
35
src/SystemClock.h
Normal file
35
src/SystemClock.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#undef NOMINMAX
|
||||
|
||||
#include "iClock.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class SystemClock : public iClock {
|
||||
public:
|
||||
static const SystemClock& instance() {
|
||||
static const SystemClock instance_;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
SystemClock() = default;
|
||||
SystemClock(SystemClock&&) = default;
|
||||
SystemClock(const SystemClock&) = default;
|
||||
|
||||
SystemClock& operator=(SystemClock&&) = default;
|
||||
SystemClock& operator=(const SystemClock&) = default;
|
||||
|
||||
uint64_t now() const override {
|
||||
return GetTickCount64();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
47
src/Text.h
Normal file
47
src/Text.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "iWritable.h"
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class Text : public WritableBase {
|
||||
public:
|
||||
Text(Text&&) = default;
|
||||
Text(const Text&) = default;
|
||||
|
||||
Text& operator=(Text&&) = default;
|
||||
Text& operator=(const Text&) = default;
|
||||
|
||||
Text(const std::wstring& str, uint32_t x = 0, uint32_t y = 0) :
|
||||
WritableBase(x, y), entity_(str) {
|
||||
}
|
||||
|
||||
void Write(Textbuffer& fb) const override {
|
||||
const int32_t w = static_cast<int32_t>(fb.width());
|
||||
const int32_t h = static_cast<int32_t>(fb.height());
|
||||
|
||||
char16_t* ptr = fb.ptr();
|
||||
|
||||
int32_t x = x_, y = y_;
|
||||
if (y >= h) return;
|
||||
|
||||
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];
|
||||
x += (entity_[i] > UINT8_MAX)? 2: 1;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::wstring entity_;
|
||||
};
|
||||
|
||||
|
||||
}
|
87
src/Texture.cc
Normal file
87
src/Texture.cc
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "Texture.h"
|
||||
|
||||
|
||||
void gj::Texture::Draw(Colorbuffer& fb) const {
|
||||
const int32_t w = static_cast<int32_t>(fb.width());
|
||||
const int32_t h = static_cast<int32_t>(fb.height());
|
||||
|
||||
const int32_t srcw = static_cast<int32_t>(src_.width());
|
||||
const int32_t srch = static_cast<int32_t>(src_.height());
|
||||
|
||||
/* dst coordinate */
|
||||
vec3 p[4] = {
|
||||
{ -1, 1, 1 },
|
||||
{ -1, -1, 1 },
|
||||
{ 1, -1, 1 },
|
||||
{ 1, 1, 1 },
|
||||
};
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
p[i] = ::linalg::mul(mat_, p[i]);
|
||||
}
|
||||
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;
|
||||
const double pb = std::min({p[0].y, p[1].y, p[2].y, p[3].y})-.1;
|
||||
const double pw = pr - pl;
|
||||
const double ph = pu - pb;
|
||||
|
||||
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);
|
||||
const int32_t pbi = static_cast<int32_t>((pb + 1) / 2 * h);
|
||||
const int32_t pwi = pri - pli;
|
||||
const int32_t phi = pui - pbi;
|
||||
|
||||
/* src coordinate */
|
||||
vec3 q[4] = {
|
||||
{ pl, pu, 1 },
|
||||
{ pl, pb, 1 },
|
||||
{ pr, pb, 1 },
|
||||
{ pr, pu, 1 },
|
||||
};
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
q[i] = ::linalg::mul(invmat_, q[i]);
|
||||
}
|
||||
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});
|
||||
|
||||
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;
|
||||
const double qrdy = q[3].y - q[2].y;
|
||||
|
||||
/* blit with transformation */
|
||||
const float* src = src_.ptr();
|
||||
float* dst = fb.ptr();
|
||||
for (int32_t y = 0; y <= phi; ++y) {
|
||||
const double yfr = y*1. / phi;
|
||||
|
||||
const double lxf = qldx * yfr + q[1].x;
|
||||
const double rxf = qrdx * yfr + q[2].x;
|
||||
const double ax = (rxf - lxf) / pwi;
|
||||
|
||||
const double lyf = qldy * yfr + q[1].y;
|
||||
const double ryf = qrdy * yfr + q[2].y;
|
||||
const double ay = (ryf - lyf) / pwi;
|
||||
|
||||
for (int32_t x = 0; x <= pwi; ++x) {
|
||||
const double xf = lxf + ax*x;
|
||||
const double yf = lyf + ay*x;
|
||||
if (std::abs(xf) > 1 || std::abs(yf) > 1) continue;
|
||||
|
||||
int32_t srcx = static_cast<int32_t>((xf+1)/2 * srcw);
|
||||
int32_t srcy = srch - 1 - static_cast<int32_t>((yf+1)/2 * srch);
|
||||
if (srcx >= srcw) srcx = srcw - 1;
|
||||
if (srcy >= srch) srcy = srch - 1;
|
||||
|
||||
const int32_t dstx = pli + x;
|
||||
const int32_t dsty = (h-pui) + y;
|
||||
if (dstx < 0 || w <= dstx) continue;
|
||||
if (dsty < 0 || h <= dsty) continue;
|
||||
|
||||
dst[dstx + w*dsty] = src[srcx + srcw*srcy];
|
||||
}
|
||||
}
|
||||
}
|
37
src/Texture.h
Normal file
37
src/Texture.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "thirdparty/linalg.h"
|
||||
|
||||
#include "iDrawable.h"
|
||||
#include "Rasterbuffer.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class Texture : public DrawableBase {
|
||||
public:
|
||||
Texture() = delete;
|
||||
Texture(Texture&&) = default;
|
||||
Texture(const Texture&) = default;
|
||||
|
||||
Texture& operator=(Texture&&) = default;
|
||||
Texture& operator=(const Texture&) = default;
|
||||
|
||||
Texture(Colorbuffer&& src) : src_(std::move(src)) {
|
||||
}
|
||||
|
||||
void Draw(Colorbuffer& fb) const override;
|
||||
|
||||
void SetSource(Colorbuffer&& src) {
|
||||
src_ = std::move(src);
|
||||
}
|
||||
|
||||
private:
|
||||
Colorbuffer src_;
|
||||
};
|
||||
|
||||
|
||||
}
|
43
src/TickingClock.h
Normal file
43
src/TickingClock.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#undef NOMINMAX
|
||||
|
||||
#include "iClock.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class TickingClock : public iClock {
|
||||
public:
|
||||
TickingClock() = delete;
|
||||
TickingClock(TickingClock&&) = default;
|
||||
TickingClock(const TickingClock&) = default;
|
||||
|
||||
TickingClock& operator=(TickingClock&&) = default;
|
||||
TickingClock& operator=(const TickingClock&) = default;
|
||||
|
||||
TickingClock(const iClock* parent) : parent_(parent) {
|
||||
Tick();
|
||||
}
|
||||
|
||||
void Tick() {
|
||||
now_ = parent_->now();
|
||||
}
|
||||
|
||||
uint64_t now() const override {
|
||||
return now_;
|
||||
}
|
||||
|
||||
private:
|
||||
const iClock* parent_;
|
||||
|
||||
uint64_t now_;
|
||||
};
|
||||
|
||||
|
||||
}
|
87
src/Win32Console.cc
Normal file
87
src/Win32Console.cc
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "Win32Console.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
||||
static void CalcChar(CHAR_INFO& c, float color, uint16_t text) {
|
||||
constexpr wchar_t chars[] = L" .,:x!|X#%@$M";
|
||||
constexpr uint8_t attrs[] = {
|
||||
FOREGROUND_INTENSITY,
|
||||
BACKGROUND_INTENSITY,
|
||||
BACKGROUND_INTENSITY | FOREGROUND_RED,
|
||||
BACKGROUND_RED | FOREGROUND_INTENSITY,
|
||||
};
|
||||
|
||||
constexpr size_t char_expr_count = sizeof(chars)/sizeof(chars[0])-1;
|
||||
constexpr size_t attr_expr_count = sizeof(attrs)/sizeof(attrs[0]);
|
||||
|
||||
constexpr size_t reso = char_expr_count*attr_expr_count;
|
||||
|
||||
/* post effect */
|
||||
color = static_cast<float>(std::pow(color, 1.9));
|
||||
|
||||
int8_t a = static_cast<int8_t>(color*reso);
|
||||
if (a >= reso) a = reso-1;
|
||||
if (a < 0) a = 0;
|
||||
|
||||
size_t ci = a%char_expr_count;
|
||||
size_t ai = a/char_expr_count;
|
||||
if (ai%2 == 1) ci = char_expr_count-ci-1;
|
||||
|
||||
c.Char.UnicodeChar = chars[ci];
|
||||
c.Attributes = attrs[ai];
|
||||
|
||||
if (text) c.Char.UnicodeChar = text;
|
||||
}
|
||||
|
||||
void gj::Win32Console::main() {
|
||||
bool shown = false;
|
||||
|
||||
while (alive_.load()) {
|
||||
if (shown_.load()) {
|
||||
if (!shown) {
|
||||
shown = true;
|
||||
ShowWindow(win_, TRUE);
|
||||
}
|
||||
|
||||
constexpr CONSOLE_CURSOR_INFO cursor{ 1, FALSE };
|
||||
SetConsoleCursorInfo(screen_, &cursor);
|
||||
|
||||
CHAR_INFO* c = chars_.get();
|
||||
{ /* critical section */
|
||||
std::lock_guard<std::mutex> _(mtx_);
|
||||
|
||||
const float* cb = cb_main_.ptr();
|
||||
const char16_t* tb = tb_main_.ptr();
|
||||
|
||||
for (uint32_t y = 0; y < h_; ++y) {
|
||||
bool mb = false;
|
||||
for (uint32_t x = 0; x < w_; ++x) {
|
||||
if (mb) {
|
||||
*c = *(c - 1);
|
||||
(c - 1)->Attributes |= COMMON_LVB_LEADING_BYTE;
|
||||
c->Attributes |= COMMON_LVB_TRAILING_BYTE;
|
||||
mb = false;
|
||||
} else {
|
||||
CalcChar(*c, *cb, *tb);
|
||||
mb = *tb > UINT8_MAX;
|
||||
}
|
||||
++cb, ++tb, ++c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const COORD size = { static_cast<SHORT>(w_), static_cast<SHORT>(h_), };
|
||||
const COORD pos = { 0, 0, };
|
||||
SMALL_RECT rc = { 0, 0, static_cast<SHORT>(w_), static_cast<SHORT>(h_), };
|
||||
WriteConsoleOutput(screen_, chars_.get(), size, pos, &rc);
|
||||
|
||||
} else {
|
||||
if (shown) {
|
||||
ShowWindow(win_, FALSE);
|
||||
shown = false;
|
||||
}
|
||||
}
|
||||
Sleep(30);
|
||||
}
|
||||
}
|
116
src/Win32Console.h
Normal file
116
src/Win32Console.h
Normal file
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#undef NOMINMAX
|
||||
|
||||
#include "iConsole.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class Win32Console : public iConsole {
|
||||
public:
|
||||
Win32Console() = delete;
|
||||
Win32Console(Win32Console&&) = delete;
|
||||
Win32Console(const Win32Console&) = delete;
|
||||
|
||||
Win32Console& operator=(Win32Console&&) = delete;
|
||||
Win32Console& operator=(const Win32Console&) = delete;
|
||||
|
||||
Win32Console(iAllocator* alloc, uint32_t w, uint32_t h) :
|
||||
w_(w), h_(h), shown_(false), alive_(true),
|
||||
th_([this]() { main(); }),
|
||||
cb_main_(alloc, w, h), cb_sub_(alloc, w, h),
|
||||
tb_main_(alloc, w, h), tb_sub_(alloc, w, h),
|
||||
chars_(std::make_unique<CHAR_INFO[]>(static_cast<uint64_t>(w)*h)),
|
||||
win_(GetConsoleWindow()) {
|
||||
_ASSERT(win_);
|
||||
|
||||
screen_ = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
_ASSERT(screen_ != INVALID_HANDLE_VALUE);
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFOEX size;
|
||||
size.cbSize = sizeof(size);
|
||||
|
||||
GetConsoleScreenBufferInfoEx(screen_, &size);
|
||||
COORD c;
|
||||
c.X = w_;
|
||||
c.Y = h_;
|
||||
size.dwSize = c;
|
||||
|
||||
size.srWindow.Left = 0;
|
||||
size.srWindow.Right = w_ + 1;
|
||||
size.srWindow.Top = 0;
|
||||
size.srWindow.Bottom = h_ + 1;
|
||||
SetConsoleScreenBufferInfoEx(screen_, &size);
|
||||
|
||||
ShowWindow(win_, FALSE);
|
||||
SetWindowLong(win_, GWL_STYLE, GetWindowLong(win_, GWL_STYLE) & ~(WS_SIZEBOX | WS_MAXIMIZEBOX));
|
||||
}
|
||||
~Win32Console() {
|
||||
alive_.store(false);
|
||||
th_.join();
|
||||
}
|
||||
|
||||
void Show() override {
|
||||
shown_.store(true);
|
||||
}
|
||||
void Hide() override {
|
||||
shown_.store(false);
|
||||
}
|
||||
|
||||
Colorbuffer& TakeColorbuffer() override {
|
||||
return cb_sub_;
|
||||
}
|
||||
void SwapColorbuffer() override {
|
||||
std::lock_guard<std::mutex> _(mtx_);
|
||||
std::swap(cb_main_, cb_sub_);
|
||||
}
|
||||
|
||||
Textbuffer& TakeTextbuffer() override {
|
||||
return tb_sub_;
|
||||
}
|
||||
void SwapTextbuffer() override {
|
||||
std::lock_guard<std::mutex> _(mtx_);
|
||||
std::swap(tb_main_, tb_sub_);
|
||||
}
|
||||
|
||||
uint32_t width() const override {
|
||||
return w_;
|
||||
}
|
||||
uint32_t height() const override {
|
||||
return h_;
|
||||
}
|
||||
|
||||
private:
|
||||
const uint32_t w_, h_;
|
||||
|
||||
std::atomic_bool alive_;
|
||||
std::atomic_bool shown_;
|
||||
std::mutex mtx_;
|
||||
std::thread th_;
|
||||
|
||||
Colorbuffer cb_main_;
|
||||
Colorbuffer cb_sub_;
|
||||
|
||||
Textbuffer tb_main_;
|
||||
Textbuffer tb_sub_;
|
||||
|
||||
std::unique_ptr<CHAR_INFO[]> chars_;
|
||||
|
||||
HANDLE screen_ = INVALID_HANDLE_VALUE;
|
||||
HWND win_ = nullptr;
|
||||
|
||||
void main();
|
||||
};
|
||||
|
||||
|
||||
}
|
35
src/common.h
Normal file
35
src/common.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <codecvt>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#undef NOMINMAX
|
||||
|
||||
#include "thirdparty/linalg.h"
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
using mat3 = ::linalg::mat<double, 3, 3>;
|
||||
using vec3 = ::linalg::vec<double, 3>;
|
||||
|
||||
|
||||
static inline std::wstring ConvertUtf8ToUtf16(const std::string& str) {
|
||||
std::wostringstream conv;
|
||||
conv << str.c_str();
|
||||
return conv.str();
|
||||
}
|
||||
|
||||
|
||||
[[noreturn]]
|
||||
static inline void Abort(const std::string& msg) {
|
||||
MessageBox(NULL, ConvertUtf8ToUtf16(msg).c_str(), L"PROGRAM ABORTED", MB_OK);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
76
src/iAllocator.h
Normal file
76
src/iAllocator.h
Normal file
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class iAllocator {
|
||||
public:
|
||||
template <typename T>
|
||||
struct Deleter {
|
||||
Deleter() = default;
|
||||
Deleter(Deleter&&) = default;
|
||||
Deleter(const Deleter&) = delete;
|
||||
|
||||
Deleter& operator=(Deleter&&) = default;
|
||||
Deleter& operator=(const Deleter&) = delete;
|
||||
|
||||
Deleter(iAllocator* alloc) : alloc_(alloc) {
|
||||
}
|
||||
|
||||
void operator()(T* ptr) {
|
||||
assert(alloc_);
|
||||
ptr->~T();
|
||||
alloc_->Free(ptr);
|
||||
}
|
||||
|
||||
iAllocator* alloc_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using UniqPtr = std::unique_ptr<T, iAllocator::Deleter<T>>;
|
||||
|
||||
iAllocator(iAllocator&&) = default;
|
||||
iAllocator(const iAllocator&) = default;
|
||||
|
||||
iAllocator& operator=(iAllocator&&) = default;
|
||||
iAllocator& operator=(const iAllocator&) = default;
|
||||
|
||||
iAllocator() = default;
|
||||
|
||||
virtual ~iAllocator() = default;
|
||||
|
||||
virtual void* Alloc(const size_t size) = 0;
|
||||
virtual void Free(void* ptr) = 0;
|
||||
|
||||
template <typename T>
|
||||
T* Alloc(size_t n = 1) {
|
||||
return reinterpret_cast<T*>(Alloc(sizeof(T) * n));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
UniqPtr<T> MakeUniq(Args&&... args) {
|
||||
T* ptr = Alloc<T>();
|
||||
return std::unique_ptr<T, Deleter<T>>(new(ptr) T(std::forward<Args>(args)...), Deleter<T>(this));
|
||||
}
|
||||
template <typename I, typename T, typename... Args>
|
||||
UniqPtr<I> MakeUniq(Args&&... args) {
|
||||
T* ptr = Alloc<T>();
|
||||
return std::unique_ptr<I, Deleter<I>>(new(ptr) T(std::forward<Args>(args)...), Deleter<I>(this));
|
||||
}
|
||||
template <typename T>
|
||||
UniqPtr<T> MakeUniqArray(size_t n) {
|
||||
T* ptr = Alloc<T>(n);
|
||||
return std::unique_ptr<T, Deleter<T>>(ptr, Deleter<T>(this));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using UniqPtr = iAllocator::UniqPtr<T>;
|
||||
|
||||
|
||||
}
|
25
src/iClock.h
Normal file
25
src/iClock.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class iClock {
|
||||
public:
|
||||
iClock() = default;
|
||||
iClock(iClock&&) = default;
|
||||
iClock(const iClock&) = default;
|
||||
|
||||
iClock& operator=(iClock&&) = default;
|
||||
iClock& operator=(const iClock&) = default;
|
||||
|
||||
virtual ~iClock() = default;
|
||||
|
||||
virtual uint64_t now() const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
34
src/iConsole.h
Normal file
34
src/iConsole.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "Rasterbuffer.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class iConsole {
|
||||
public:
|
||||
iConsole(iConsole&&) = delete;
|
||||
iConsole(const iConsole&) = delete;
|
||||
|
||||
iConsole& operator=(iConsole&&) = delete;
|
||||
iConsole& operator=(const iConsole&) = delete;
|
||||
|
||||
iConsole() = default;
|
||||
virtual ~iConsole() = default;
|
||||
|
||||
virtual void Show() = 0;
|
||||
virtual void Hide() = 0;
|
||||
|
||||
virtual Colorbuffer& TakeColorbuffer() = 0;
|
||||
virtual void SwapColorbuffer() = 0;
|
||||
|
||||
virtual Textbuffer& TakeTextbuffer() = 0;
|
||||
virtual void SwapTextbuffer() = 0;
|
||||
|
||||
virtual uint32_t width() const = 0;
|
||||
virtual uint32_t height() const = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
49
src/iDrawable.h
Normal file
49
src/iDrawable.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "Rasterbuffer.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class iDrawable {
|
||||
public:
|
||||
iDrawable(iDrawable&&) = default;
|
||||
iDrawable(const iDrawable&) = default;
|
||||
|
||||
iDrawable& operator=(iDrawable&&) = default;
|
||||
iDrawable& operator=(const iDrawable&) = default;
|
||||
|
||||
iDrawable() = default;
|
||||
virtual ~iDrawable() = default;
|
||||
|
||||
virtual void Draw(Colorbuffer& buf) const = 0;
|
||||
};
|
||||
|
||||
class DrawableBase : public iDrawable {
|
||||
public:
|
||||
DrawableBase() = default;
|
||||
~DrawableBase() = default;
|
||||
|
||||
DrawableBase(DrawableBase&&) = default;
|
||||
DrawableBase(const DrawableBase&) = default;
|
||||
|
||||
DrawableBase& operator=(DrawableBase&&) = default;
|
||||
DrawableBase& operator=(const DrawableBase&) = default;
|
||||
|
||||
void SetMatrix(const mat3& m) {
|
||||
SetMatrix(mat3(m));
|
||||
}
|
||||
void SetMatrix(mat3&& m) {
|
||||
mat_ = std::move(m);
|
||||
invmat_ = ::linalg::inverse(mat_);
|
||||
}
|
||||
|
||||
protected:
|
||||
mat3 mat_ = ::linalg::identity;
|
||||
mat3 invmat_ = ::linalg::identity;
|
||||
};
|
||||
|
||||
|
||||
}
|
28
src/iElement.h
Normal file
28
src/iElement.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "Frame.h"
|
||||
#include "Period.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class iElement {
|
||||
public:
|
||||
iElement(iElement&&) = default;
|
||||
iElement(const iElement&) = default;
|
||||
|
||||
iElement& operator=(iElement&&) = default;
|
||||
iElement& operator=(const iElement&) = default;
|
||||
|
||||
iElement() = default;
|
||||
virtual ~iElement() = default;
|
||||
|
||||
virtual void Update(Frame& f) = 0;
|
||||
|
||||
/* Interfaces had better not have a variable but this is for optimization. */
|
||||
const Period period;
|
||||
};
|
||||
|
||||
|
||||
}
|
29
src/iElementDriver.h
Normal file
29
src/iElementDriver.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class iElementDriver {
|
||||
public:
|
||||
using Value = std::variant<int64_t, double, std::string>;
|
||||
using Param = std::map<std::string, Value>;
|
||||
|
||||
iElementDriver(iElementDriver&&) = default;
|
||||
iElementDriver(const iElementDriver&) = default;
|
||||
|
||||
iElementDriver& operator=(iElementDriver&&) = default;
|
||||
iElementDriver& operator=(const iElementDriver&) = default;
|
||||
|
||||
iElementDriver() = default;
|
||||
virtual ~iElementDriver() = default;
|
||||
|
||||
virtual void Update(Param&) = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
27
src/iElementFactory.h
Normal file
27
src/iElementFactory.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "iAllocator.h"
|
||||
#include "iElement.h"
|
||||
#include "iElementDriver.h"
|
||||
#include "Period.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class iElementFactory {
|
||||
public:
|
||||
iElementFactory(iElementFactory&&) = default;
|
||||
iElementFactory(const iElementFactory&) = default;
|
||||
|
||||
iElementFactory& operator=(iElementFactory&&) = default;
|
||||
iElementFactory& operator=(const iElementFactory&) = default;
|
||||
|
||||
iElementFactory() = default;
|
||||
virtual ~iElementFactory() = default;
|
||||
|
||||
virtual UniqPtr<iElement> Create(const Period& p, UniqPtr<iElementDriver>&& drv) = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
24
src/iLogger.h
Normal file
24
src/iLogger.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class iLogger {
|
||||
public:
|
||||
iLogger(iLogger&&) = delete;
|
||||
iLogger(const iLogger&) = delete;
|
||||
|
||||
iLogger& operator=(iLogger&&) = delete;
|
||||
iLogger& operator=(const iLogger&) = delete;
|
||||
|
||||
iLogger() = default;
|
||||
virtual ~iLogger() = default;
|
||||
|
||||
virtual void Print(const std::wstring& msg) = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
30
src/iScene.h
Normal file
30
src/iScene.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "Frame.h"
|
||||
#include "iAllocator.h"
|
||||
#include "iDrawable.h"
|
||||
#include "iWritable.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class iScene {
|
||||
public:
|
||||
iScene() = default;
|
||||
iScene(iScene&&) = default;
|
||||
iScene(const iScene&) = default;
|
||||
|
||||
iScene& operator=(iScene&&) = default;
|
||||
iScene& operator=(const iScene&) = default;
|
||||
|
||||
virtual ~iScene() = default;
|
||||
|
||||
/* Returns next scene if this scene ends, otherwise nullptr. */
|
||||
virtual UniqPtr<iScene> Update(Frame& f) = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
46
src/iWritable.h
Normal file
46
src/iWritable.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "Rasterbuffer.h"
|
||||
|
||||
|
||||
namespace gj {
|
||||
|
||||
|
||||
class iWritable {
|
||||
public:
|
||||
iWritable(iWritable&&) = default;
|
||||
iWritable(const iWritable&) = default;
|
||||
|
||||
iWritable& operator=(iWritable&&) = default;
|
||||
iWritable& operator=(const iWritable&) = default;
|
||||
|
||||
iWritable() = default;
|
||||
virtual ~iWritable() = default;
|
||||
|
||||
virtual void Write(Textbuffer&) const = 0;
|
||||
};
|
||||
|
||||
class WritableBase : public iWritable {
|
||||
public:
|
||||
WritableBase(WritableBase&&) = default;
|
||||
WritableBase(const WritableBase&) = default;
|
||||
|
||||
WritableBase& operator=(WritableBase&&) = default;
|
||||
WritableBase& operator=(const WritableBase&) = default;
|
||||
|
||||
WritableBase(int32_t x, int32_t y) : x_(x), y_(y) {
|
||||
}
|
||||
|
||||
void SetPosition(int32_t x, int32_t y) {
|
||||
x_ = x;
|
||||
y_ = y;
|
||||
}
|
||||
|
||||
protected:
|
||||
int32_t x_ = 0, y_ = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
50
src/main.cc
Normal file
50
src/main.cc
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#undef NOMINMAX
|
||||
|
||||
#include "common.h"
|
||||
#include "Font.h"
|
||||
#include "Game.h"
|
||||
#include "LinearAllocator.h"
|
||||
#include "SystemClock.h"
|
||||
#include "Win32Console.h"
|
||||
|
||||
|
||||
constexpr size_t kHeapSize = 1024*1024*64;
|
||||
|
||||
constexpr uint32_t kWidth = 96;
|
||||
constexpr uint32_t kHeight = 28;
|
||||
|
||||
int main() {
|
||||
auto memory = std::make_unique<uint8_t[]>(kHeapSize);
|
||||
gj::LinearAllocator alloc(memory.get(), kHeapSize);
|
||||
|
||||
gj::Win32Console console(&alloc, kWidth, kHeight);
|
||||
console.Show();
|
||||
|
||||
gj::Game::Param param;
|
||||
param.alloc = &alloc;
|
||||
param.clock = &gj::SystemClock::instance();
|
||||
param.w = kWidth;
|
||||
param.h = kHeight;
|
||||
gj::Game game(std::move(param));
|
||||
while (true) {
|
||||
game.Update();
|
||||
{
|
||||
auto& fb = console.TakeColorbuffer();
|
||||
fb.Clear();
|
||||
game.Draw(fb);
|
||||
console.SwapColorbuffer();
|
||||
}
|
||||
{
|
||||
auto& fb = console.TakeTextbuffer();
|
||||
fb.Clear();
|
||||
game.Write(fb);
|
||||
console.SwapTextbuffer();
|
||||
}
|
||||
Sleep(10);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user