Merge pull request #192 from MihailRis/worldwide-refactor

Worldwide refactor: in search of good architecture
This commit is contained in:
MihailRis
2024-05-06 17:50:35 +03:00
committed by GitHub
392 changed files with 14950 additions and 11696 deletions
+2 -1
View File
@@ -8,6 +8,7 @@ Debug/voxel_engine
/screenshots /screenshots
/out /out
/misc
/world /world
/worlds/**/* /worlds/**/*
/settings.toml /settings.toml
@@ -41,4 +42,4 @@ appimage-build/
*~ *~
/res/content/* /res/content/*
!/res/content/base !/res/content/base
+34
View File
@@ -95,6 +95,26 @@ world.get_seed() -> int
Returns world seed. Returns world seed.
## *pack* library
```python
pack.get_folder(packid: str) -> str
```
Returns installed content-pack folder
```python
pack.is_installed(packid: str) -> bool
```
Check if the world has specified pack installed
```python
pack.get_installed() -> array of strings
```
Returns all installed content-pack ids
## *gui* library ## *gui* library
Library contains ui elements access functions. Library should not be directly used, because script *layouts/layout_name.xml.lua* already has a generated variable **document** (instance of **Document**) Library contains ui elements access functions. Library should not be directly used, because script *layouts/layout_name.xml.lua* already has a generated variable **document** (instance of **Document**)
@@ -161,6 +181,13 @@ inventory.clone(invid: int) -> int
Create inventory copy. Returns the created copy ID. Create inventory copy. Returns the created copy ID.
```python
inventory.move(invA: int, slotA: int, invB: int, slotB: int)
```
Move item from slotA of invA to slotB of invB. invA may be the same as invB.
If slotB will be chosen automaticly if argument is not specified.
## *block* library ## *block* library
```python ```python
@@ -337,6 +364,13 @@ hud.close(layoutid: str)
Remove an element from the screen Remove an element from the screen
```python
hud.get_block_inventory() -> int
```
Get open block inventory ID or 0
## Block events ## Block events
```lua ```lua
+35
View File
@@ -89,6 +89,26 @@ world.get_seed() -> int
Возвращает зерно мира. Возвращает зерно мира.
## Библиотека pack
```python
pack.get_folder(packid: str) -> str
```
Возвращает путь к папке установленного контент-пака
```python
pack.is_installed(packid: str) -> bool
```
Проверяет наличие контент-пака в мире
```python
pack.get_installed() -> массив строк
```
Возращает id всех установленных в мире контент-паков
## Библиотека gui ## Библиотека gui
Библиотека содержит функции для доступа к свойствам UI элементов. Вместо gui следует использовать объектную обертку, предоставляющую доступ к свойствам через мета-методы __index, __newindex: Библиотека содержит функции для доступа к свойствам UI элементов. Вместо gui следует использовать объектную обертку, предоставляющую доступ к свойствам через мета-методы __index, __newindex:
@@ -155,6 +175,14 @@ inventory.clone(invid: int) -> int
Создает копию инвентаря и возвращает id копии. Если копируемого инвентаря не существует, возвращает 0. Создает копию инвентаря и возвращает id копии. Если копируемого инвентаря не существует, возвращает 0.
```python
inventory.move(invA: int, slotA: int, invB: int, slotB: int)
```
Перемещает предмет из slotA инвентаря invA в slotB инвентаря invB.
invA и invB могут указывать на один инвентарь.
slotB будет выбран автоматически, если не указывать явно.
## Библиотека block ## Библиотека block
```python ```python
@@ -326,6 +354,13 @@ hud.close(layoutid: str)
``` ```
Удаляет элемент с экрана Удаляет элемент с экрана
```python
hud.get_block_inventory() -> int
```
Получить ID инвентаря открытого блока или 0
## События блоков ## События блоков
```lua ```lua
-22
View File
@@ -1,22 +0,0 @@
bazalt=Bazalt
blue_lamp=Blue Lamp
brick=Brick
dirt=Dirt
flower=Flower
glass=Glass
grass_block=Ground
grass=Tall Grass
green_lamp=Green Lamp
lamp=Lamp
leaves=Leaves
lightbulb=Bulb
metal=Metal
pane=Pane
pipe=Pipe
planks=Planks
red_lamp=Red Lamp
rust=Rust
sand=Sand
stone=Stone
water=Water
wood=Wood
+22 -22
View File
@@ -1,22 +1,22 @@
bazalt=Базальт bazalt=базальт
blue_lamp=Синяя Лампа blue lamp=синяя лампа
brick=Кирпич brick=кирпич
dirt=Земля dirt=земля
flower=Цветок flower=цветок
glass=Стекло glass=стекло
grass_block=Дёрн grass block=дёрн
grass=Высокая Трава tall grass=высокая трава
green_lamp=Зелёная Лампа green lamp=зелёная лампа
lamp=Лампа lamp=лампа
leaves=Листва leaves=листва
lightbulb=Лампочка light bulb=лампочка
metal=Металл metal=металл
pane=Панель pane=панель
pipe=Труба pipe=труба
planks=Доски planks=доски
red_lamp=Красная Лампа red lamp=красная лампа
rust=Ржавчина rust=ржавчина
sand=Песок sand=песок
stone=Камень stone=камень
water=Вода water=вода
wood=Бревно wood=бревно
+6 -1
View File
@@ -1,3 +1,8 @@
function inventory_share_func(invid, slotid) function inventory_share_func(invid, slotid)
inventory.set(invid, slotid, 0, 0) local blockinv = hud.get_block_inventory()
if blockinv ~= 0 then
inventory.move(invid, slotid, blockinv)
else
inventory.set(invid, slotid, 0, 0)
end
end end
+4
View File
@@ -0,0 +1,4 @@
<panel size='400' padding='8' interval='8' color='0'>
<label context='menu'>@Page not found</label>
<button onclick='menu:back()'>@Back</button>
</panel>
+13
View File
@@ -0,0 +1,13 @@
<container size='887,454' color='#0F1E2DB2' padding='8' interval='5' context='menu'>
<panel id='packs_cur' pos='2' size='440,406' color='0' max-length='406'>
<!-- content is generated in script -->
</panel>
<panel id='packs_add' pos='445,2' size='440,406' color='0' max-length='406'>
<!-- content is generated in script -->
</panel>
<button id='apply_btn' pos='2,410' size='440,40' onclick='apply()'>@Apply</button>
<button pos='445,410' size='398,40' onclick='menu:back()'>@Cancel</button>
<image onclick='refresh()' interactive='true' src='gui/refresh'
size='32' margin='7' gravity='bottom-right'
color='#FFFFFF80' hover-color='#FFFFFF10'/>
</container>
+131
View File
@@ -0,0 +1,131 @@
function on_open(params)
if params then
mode = params.mode
end
refresh()
end
add_packs = {}
rem_packs = {}
function apply()
core.reconfig_packs(add_packs, rem_packs)
if mode ~= "world" then
menu:back()
end
end
function refresh_changes()
document.apply_btn.enabled = (#add_packs>0) or (#rem_packs>0)
end
function move_pack(id)
-- cancel pack addition
if table.has(add_packs, id) then
document["pack_"..id]:move_into(document.packs_add)
table.remove_value(add_packs, id)
-- cancel pack removal
elseif table.has(rem_packs, id) then
document["pack_"..id]:move_into(document.packs_cur)
table.remove_value(rem_packs, id)
-- add pack
elseif table.has(packs_installed, id) then
document["pack_"..id]:move_into(document.packs_add)
table.insert(rem_packs, id)
-- remove pack
else
document["pack_"..id]:move_into(document.packs_cur)
table.insert(add_packs, id)
end
refresh_changes()
end
function place_pack(panel, packinfo, callback)
if packinfo.error then
callback = nil
end
if packinfo.has_indices then
packinfo.id_verbose = packinfo.id.."*"
else
packinfo.id_verbose = packinfo.id
end
packinfo.callback = callback
panel:add(gui.template("pack", packinfo))
if not callback then
document["pack_"..packinfo.id].enabled = false
end
end
function check_dependencies(packinfo)
if packinfo.dependencies == nil then
return
end
for i,dep in ipairs(packinfo.dependencies) do
local depid = dep:sub(2,-1)
if dep:sub(1,1) == '!' then
if not table.has(packs_all, depid) then
return string.format(
"%s (%s)", gui.str("error.dependency-not-found"), depid
)
end
if table.has(packs_installed, packinfo.id) then
table.insert(required, depid)
end
end
end
return
end
function refresh()
packs_installed = pack.get_installed()
packs_available = pack.get_available()
base_packs = pack.get_base_packs()
packs_all = {unpack(packs_installed)}
required = {}
for i,k in ipairs(packs_available) do
table.insert(packs_all, k)
end
local packs_cur = document.packs_cur
local packs_add = document.packs_add
packs_cur:clear()
packs_add:clear()
for i,id in ipairs(packs_installed) do
local packinfo = pack.get_info(id)
packinfo.index = i
callback = not table.has(base_packs, id) and string.format('move_pack("%s")', id) or nil
packinfo.error = check_dependencies(packinfo)
place_pack(packs_cur, packinfo, callback)
end
for i,id in ipairs(packs_available) do
local packinfo = pack.get_info(id)
packinfo.index = i
callback = string.format('move_pack("%s")', id)
packinfo.error = check_dependencies(packinfo)
place_pack(packs_add, packinfo, callback)
end
for i,id in ipairs(packs_installed) do
if table.has(required, id) then
document["pack_"..id].enabled = false
end
end
apply_movements(packs_cur, packs_add)
refresh_changes()
end
function apply_movements(packs_cur, packs_add)
for i,id in ipairs(packs_installed) do
if table.has(rem_packs, id) then
document["pack_"..id]:move_into(packs_add)
end
end
for i,id in ipairs(packs_available) do
if table.has(add_packs, id) then
document["pack_"..id]:move_into(packs_cur)
end
end
end
+3
View File
@@ -0,0 +1,3 @@
<panel size='400' color='#00000080' padding='8' context='settings'>
<!-- content is generated in script -->
</panel>
+16
View File
@@ -0,0 +1,16 @@
settings = session.get_entry('new_world')
function on_open()
local names = core.get_generators()
table.sort(names)
local panel = document.root
for _,k in ipairs(names) do
panel:add(gui.template("generator", {
callback=string.format("settings.generator=%q menu:back()", k),
id=k,
name=settings.generator_name(k)
}))
end
panel:add("<button onclick='menu:back()'>@Back</button>")
end
+3
View File
@@ -0,0 +1,3 @@
<panel size='400' color='#00000080' padding='8'>
<!-- content is generated in script -->
</panel>
+19
View File
@@ -0,0 +1,19 @@
function on_open()
local locales = gui.get_locales_info()
local invlocales = {}
local names = {}
for k, v in pairs(locales) do
table.insert(names, v.name)
invlocales[v.name] = k
end
table.sort(names)
local panel = document.root
for _,k in ipairs(names) do
panel:add(string.format(
"<button onclick=%q>%s</button>",
string.format("core.set_setting('ui.language', %q) menu:back()", invlocales[k]), k
))
end
panel:add("<button onclick='menu:back()'>@Back</button>")
end
+7
View File
@@ -0,0 +1,7 @@
<panel size='400' color='0' interval='1' context='menu'>
<button onclick='menu.page="new_world"'>@New World</button>
<panel id='worlds' size='390,1' padding='5' color='#FFFFFF11' max-length='400'>
</panel>
<button onclick='menu.page="settings"'>@Settings</button>
<button onclick='core.quit()'>@Quit</button>
</panel>
+6
View File
@@ -0,0 +1,6 @@
function on_open()
local worlds = world.get_list()
for _, info in ipairs(worlds) do
document.worlds:add(gui.template("world", info))
end
end
+18
View File
@@ -0,0 +1,18 @@
<panel size='400' color='0' interval='1' context='world'>
<label>@Name</label>
<textbox id='name_box'
validator='world_name_validator'
placeholder='New World'
padding='4'>
</textbox>
<label>@Seed</label>
<textbox id='seed_box' placeholder='-' padding='4'></textbox>
<button onclick='save_state() menu.page="generators"' id='generator_btn'>
@World generator
</button>
<button id='content_btn' onclick='save_state() menu.page="content"'/>
<button onclick='create_world()' margin='1,20,1,1'>
@Create World
</button>
<button onclick='menu:back()'>@Back</button>
</panel>
+47
View File
@@ -0,0 +1,47 @@
settings = session.get_entry('new_world')
function world_name_validator(name)
return name:match("^[%w-\\.\\ ]+$") ~= nil and not world.exists(name)
end
function save_state()
settings.name = document.name_box.text
settings.seed = document.seed_box.text
end
function settings.generator_name(id)
local prefix, name = parse_path(id)
if prefix == "core" then
return gui.str(name, "world.generators")
else
return id
end
end
function create_world()
if not document.name_box.valid then
return
end
local name = document.name_box.text
local seed = document.seed_box.text
local generator = settings.generator
session.reset_entry('new_world')
core.new_world(name, seed, generator)
end
function on_open()
document.content_btn.text = string.format(
"%s [%s]", gui.str("Content", "menu"), #pack.get_installed()
)
if settings.generator == nil then
settings.generator = core.get_default_generator()
end
document.generator_btn.text = string.format(
"%s: %s",
gui.str("World generator", "world"),
settings.generator_name(settings.generator)
)
document.name_box.text = settings.name or ''
document.seed_box.text = settings.seed or ''
document.seed_box.placeholder = tostring(math.random()):sub(3)
end
+8
View File
@@ -0,0 +1,8 @@
<panel size='400' color='0' interval='1' context='menu'>
<button onclick='menu:reset()'>@Continue</button>
<button onclick='menu.page="content?mode=world"'>@Content</button>
<button onclick='menu.page="settings"'>@Settings</button>
<button onclick='core.close_world(true)'>
@Save and Quit to Menu
</button>
</panel>
+14
View File
@@ -0,0 +1,14 @@
<container size='668,418' color='#0F1E2DB2' context='menu'>
<panel pos='6' size='250' color='0' interval='1'>
<button id='s_aud' onclick='set_page("s_aud", "settings_audio")'>@Audio</button>
<button id='s_gfx' onclick='set_page("s_gfx", "settings_graphics")'>@Graphics</button>
<button id='s_ctl' onclick='set_page("s_ctl", "settings_controls")'>@Controls</button>
</panel>
<pagebox id='menu' pos='260,6' size='400'>
</pagebox>
<panel margin='6' gravity='bottom-left' size='250' color='0' interval='1'>
<button onclick='menu.page="languages"' id='langs_btn'>-</button>
<button onclick='menu:back()'>@Back</button>
</panel>
</container>
+15
View File
@@ -0,0 +1,15 @@
function on_open()
document.langs_btn.text = string.format(
"%s: %s", gui.str("Language", "settings"),
gui.get_locales_info()[core.get_setting("ui.language")].name
)
set_page("s_gfx", "settings_graphics")
end
function set_page(btn, page)
document.s_aud.enabled = true
document.s_gfx.enabled = true
document.s_ctl.enabled = true
document[btn].enabled = false
document.menu.page = page
end
+2
View File
@@ -0,0 +1,2 @@
<panel size='400' color='0' interval='1'>
</panel>
+33
View File
@@ -0,0 +1,33 @@
function create_setting(id, name, step, postfix)
local info = core.get_setting_info(id)
postfix = postfix or ""
document.root:add(gui.template("track_setting", {
id=id,
name=gui.str(name, "settings"),
value=core.get_setting(id),
min=info.min,
max=info.max,
step=step,
postfix=postfix
}))
update_setting(core.get_setting(id), id, name, postfix)
end
function update_setting(x, id, name, postfix)
core.set_setting(id, x)
-- updating label
document[id..".L"].text = string.format(
"%s: %s%s",
gui.str(name, "settings"),
core.str_setting(id),
postfix
)
end
function on_open()
create_setting("audio.volume-master", "Master Volume", 0.01)
create_setting("audio.volume-regular", "Regular Sounds", 0.01)
create_setting("audio.volume-ui", "UI Sounds", 0.01)
create_setting("audio.volume-ambient", "Ambient", 0.01)
create_setting("audio.volume-music", "Music", 0.01)
end
+10
View File
@@ -0,0 +1,10 @@
<panel size='400' color='0'>
<label id='sensitivity_label'>-</label>
<trackbar id='sensitivity_track'
min='0.1' max='10' value='2' step='0.1'
consumer='change_sensitivity'>
</trackbar>
<panel id='bindings_panel' size='380,204' padding='2' interval='1' max-length='350' color='#0000004C'>
<!-- content is generated in script -->
</panel>
</panel>
@@ -0,0 +1,25 @@
function refresh_sensitivity()
document.sensitivity_label.text = string.format(
"%s: %s",
gui.str("Mouse Sensitivity", "settings"),
core.str_setting("camera.sensitivity")
)
end
function change_sensitivity(val)
core.set_setting("camera.sensitivity", val)
refresh_sensitivity()
end
function on_open()
document.sensitivity_track.value = core.get_setting("camera.sensitivity")
refresh_sensitivity()
local panel = document.bindings_panel
local bindings = core.get_bindings()
for i,name in ipairs(bindings) do
panel:add(gui.template("binding", {
id=name, name=gui.str(name)
}))
end
end
+2
View File
@@ -0,0 +1,2 @@
<panel size='400' color='0' interval='1' context='menu'>
</panel>
@@ -0,0 +1,44 @@
function create_setting(id, name, step, postfix)
local info = core.get_setting_info(id)
postfix = postfix or ""
document.root:add(gui.template("track_setting", {
id=id,
name=gui.str(name, "settings"),
value=core.get_setting(id),
min=info.min,
max=info.max,
step=step,
postfix=postfix
}))
update_setting(core.get_setting(id), id, name, postfix)
end
function update_setting(x, id, name, postfix)
core.set_setting(id, x)
-- updating label
document[id..".L"].text = string.format(
"%s: %s%s",
gui.str(name, "settings"),
core.str_setting(id),
postfix
)
end
function create_checkbox(id, name)
document.root:add(string.format(
"<checkbox consumer='function(x) core.set_setting(\"%s\", x) end' checked='%s'>%s</checkbox>",
id, core.str_setting(id), gui.str(name, "settings")
))
end
function on_open()
create_setting("chunks.load-distance", "Load Distance", 1)
create_setting("chunks.load-speed", "Load Speed", 1)
create_setting("graphics.fog-curve", "Fog Curve", 0.1)
create_setting("graphics.gamma", "Gamma", 0.05)
create_setting("camera.fov", "FOV", 1, "°")
create_checkbox("display.fullscreen", "Fullscreen")
create_checkbox("display.vsync", "V-Sync")
create_checkbox("graphics.backlight", "Backlight")
create_checkbox("camera.shaking", "Camera Shaking")
end
+4
View File
@@ -0,0 +1,4 @@
<panel size='400' padding='8' interval='1' color='#00000080'>
<label id='title_label'>???</label>
<label id='progress_label'>-</label>
</panel>
+10
View File
@@ -0,0 +1,10 @@
function on_progress(done, total)
local progress = done / total
document.progress_label.text = string.format(
"%s/%s (%s%%)", done, total, math.floor(progress*100)
)
end
function on_open(title)
document.title_label.text = title
end
+7
View File
@@ -0,0 +1,7 @@
<panel size='500' color='#00000080' padding='8' context='menu'>
<label>@missing-content</label>
<panel id='content_panel' size='480,100' color='#00000080' scrollable='true' max-length='400'>
<!-- content is generated in script -->
</panel>
<button onclick='menu:back()'>@Back to Main Menu</button>
</panel>
@@ -0,0 +1,5 @@
function on_open(report)
for i, entry in ipairs(report.content) do
document.content_panel:add(gui.template("content_entry", entry))
end
end
+4
View File
@@ -0,0 +1,4 @@
<panel size='400,40' padding='4' color='0' orientation='horizontal'>
<bindbox binding='%{id}'/>
<label margin='6'>%{name}</label>
</panel>
+4
View File
@@ -0,0 +1,4 @@
<panel size='500,20' color='0' orientation='horizontal' padding='2'>
<label color='#80808080'>[%{type}]</label>
<label color='#FF333380'>"%{name}</label>
</panel>
+4
View File
@@ -0,0 +1,4 @@
<container onclick='%{callback}' size='80,30' hover-color='#FFFFFF10'>
<label pos='80,4' size='300,25' color='#FFFFFF80' align='right'>[%{id}]</label>
<label pos='0,8'>%{name}</label>
</container>
+15
View File
@@ -0,0 +1,15 @@
<container id='pack_%{id}' onclick='%{callback}' size='0,80' color='#00000040' hover-color='#00000080' z-index="%{index}">
<label color='#FFFFFF80' size='300,25' align='right' gravity='top-right'>
[%{id_verbose}]
</label>
<label pos='78,6'>%{title}</label>
<label if='%{creator}' color='#CCFFE5B2' size='300,20' align='right'
gravity='bottom-right'>
%{creator}
</label>
<label if='%{error}' pos='80,28' size='355,50' multiline='true' color='#FF4040'>%{error}</label>
<label ifnot='%{error}' pos='80,28' size='355,50' multiline='true' color='#FFFFFFB2'>
%{description}
</label>
<image pos='8,8' src='%{icon}' size='64'/>
</container>
+6
View File
@@ -0,0 +1,6 @@
<panel color='0' context='settings'>
<label id='%{id}.L' margin='0,3,0,0'>%{name}: %{value}%{postfix}</label>
<trackbar
value='%{value}' min='%{min}' max='%{max}' step='%{step}'
consumer='function(x) update_setting(x, "%{id}", "%{name}", "%{postfix}") end'/>
</panel>
+17
View File
@@ -0,0 +1,17 @@
<container
size='380,66'
color='#0F1E2DB2'
hover-color='#162B3399'
onclick='core.open_world("%{name}")'
>
<image pos='1' src='%{icon}' size='96,64'></image>
<label pos='104,8'>%{name}</label>
<button margin='4'
gravity='center-right'
color='#00000000'
hover-color='#FFFFFF2B'
padding='0'
onclick='core.delete_world("%{name}")'>
<image src='gui/delete_icon' size='32,32' color='#FFFFFF50'/>
</button>
</container>
-1
View File
@@ -11,4 +11,3 @@
"gui/crosshair" "gui/crosshair"
] ]
} }
+98 -2
View File
@@ -131,7 +131,9 @@ events = {
} }
function events.on(event, func) function events.on(event, func)
events.handlers[event] = events.handlers[event] or {} -- why an array? length is always = 1
-- FIXME: temporary fixed
events.handlers[event] = {} -- events.handlers[event] or {}
table.insert(events.handlers[event], func) table.insert(events.handlers[event], func)
end end
@@ -175,11 +177,105 @@ Document = {}
function Document.new(docname) function Document.new(docname)
return setmetatable({name=docname}, { return setmetatable({name=docname}, {
__index=function(self, k) __index=function(self, k)
return Element.new(self.name, k) local elem = Element.new(self.name, k)
rawset(self, k, elem)
return elem
end end
}) })
end end
_GUI_ROOT = Document.new("core:root")
_MENU = _GUI_ROOT.menu
menu = _MENU
local __post_runnables = {}
function __process_post_runnables()
if #__post_runnables then
for _, func in ipairs(__post_runnables) do
func()
end
__post_runnables = {}
end
end
function time.post_runnable(runnable)
table.insert(__post_runnables, runnable)
end
function gui.template(name, params)
local text = file.read(file.find("layouts/templates/"..name..".xml"))
for k,v in pairs(params) do
local arg = tostring(v):gsub("'", "\\'"):gsub('"', '\\"')
text = text:gsub("(%%{"..k.."})", arg)
end
text = text:gsub("if%s*=%s*'%%{%w+}'", "if=''")
text = text:gsub("if%s*=%s*\"%%{%w+}\"", "if=\"\"")
-- remove unsolved properties: attr='%{var}'
text = text:gsub("%w+%s*=%s*'%%{%w+}'%s?", "")
text = text:gsub("%w+%s*=%s*\"%%{%w+}\"%s?", "")
return text
end
session = {
entries={}
}
function session.get_entry(name)
local entry = session.entries[name]
if entry == nil then
entry = {}
session.entries[name] = entry
end
return entry
end
function session.reset_entry(name)
session.entries[name] = nil
end
function timeit(func, ...)
local tm = time.uptime()
func(...)
print("[time mcs]", (time.uptime()-tm) * 1000000)
end
function table.has(t, x)
for i,v in ipairs(t) do
if v == x then
return true
end
end
return false
end
function table.index(t, x)
for i,v in ipairs(t) do
if v == x then
return i
end
end
return -1
end
function table.remove_value(t, x)
local index = table.index(t, x)
if index ~= -1 then
table.remove(t, index)
end
end
function table.tostring(t)
local s = '['
for i,v in ipairs(t) do
s = s..tostring(v)
if i < #t then
s = s..', '
end
end
return s..']'
end
-- Deprecated functions -- Deprecated functions
block_index = block.index block_index = block.index
block_name = block.name block_name = block.name
+20 -20
View File
@@ -13,44 +13,44 @@ error.dependency-not-found=Die verwendete Abhängigkeit wurde nicht gefunden
pack.remove-confirm=Alle vom Paket bereitgestellten Inhalte (dauerhaft) aus der Welt löschen? pack.remove-confirm=Alle vom Paket bereitgestellten Inhalte (dauerhaft) aus der Welt löschen?
# Меню # Меню
menu.Apply=Anwenden
menu.Audio=Klang
menu.Back to Main Menu=Zurück zum Menü
menu.Content Error=Inhaltsfehler
menu.Content=Inhalt
menu.Continue=Weitermachen
menu.Controls=Kontrolle
menu.Create World=Erschaffe eine Welt
menu.missing-content=Fehlender Inhalt!
menu.New World=Neue Welt menu.New World=Neue Welt
menu.Quit=Ausfahrt menu.Quit=Ausfahrt
menu.Continue=Weitermachen
menu.Save and Quit to Menu=Speichern und zum Menü zurückkehren menu.Save and Quit to Menu=Speichern und zum Menü zurückkehren
menu.missing-content=Fehlender Inhalt!
menu.Content Error=Inhaltsfehler
menu.Controls=Kontrolle
menu.Back to Main Menu=Zurück zum Menü
menu.Settings=Einstellungen menu.Settings=Einstellungen
menu.Content=Inhalt
menu.Audio=Klang
world.Seed=Mais world.Seed=Mais
world.Name=Name world.Name=Name
world.World generator=Weltgenerator world.World generator=Weltgenerator
world.generators.default=Normal world.generators.default=Normal
world.generators.flat=Wohnung world.generators.flat=Wohnung
menu.Create World=Erschaffe eine Welt world.Create World=Welt Erschaffen
world.convert-request=Es gibt Änderungen in den Indizes! Die Welt bekehren? world.convert-request=Es gibt Änderungen in den Indizes! Die Welt bekehren?
world.delete-confirm=Die Welt dauerhaft löschen? world.delete-confirm=Die Welt dauerhaft löschen?
# Настройки # Настройки
settings.Ambient=Hintergrund
settings.Backlight=Hintergrundbeleuchtung
settings.Camera Shaking=Wackelnde Kamera
settings.Fog Curve=Nebelkurve
settings.FOV=Sichtlinie
settings.Language=Sprache
settings.Load Distance=Ladeentfernung settings.Load Distance=Ladeentfernung
settings.Load Speed=Download-Geschwindigkeit settings.Load Speed=Download-Geschwindigkeit
settings.Fog Curve=Nebelkurve
settings.Backlight=Hintergrundbeleuchtung
settings.V-Sync=Vertikale Synchronisation
settings.Camera Shaking=Wackelnde Kamera
settings.Master Volume=Allgemeine Lautstärke settings.Master Volume=Allgemeine Lautstärke
settings.Mouse Sensitivity=Maus-Empfindlichkeit
settings.Music=Musik
settings.Regular Sounds=Normale Geräusche settings.Regular Sounds=Normale Geräusche
settings.UI Sounds=Interface-Sounds settings.UI Sounds=Interface-Sounds
settings.Ambient=Hintergrund settings.V-Sync=Vertikale Synchronisation
settings.Music=Musik
settings.FOV=Sichtlinie
settings.Mouse Sensitivity=Maus-Empfindlichkeit
settings.Language=Sprache
# Управление # Управление
movement.forward=Vorwärts movement.forward=Vorwärts
+2 -2
View File
@@ -1,7 +1,7 @@
# Menu # Menu
menu.missing-content=Missing Content! menu.missing-content=Missing Content!
world.convert-request=Content indices have changed! Convert world files? world.convert-request=Content indices have changed! Convert world files?
pack.remove-confirm=Do you want to erase all pack content from the world forever? pack.remove-confirm=Do you want to erase all pack(s) content from the world forever?
error.pack-not-found=Could not to find pack error.pack-not-found=Could not to find pack
error.dependency-not-found=Dependency pack is not found error.dependency-not-found=Dependency pack is not found
world.delete-confirm=Do you want to delete world forever? world.delete-confirm=Do you want to delete world forever?
@@ -24,4 +24,4 @@ player.build=Place Block
player.flight=Flight player.flight=Flight
player.noclip=No-clip player.noclip=No-clip
camera.zoom=Zoom camera.zoom=Zoom
camera.mode=Switch Camera Mode camera.mode=Switch Camera Mode
+30 -15
View File
@@ -5,38 +5,53 @@ Ok=OK
Cancel=Anulowanie Cancel=Anulowanie
Back=Powrót Back=Powrót
Continue=Kontynuacja Continue=Kontynuacja
Add=Dodać
Converting world...=Konwersja świata w toku...
error.pack-not-found=Nie udało się znaleźć pakietu error.pack-not-found=Nie udało się znaleźć pakietu
# Menu # Menu
menu.New World=Nowy Świat menu.Apply=Zastosować
menu.Quit=Wyjście menu.Audio=Dźwięki
menu.Continue=Kontynuacja
menu.Save and Quit to Menu=Zapisz i wyjdź do menu
menu.missing-content=Brak treści!
menu.Controls=Zarządzanie
menu.Back to Main Menu=Powrót do menu menu.Back to Main Menu=Powrót do menu
menu.Settings=Ustawienia
menu.Content=Treść menu.Content=Treść
menu.Continue=Kontynuacja
menu.Controls=Zarządzanie
menu.Graphics=Grafika
menu.Create World=Stwórz świat
menu.missing-content=Brakująca treść!
menu.New World=Nowy Świat
menu.Page not found=Strona nie znaleziona
menu.Quit=Wyjście
menu.Save and Quit to Menu=Zapisz i wyjdź do menu
menu.Settings=Ustawienia
world.Seed=Ziarno world.Seed=Ziarno
world.Name=Nazwa world.Name=Nazwa
menu.Create World=Stwórz świat
world.World generator=Generator światła world.World generator=Generator światła
world.generators.default=Ekstremalne world.generators.default=Ekstremalne
world.generators.flat=Mieszkanie world.generators.flat=Mieszkanie
world.Create World=Stwórz świat
world.convert-request=Szykują się zmiany w indeksach! Przekształcić świat? world.convert-request=Szykują się zmiany w indeksach! Przekształcić świat?
world.delete-confirm=Trwale usunąć świat?
# Ustawienia # Ustawienia
settings.Ambient=Tło
settings.Backlight=Podświetlenie
settings.Camera Shaking=Drżąca kamera
settings.Fog Curve=Krzywa mgły
settings.FOV=Wzrok
settings.Fullscreen=Pełny ekran
settings.Gamma=Gamma
settings.Language=Język
settings.Load Distance=Odległość ładowania settings.Load Distance=Odległość ładowania
settings.Load Speed=Prędkość pobierania settings.Load Speed=Prędkość pobierania
settings.Fog Curve=Krzywa mgły settings.Master Volume=Głośność główna
settings.Backlight=Podświetlenie
settings.V-Sync=Synchronizacja pionowa
settings.FOV=Wzrok
settings.Mouse Sensitivity=Wrażliwość myszy settings.Mouse Sensitivity=Wrażliwość myszy
settings.Language=Język settings.Music=Muzyka
settings.Regular Sounds=Normalne dźwięki
settings.UI Sounds=Dźwięki interfejsu
settings.V-Sync=Synchronizacja pionowa
# Zarządzanie # Zarządzanie
movement.forward=Naprzód movement.forward=Naprzód
+28 -25
View File
@@ -10,47 +10,50 @@ Converting world...=Выполняется конвертация мира...
error.pack-not-found=Не удалось найти пакет error.pack-not-found=Не удалось найти пакет
error.dependency-not-found=Используемая зависимость не найдена error.dependency-not-found=Используемая зависимость не найдена
pack.remove-confirm=Удалить весь поставляемый паком контент из мира (безвозвратно)? pack.remove-confirm=Удалить весь поставляемый паком/паками контент из мира (безвозвратно)?
# Меню # Меню
menu.New World=Новый Мир menu.Apply=Применить
menu.Quit=Выход
menu.Continue=Продолжить
menu.Save and Quit to Menu=Сохранить и Выйти в Меню
menu.missing-content=Отсутствует Контент!
menu.Content Error=Ошибка Контента
menu.Controls=Управление
menu.Back to Main Menu=Вернуться в Меню
menu.Settings=Настройки
menu.Content=Контент
menu.Audio=Звук menu.Audio=Звук
menu.Back to Main Menu=Вернуться в Меню
menu.Content Error=Ошибка Контента
menu.Content=Контент
menu.Continue=Продолжить
menu.Controls=Управление
menu.Graphics=Графика
menu.missing-content=Отсутствует Контент!
menu.New World=Новый Мир
menu.Page not found=Страница не найдена
menu.Quit=Выход
menu.Save and Quit to Menu=Сохранить и Выйти в Меню
menu.Settings=Настройки
world.Seed=Зерно world.Seed=Зерно
world.Name=Название world.Name=Название
world.World generator=Генератор мира world.World generator=Генератор мира
world.generators.default=Обычный world.generators.default=Обычный
world.generators.flat=Плоский world.generators.flat=Плоский
menu.Create World=Создать Мир world.Create World=Создать Мир
world.convert-request=Есть изменения в индексах! Конвертировать мир? world.convert-request=Есть изменения в индексах! Конвертировать мир?
world.delete-confirm=Удалить мир безвозвратно? world.delete-confirm=Удалить мир безвозвратно?
# Настройки # Настройки
settings.Ambient=Фон
settings.Backlight=Подсветка
settings.Camera Shaking=Тряска Камеры
settings.Fog Curve=Кривая Тумана
settings.FOV=Поле Зрения
settings.Fullscreen=Полный экран
settings.Gamma=Гамма
settings.Language=Язык
settings.Load Distance=Дистанция Загрузки settings.Load Distance=Дистанция Загрузки
settings.Load Speed=Скорость Загрузки settings.Load Speed=Скорость Загрузки
settings.Fog Curve=Кривая Тумана
settings.Backlight=Подсветка
settings.V-Sync=Вертикальная Синхронизация
settings.Camera Shaking=Тряска Камеры
settings.Master Volume=Общая Громкость settings.Master Volume=Общая Громкость
settings.Mouse Sensitivity=Чувствительность Мыши
settings.Music=Музыка
settings.Regular Sounds=Обычные Звуки settings.Regular Sounds=Обычные Звуки
settings.UI Sounds=Звуки Интерфейса settings.UI Sounds=Звуки Интерфейса
settings.Ambient=Фон settings.V-Sync=Вертикальная Синхронизация
settings.Music=Музыка
settings.FOV=Поле Зрения
settings.Mouse Sensitivity=Чувствительность Мыши
settings.Language=Язык
# Управление # Управление
movement.forward=Вперёд movement.forward=Вперёд
@@ -67,4 +70,4 @@ player.attack=Атаковать / Сломать
player.build=Поставить Блок player.build=Поставить Блок
player.flight=Полёт player.flight=Полёт
camera.zoom=Приближение camera.zoom=Приближение
camera.mode=Сменить Режим Камеры camera.mode=Сменить Режим Камеры
+27 -13
View File
@@ -5,19 +5,26 @@ Ok=Гаразд
Cancel=Скасувати Cancel=Скасувати
Back=Назад Back=Назад
Continue=Продовжити Continue=Продовжити
Add=Додати
Converting world...=Виконується конвертація світу...
error.pack-not-found=Не вдалося знайти пакет error.pack-not-found=Не вдалося знайти пакет
# Меню # Меню
menu.New World=Новий Світ menu.Apply=Застосувати
menu.Quit=Вихід menu.Audio=Звук
menu.Continue=Продовжити
menu.Save and Quit to Menu=Зберегти і Вийти в Меню
menu.missing-content=Відсутній Контент!
menu.Controls=Керування
menu.Back to Main Menu=Повернутися до Меню menu.Back to Main Menu=Повернутися до Меню
menu.Settings=Налаштування menu.Content Error=Помилка Контенту
menu.Content=Контент menu.Content=Контент
menu.Continue=Продовжити
menu.Controls=Керування
menu.Graphics=Графіка
menu.missing-content=Відсутній Контент!
menu.New World=Новий Світ
menu.Page not found=Сторінка не знайдена
menu.Quit=Вихід
menu.Save and Quit to Menu=Зберегти і Вийти в Меню
menu.Settings=Налаштування
world.Seed=Зерно world.Seed=Зерно
world.Name=Назва world.Name=Назва
menu.Create World=Створити Світ menu.Create World=Створити Світ
@@ -28,15 +35,22 @@ world.generators.flat=Плоскі
world.convert-request=Є зміни в індексах! Конвертувати світ? world.convert-request=Є зміни в індексах! Конвертувати світ?
# Налаштування # Налаштування
settings.Ambient=Фон
settings.Backlight=Підсвічування
settings.Camera Shaking=Тряска Камери
settings.Fog Curve=Крива Туману
settings.FOV=Поле зору
settings.Fullscreen=Повний екран
settings.Gamma=Гамма
settings.Language=Мова
settings.Load Distance=Дистанція Завантаження settings.Load Distance=Дистанція Завантаження
settings.Load Speed=Швидкість Завантаження settings.Load Speed=Швидкість Завантаження
settings.Fog Curve=Крива Туману settings.Master Volume=Загальна Гучність
settings.Backlight=Підсвічування
settings.V-Sync=Вертикальна Синхронізація
settings.FOV=Поле зору
settings.Mouse Sensitivity=Чутливість Миші settings.Mouse Sensitivity=Чутливість Миші
settings.Language=Мова settings.Music=Музика
settings.Regular Sounds=Звичайні Звуки
settings.UI Sounds=Звуки інтерфейсу
settings.V-Sync=Вертикальна Синхронізація
# Керування # Керування
movement.forward=Уперед movement.forward=Уперед
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 B

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

+40 -65
View File
@@ -1,112 +1,87 @@
#include "Assets.h" #include "Assets.hpp"
#include "../audio/audio.h" #include "../audio/audio.hpp"
#include "../graphics/Texture.h" #include "../graphics/core/Texture.hpp"
#include "../graphics/Shader.h" #include "../graphics/core/Shader.hpp"
#include "../graphics/Atlas.h" #include "../graphics/core/Atlas.hpp"
#include "../graphics/Font.h" #include "../graphics/core/Font.hpp"
#include "../frontend/UiDocument.h" #include "../frontend/UiDocument.hpp"
#include "../logic/scripting/scripting.h" #include "../logic/scripting/scripting.hpp"
Assets::~Assets() { Assets::~Assets() {
} }
Texture* Assets::getTexture(std::string name) const { Texture* Assets::getTexture(std::string name) const {
auto found = textures.find(name); auto found = textures.find(name);
if (found == textures.end()) if (found == textures.end())
return nullptr; return nullptr;
return found->second.get(); return found->second.get();
} }
void Assets::store(Texture* texture, std::string name){ void Assets::store(Texture* texture, std::string name){
textures.emplace(name, texture); textures.emplace(name, texture);
} }
Shader* Assets::getShader(std::string name) const{ Shader* Assets::getShader(std::string name) const{
auto found = shaders.find(name); auto found = shaders.find(name);
if (found == shaders.end()) if (found == shaders.end())
return nullptr; return nullptr;
return found->second.get(); return found->second.get();
} }
void Assets::store(Shader* shader, std::string name){ void Assets::store(Shader* shader, std::string name){
shaders.emplace(name, shader); shaders.emplace(name, shader);
} }
Font* Assets::getFont(std::string name) const { Font* Assets::getFont(std::string name) const {
auto found = fonts.find(name); auto found = fonts.find(name);
if (found == fonts.end()) if (found == fonts.end())
return nullptr; return nullptr;
return found->second.get(); return found->second.get();
} }
void Assets::store(Font* font, std::string name){ void Assets::store(Font* font, std::string name){
fonts.emplace(name, font); fonts.emplace(name, font);
} }
Atlas* Assets::getAtlas(std::string name) const { Atlas* Assets::getAtlas(std::string name) const {
auto found = atlases.find(name); auto found = atlases.find(name);
if (found == atlases.end()) if (found == atlases.end())
return nullptr; return nullptr;
return found->second.get(); return found->second.get();
} }
void Assets::store(Atlas* atlas, std::string name){ void Assets::store(Atlas* atlas, std::string name){
atlases.emplace(name, atlas); atlases.emplace(name, atlas);
} }
audio::Sound* Assets::getSound(std::string name) const { audio::Sound* Assets::getSound(std::string name) const {
auto found = sounds.find(name); auto found = sounds.find(name);
if (found == sounds.end()) if (found == sounds.end())
return nullptr; return nullptr;
return found->second.get(); return found->second.get();
} }
void Assets::store(audio::Sound* sound, std::string name) { void Assets::store(audio::Sound* sound, std::string name) {
sounds.emplace(name, sound); sounds.emplace(name, sound);
} }
const std::vector<TextureAnimation>& Assets::getAnimations() { const std::vector<TextureAnimation>& Assets::getAnimations() {
return animations; return animations;
} }
void Assets::store(const TextureAnimation& animation) { void Assets::store(const TextureAnimation& animation) {
animations.emplace_back(animation); animations.emplace_back(animation);
} }
UiDocument* Assets::getLayout(std::string name) const { UiDocument* Assets::getLayout(std::string name) const {
auto found = layouts.find(name); auto found = layouts.find(name);
if (found == layouts.end()) if (found == layouts.end())
return nullptr; return nullptr;
return found->second.get(); return found->second.get();
} }
void Assets::store(UiDocument* layout, std::string name) { void Assets::store(UiDocument* layout, std::string name) {
layouts.emplace(name, layout); layouts[name] = std::shared_ptr<UiDocument>(layout);
}
void Assets::extend(const Assets& assets) {
for (auto entry : assets.textures) {
textures[entry.first] = entry.second;
}
for (auto entry : assets.shaders) {
shaders[entry.first] = entry.second;
}
for (auto entry : assets.fonts) {
fonts[entry.first] = entry.second;
}
for (auto entry : assets.atlases) {
atlases[entry.first] = entry.second;
}
for (auto entry : assets.layouts) {
layouts[entry.first] = entry.second;
}
for (auto entry : assets.sounds) {
sounds[entry.first] = entry.second;
}
animations.clear();
for (auto entry : assets.animations) {
animations.emplace_back(entry);
}
} }
-55
View File
@@ -1,55 +0,0 @@
#ifndef ASSETS_ASSETS_H_
#define ASSETS_ASSETS_H_
#include "../graphics/TextureAnimation.h"
#include <string>
#include <memory>
#include <unordered_map>
#include <vector>
class Texture;
class Shader;
class Font;
class Atlas;
class UiDocument;
namespace audio {
class Sound;
}
class Assets {
std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
std::unordered_map<std::string, std::shared_ptr<Shader>> shaders;
std::unordered_map<std::string, std::shared_ptr<Font>> fonts;
std::unordered_map<std::string, std::shared_ptr<Atlas>> atlases;
std::unordered_map<std::string, std::shared_ptr<UiDocument>> layouts;
std::unordered_map<std::string, std::shared_ptr<audio::Sound>> sounds;
std::vector<TextureAnimation> animations;
public:
~Assets();
Texture* getTexture(std::string name) const;
void store(Texture* texture, std::string name);
Shader* getShader(std::string name) const;
void store(Shader* shader, std::string name);
Font* getFont(std::string name) const;
void store(Font* font, std::string name);
Atlas* getAtlas(std::string name) const;
void store(Atlas* atlas, std::string name);
audio::Sound* getSound(std::string name) const;
void store(audio::Sound* sound, std::string name);
const std::vector<TextureAnimation>& getAnimations();
void store(const TextureAnimation& animation);
UiDocument* getLayout(std::string name) const;
void store(UiDocument* layout, std::string name);
void extend(const Assets& assets);
};
#endif /* ASSETS_ASSETS_H_ */
+63
View File
@@ -0,0 +1,63 @@
#ifndef ASSETS_ASSETS_HPP_
#define ASSETS_ASSETS_HPP_
#include "../graphics/core/TextureAnimation.hpp"
#include <string>
#include <memory>
#include <functional>
#include <unordered_map>
#include <vector>
class Texture;
class Shader;
class Font;
class Atlas;
class Assets;
class UiDocument;
namespace audio {
class Sound;
}
namespace assetload {
/// @brief final work to do in the main thread
using postfunc = std::function<void(Assets*)>;
}
class Assets {
std::unordered_map<std::string, std::shared_ptr<Texture>> textures;
std::unordered_map<std::string, std::shared_ptr<Shader>> shaders;
std::unordered_map<std::string, std::shared_ptr<Font>> fonts;
std::unordered_map<std::string, std::shared_ptr<Atlas>> atlases;
std::unordered_map<std::string, std::shared_ptr<UiDocument>> layouts;
std::unordered_map<std::string, std::shared_ptr<audio::Sound>> sounds;
std::vector<TextureAnimation> animations;
public:
Assets() {}
Assets(const Assets&) = delete;
~Assets();
Texture* getTexture(std::string name) const;
void store(Texture* texture, std::string name);
Shader* getShader(std::string name) const;
void store(Shader* shader, std::string name);
Font* getFont(std::string name) const;
void store(Font* font, std::string name);
Atlas* getAtlas(std::string name) const;
void store(Atlas* atlas, std::string name);
audio::Sound* getSound(std::string name) const;
void store(audio::Sound* sound, std::string name);
const std::vector<TextureAnimation>& getAnimations();
void store(const TextureAnimation& animation);
UiDocument* getLayout(std::string name) const;
void store(UiDocument* layout, std::string name);
};
#endif // ASSETS_ASSETS_HPP_
+109 -35
View File
@@ -1,58 +1,74 @@
#include "AssetsLoader.h" #include "AssetsLoader.hpp"
#include "Assets.h"
#include "assetload_funcs.h" #include "Assets.hpp"
#include "assetload_funcs.hpp"
#include "../util/ThreadPool.hpp"
#include "../constants.hpp"
#include "../data/dynamic.hpp"
#include "../debug/Logger.hpp"
#include "../coders/imageio.hpp"
#include "../files/files.hpp"
#include "../files/engine_paths.hpp"
#include "../content/Content.hpp"
#include "../content/ContentPack.hpp"
#include "../graphics/core/Texture.hpp"
#include "../logic/scripting/scripting.hpp"
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include "../constants.h" static debug::Logger logger("assets-loader");
#include "../data/dynamic.h"
#include "../files/files.h"
#include "../files/engine_paths.h"
#include "../content/Content.h"
#include "../content/ContentPack.h"
#include "../logic/scripting/scripting.h"
AssetsLoader::AssetsLoader(Assets* assets, const ResPaths* paths) AssetsLoader::AssetsLoader(Assets* assets, const ResPaths* paths)
: assets(assets), paths(paths) : assets(assets), paths(paths)
{ {
addLoader(AssetType::shader, assetload::shader); addLoader(AssetType::shader, assetload::shader);
addLoader(AssetType::texture, assetload::texture); addLoader(AssetType::texture, assetload::texture);
addLoader(AssetType::font, assetload::font); addLoader(AssetType::font, assetload::font);
addLoader(AssetType::atlas, assetload::atlas); addLoader(AssetType::atlas, assetload::atlas);
addLoader(AssetType::layout, assetload::layout); addLoader(AssetType::layout, assetload::layout);
addLoader(AssetType::sound, assetload::sound); addLoader(AssetType::sound, assetload::sound);
} }
void AssetsLoader::addLoader(AssetType tag, aloader_func func) { void AssetsLoader::addLoader(AssetType tag, aloader_func func) {
loaders[tag] = func; loaders[tag] = func;
} }
void AssetsLoader::add(AssetType tag, const std::string filename, const std::string alias, std::shared_ptr<AssetCfg> settings) { void AssetsLoader::add(AssetType tag, const std::string filename, const std::string alias, std::shared_ptr<AssetCfg> settings) {
entries.push(aloader_entry{tag, filename, alias, settings}); entries.push(aloader_entry{tag, filename, alias, settings});
} }
bool AssetsLoader::hasNext() const { bool AssetsLoader::hasNext() const {
return !entries.empty(); return !entries.empty();
}
aloader_func AssetsLoader::getLoader(AssetType tag) {
auto found = loaders.find(tag);
if (found == loaders.end()) {
throw std::runtime_error(
"unknown asset tag "+std::to_string(static_cast<int>(tag))
);
}
return found->second;
} }
bool AssetsLoader::loadNext() { bool AssetsLoader::loadNext() {
const aloader_entry& entry = entries.front(); const aloader_entry& entry = entries.front();
std::cout << " loading " << entry.filename << " as " << entry.alias << std::endl; logger.info() << "loading " << entry.filename << " as " << entry.alias;
std::cout.flush(); try {
auto found = loaders.find(entry.tag); aloader_func loader = getLoader(entry.tag);
if (found == loaders.end()) { auto postfunc = loader(this, paths, entry.filename, entry.alias, entry.config);
std::cerr << "unknown asset tag " << static_cast<int>(entry.tag) << std::endl; postfunc(assets);
return false; entries.pop();
} return true;
aloader_func loader = found->second; } catch (std::runtime_error& err) {
bool status = loader(*this, assets, paths, entry.filename, entry.alias, entry.config); logger.error() << err.what();
entries.pop(); entries.pop();
return status; return false;
}
} }
void addLayouts(int env, const std::string& prefix, const fs::path& folder, AssetsLoader& loader) { void addLayouts(scriptenv env, const std::string& prefix, const fs::path& folder, AssetsLoader& loader) {
if (!fs::is_directory(folder)) { if (!fs::is_directory(folder)) {
return; return;
} }
@@ -117,11 +133,12 @@ void AssetsLoader::processPreloadList(AssetType tag, dynamic::List* list) {
auto value = list->get(i); auto value = list->get(i);
switch (value->type) { switch (value->type) {
case dynamic::valtype::string: case dynamic::valtype::string:
processPreload(tag, *value->value.str, nullptr); processPreload(tag, std::get<std::string>(value->value), nullptr);
break; break;
case dynamic::valtype::map: { case dynamic::valtype::map: {
auto name = value->value.map->getStr("name"); auto map = std::get<dynamic::Map*>(value->value);
processPreload(tag, name, value->value.map); auto name = map->getStr("name");
processPreload(tag, name, map);
break; break;
} }
default: default:
@@ -161,9 +178,11 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/menubg", "gui/menubg"); loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/menubg", "gui/menubg");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/delete_icon", "gui/delete_icon"); loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/delete_icon", "gui/delete_icon");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/no_icon", "gui/no_icon"); loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/no_icon", "gui/no_icon");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/no_world_icon", "gui/no_world_icon");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/warning", "gui/warning"); loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/warning", "gui/warning");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/error", "gui/error"); loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/error", "gui/error");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/cross", "gui/cross"); loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/cross", "gui/cross");
loader.add(AssetType::texture, TEXTURES_FOLDER+"/gui/refresh", "gui/refresh");
if (content) { if (content) {
loader.processPreloadConfigs(content); loader.processPreloadConfigs(content);
@@ -179,13 +198,68 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
auto pack = entry.second.get(); auto pack = entry.second.get();
auto& info = pack->getInfo(); auto& info = pack->getInfo();
fs::path folder = info.folder / fs::path("layouts"); fs::path folder = info.folder / fs::path("layouts");
addLayouts(pack->getEnvironment()->getId(), info.id, folder, loader); addLayouts(pack->getEnvironment(), info.id, folder, loader);
} }
} }
loader.add(AssetType::atlas, TEXTURES_FOLDER+"/blocks", "blocks"); loader.add(AssetType::atlas, TEXTURES_FOLDER+"/blocks", "blocks");
loader.add(AssetType::atlas, TEXTURES_FOLDER+"/items", "items"); loader.add(AssetType::atlas, TEXTURES_FOLDER+"/items", "items");
} }
bool AssetsLoader::loadExternalTexture(
Assets* assets,
const std::string& name,
std::vector<std::filesystem::path> alternatives
) {
if (assets->getTexture(name) != nullptr) {
return true;
}
for (auto& path : alternatives) {
if (fs::exists(path)) {
try {
auto image = imageio::read(path.string());
assets->store(Texture::from(image.get()).release(), name);
return true;
} catch (const std::exception& err) {
logger.error() << "error while loading external "
<< path.u8string() << ": " << err.what();
}
}
}
return false;
}
const ResPaths* AssetsLoader::getPaths() const { const ResPaths* AssetsLoader::getPaths() const {
return paths; return paths;
}
class LoaderWorker : public util::Worker<aloader_entry, assetload::postfunc> {
AssetsLoader* loader;
public:
LoaderWorker(AssetsLoader* loader) : loader(loader) {
}
assetload::postfunc operator()(const std::shared_ptr<aloader_entry>& entry) override {
aloader_func loadfunc = loader->getLoader(entry->tag);
return loadfunc(loader, loader->getPaths(), entry->filename, entry->alias, entry->config);
}
};
std::shared_ptr<Task> AssetsLoader::startTask(runnable onDone) {
auto pool = std::make_shared<
util::ThreadPool<aloader_entry, assetload::postfunc>
>(
"assets-loader-pool",
[=](){return std::make_shared<LoaderWorker>(this);},
[=](assetload::postfunc& func) {
func(assets);
}
);
pool->setOnComplete(onDone);
while (!entries.empty()) {
const aloader_entry& entry = entries.front();
auto ptr = std::make_shared<aloader_entry>(entry);
pool->enqueueJob(ptr);
entries.pop();
}
return pool;
} }
-94
View File
@@ -1,94 +0,0 @@
#ifndef ASSETS_ASSETS_LOADER_H
#define ASSETS_ASSETS_LOADER_H
#include <string>
#include <memory>
#include <filesystem>
#include <functional>
#include <map>
#include <queue>
namespace dynamic {
class Map;
class List;
}
enum class AssetType {
texture,
shader,
font,
atlas,
layout,
sound
};
class ResPaths;
class Assets;
class AssetsLoader;
class Content;
struct AssetCfg {
virtual ~AssetCfg() {}
};
struct LayoutCfg : AssetCfg {
int env;
LayoutCfg(int env) : env(env) {}
};
struct SoundCfg : AssetCfg {
bool keepPCM;
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {}
};
using aloader_func = std::function<bool(AssetsLoader&, Assets*, const ResPaths*, const std::string&, const std::string&, std::shared_ptr<AssetCfg>)>;
struct aloader_entry {
AssetType tag;
const std::string filename;
const std::string alias;
std::shared_ptr<AssetCfg> config;
};
class AssetsLoader {
Assets* assets;
std::map<AssetType, aloader_func> loaders;
std::queue<aloader_entry> entries;
const ResPaths* paths;
void tryAddSound(std::string name);
void processPreload(AssetType tag, const std::string& name, dynamic::Map* map);
void processPreloadList(AssetType tag, dynamic::List* list);
void processPreloadConfig(std::filesystem::path file);
void processPreloadConfigs(const Content* content);
public:
AssetsLoader(Assets* assets, const ResPaths* paths);
void addLoader(AssetType tag, aloader_func func);
/// @brief Enqueue asset load
/// @param tag asset type
/// @param filename asset file path
/// @param alias internal asset name
/// @param settings asset loading settings (based on asset type)
void add(
AssetType tag,
const std::string filename,
const std::string alias,
std::shared_ptr<AssetCfg> settings=nullptr
);
bool hasNext() const;
bool loadNext();
/// @brief Enqueue core and content assets
/// @param loader target loader
/// @param content engine content
static void addDefaults(AssetsLoader& loader, const Content* content);
const ResPaths* getPaths() const;
};
#endif // ASSETS_ASSETS_LOADER_H
+113
View File
@@ -0,0 +1,113 @@
#ifndef ASSETS_ASSETS_LOADER_HPP_
#define ASSETS_ASSETS_LOADER_HPP_
#include "Assets.hpp"
#include "../interfaces/Task.hpp"
#include "../typedefs.hpp"
#include "../delegates.hpp"
#include <string>
#include <memory>
#include <filesystem>
#include <functional>
#include <map>
#include <queue>
namespace dynamic {
class Map;
class List;
}
enum class AssetType {
texture,
shader,
font,
atlas,
layout,
sound
};
class ResPaths;
class AssetsLoader;
class Content;
struct AssetCfg {
virtual ~AssetCfg() {}
};
struct LayoutCfg : AssetCfg {
scriptenv env;
LayoutCfg(scriptenv env) : env(env) {}
};
struct SoundCfg : AssetCfg {
bool keepPCM;
SoundCfg(bool keepPCM) : keepPCM(keepPCM) {}
};
using aloader_func = std::function<assetload::postfunc(
AssetsLoader*, // redundant?
const ResPaths*,
const std::string&,
const std::string&,
std::shared_ptr<AssetCfg>)
>;
struct aloader_entry {
AssetType tag;
const std::string filename;
const std::string alias;
std::shared_ptr<AssetCfg> config;
};
class AssetsLoader {
Assets* assets;
std::map<AssetType, aloader_func> loaders;
std::queue<aloader_entry> entries;
const ResPaths* paths;
void tryAddSound(std::string name);
void processPreload(AssetType tag, const std::string& name, dynamic::Map* map);
void processPreloadList(AssetType tag, dynamic::List* list);
void processPreloadConfig(std::filesystem::path file);
void processPreloadConfigs(const Content* content);
public:
AssetsLoader(Assets* assets, const ResPaths* paths);
void addLoader(AssetType tag, aloader_func func);
/// @brief Enqueue asset load
/// @param tag asset type
/// @param filename asset file path
/// @param alias internal asset name
/// @param settings asset loading settings (based on asset type)
void add(
AssetType tag,
const std::string filename,
const std::string alias,
std::shared_ptr<AssetCfg> settings=nullptr
);
bool hasNext() const;
bool loadNext();
std::shared_ptr<Task> startTask(runnable onDone);
const ResPaths* getPaths() const;
aloader_func getLoader(AssetType tag);
/// @brief Enqueue core and content assets
/// @param loader target loader
/// @param content engine content
static void addDefaults(AssetsLoader& loader, const Content* content);
static bool loadExternalTexture(
Assets* assets,
const std::string& name,
std::vector<std::filesystem::path> alternatives
);
};
#endif // ASSETS_ASSETS_LOADER_HPP_
+209 -203
View File
@@ -1,55 +1,54 @@
#include "assetload_funcs.h" #include "assetload_funcs.hpp"
#include "Assets.hpp"
#include "AssetsLoader.hpp"
#include "../data/dynamic.hpp"
#include "../audio/audio.hpp"
#include "../files/files.hpp"
#include "../files/engine_paths.hpp"
#include "../coders/imageio.hpp"
#include "../coders/json.hpp"
#include "../coders/GLSLExtension.hpp"
#include "../graphics/core/Shader.hpp"
#include "../graphics/core/Texture.hpp"
#include "../graphics/core/ImageData.hpp"
#include "../graphics/core/Atlas.hpp"
#include "../graphics/core/Font.hpp"
#include "../graphics/core/TextureAnimation.hpp"
#include "../frontend/UiDocument.hpp"
#include <iostream> #include <iostream>
#include <stdexcept>
#include <filesystem> #include <filesystem>
#include "Assets.h"
#include "AssetsLoader.h"
#include "../audio/audio.h"
#include "../files/files.h"
#include "../files/engine_paths.h"
#include "../coders/png.h"
#include "../coders/json.h"
#include "../graphics/Shader.h"
#include "../graphics/Texture.h"
#include "../graphics/ImageData.h"
#include "../graphics/Atlas.h"
#include "../graphics/Font.h"
#include "../graphics/TextureAnimation.h"
#include "../frontend/UiDocument.h"
#include "../logic/scripting/scripting.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
static bool animation( static bool animation(
Assets* assets, Assets* assets,
const ResPaths* paths, const ResPaths* paths,
const std::string directory, const std::string& atlasName,
const std::string name, const std::string& directory,
const std::string& name,
Atlas* dstAtlas Atlas* dstAtlas
); );
bool assetload::texture( assetload::postfunc assetload::texture(
AssetsLoader&, AssetsLoader*,
Assets* assets,
const ResPaths* paths, const ResPaths* paths,
const std::string filename, const std::string filename,
const std::string name, const std::string name,
std::shared_ptr<AssetCfg> std::shared_ptr<AssetCfg>
) { ) {
std::unique_ptr<Texture> texture( std::shared_ptr<ImageData> image (
png::load_texture(paths->find(filename+".png").u8string()) imageio::read(paths->find(filename+".png").u8string()).release()
); );
if (texture == nullptr) { return [name, image](auto assets) {
std::cerr << "failed to load texture '" << name << "'" << std::endl; assets->store(Texture::from(image.get()).release(), name);
return false; };
}
assets->store(texture.release(), name);
return true;
} }
bool assetload::shader( assetload::postfunc assetload::shader(
AssetsLoader&, AssetsLoader*,
Assets* assets,
const ResPaths* paths, const ResPaths* paths,
const std::string filename, const std::string filename,
const std::string name, const std::string name,
@@ -61,43 +60,32 @@ bool assetload::shader(
std::string vertexSource = files::read_string(vertexFile); std::string vertexSource = files::read_string(vertexFile);
std::string fragmentSource = files::read_string(fragmentFile); std::string fragmentSource = files::read_string(fragmentFile);
Shader* shader = Shader::create( vertexSource = Shader::preprocessor->process(vertexFile, vertexSource);
vertexFile.string(), fragmentSource = Shader::preprocessor->process(fragmentFile, fragmentSource);
fragmentFile.string(),
vertexSource, fragmentSource
);
if (shader == nullptr) { return [=](auto assets) {
std::cerr << "failed to load shader '" << name << "'" << std::endl; assets->store(Shader::create(
return false; vertexFile.u8string(),
} fragmentFile.u8string(),
assets->store(shader, name); vertexSource, fragmentSource
return true; ), name);
};
} }
static bool appendAtlas(AtlasBuilder& atlas, const fs::path& file) { static bool append_atlas(AtlasBuilder& atlas, const fs::path& file) {
// png is only supported format
if (file.extension() != ".png")
return false;
std::string name = file.stem().string(); std::string name = file.stem().string();
// skip duplicates // skip duplicates
if (atlas.has(name)) { if (atlas.has(name)) {
return false; return false;
} }
std::unique_ptr<ImageData> image(png::load_image(file.string())); auto image = imageio::read(file.string());
if (image == nullptr) {
std::cerr << "could not to load " << file.string() << std::endl;
return false;
}
image->fixAlphaColor(); image->fixAlphaColor();
atlas.add(name, image.release()); atlas.add(name, std::move(image));
return true; return true;
} }
bool assetload::atlas( assetload::postfunc assetload::atlas(
AssetsLoader&, AssetsLoader*,
Assets* assets,
const ResPaths* paths, const ResPaths* paths,
const std::string directory, const std::string directory,
const std::string name, const std::string name,
@@ -105,201 +93,219 @@ bool assetload::atlas(
) { ) {
AtlasBuilder builder; AtlasBuilder builder;
for (const auto& file : paths->listdir(directory)) { for (const auto& file : paths->listdir(directory)) {
if (!appendAtlas(builder, file)) continue; if (!imageio::is_read_supported(file.extension().u8string()))
continue;
if (!append_atlas(builder, file))
continue;
} }
Atlas* atlas = builder.build(2); std::set<std::string> names = builder.getNames();
assets->store(atlas, name); Atlas* atlas = builder.build(2, false).release();
for (const auto& file : builder.getNames()) { return [=](auto assets) {
animation(assets, paths, "textures", file, atlas); atlas->prepare();
} assets->store(atlas, name);
return true; for (const auto& file : names) {
animation(assets, paths, name, directory, file, atlas);
}
};
} }
bool assetload::font( assetload::postfunc assetload::font(
AssetsLoader&, AssetsLoader*,
Assets* assets,
const ResPaths* paths, const ResPaths* paths,
const std::string filename, const std::string filename,
const std::string name, const std::string name,
std::shared_ptr<AssetCfg> std::shared_ptr<AssetCfg>
) { ) {
std::vector<std::unique_ptr<Texture>> pages; auto pages = std::make_shared<std::vector<std::unique_ptr<ImageData>>>();
for (size_t i = 0; i <= 4; i++) { for (size_t i = 0; i <= 4; i++) {
std::string name = filename + "_" + std::to_string(i) + ".png"; std::string name = filename + "_" + std::to_string(i) + ".png";
name = paths->find(name).string(); name = paths->find(name).string();
std::unique_ptr<Texture> texture (png::load_texture(name)); pages->push_back(imageio::read(name));
if (texture == nullptr) {
std::cerr << "failed to load bitmap font '" << name;
std::cerr << "' (missing page " << std::to_string(i) << ")";
std::cerr << std::endl;
return false;
}
pages.push_back(std::move(texture));
} }
int res = pages[0]->getHeight() / 16; return [=](auto assets) {
assets->store(new Font(std::move(pages), res, 4), name); int res = pages->at(0)->getHeight() / 16;
return true; std::vector<std::unique_ptr<Texture>> textures;
for (auto& page : *pages) {
textures.emplace_back(Texture::from(page.get()));
}
assets->store(new Font(std::move(textures), res, 4), name);
};
} }
bool assetload::layout( assetload::postfunc assetload::layout(
AssetsLoader& loader, AssetsLoader*,
Assets* assets,
const ResPaths* paths, const ResPaths* paths,
const std::string file, const std::string file,
const std::string name, const std::string name,
std::shared_ptr<AssetCfg> config std::shared_ptr<AssetCfg> config
) { ) {
try { return [=](auto assets) {
auto cfg = dynamic_cast<LayoutCfg*>(config.get()); try {
auto document = UiDocument::read(loader, cfg->env, name, file); auto cfg = std::dynamic_pointer_cast<LayoutCfg>(config);
assets->store(document.release(), name); auto document = UiDocument::read(cfg->env, name, file);
return true; assets->store(document.release(), name);
} catch (const parsing_error& err) { } catch (const parsing_error& err) {
std::cerr << "failed to parse layout XML '" << file << "'" << std::endl; throw std::runtime_error(
std::cerr << err.errorLog() << std::endl; "failed to parse layout XML '"+file+"':\n"+err.errorLog()
return false; );
} }
};
} }
bool assetload::sound( assetload::postfunc assetload::sound(
AssetsLoader& loader, AssetsLoader*,
Assets* assets,
const ResPaths* paths, const ResPaths* paths,
const std::string file, const std::string file,
const std::string name, const std::string name,
std::shared_ptr<AssetCfg> config std::shared_ptr<AssetCfg> config
) { ) {
auto cfg = dynamic_cast<SoundCfg*>(config.get()); auto cfg = std::dynamic_pointer_cast<SoundCfg>(config);
bool keepPCM = cfg ? cfg->keepPCM : false; bool keepPCM = cfg ? cfg->keepPCM : false;
std::string extension = ".ogg"; std::string extension = ".ogg";
try { std::unique_ptr<audio::Sound> baseSound = nullptr;
std::unique_ptr<audio::Sound> baseSound = nullptr;
// looking for 'sound_name' as base sound // looking for 'sound_name' as base sound
auto soundFile = paths->find(file+extension); auto soundFile = paths->find(file+extension);
if (fs::exists(soundFile)) { if (fs::exists(soundFile)) {
baseSound.reset(audio::load_sound(soundFile, keepPCM)); baseSound.reset(audio::load_sound(soundFile, keepPCM));
}
// looking for 'sound_name_0' as base sound
auto variantFile = paths->find(file+"_0"+extension);
if (fs::exists(variantFile)) {
baseSound.reset(audio::load_sound(variantFile, keepPCM));
}
// loading sound variants
for (uint i = 1; ; i++) {
auto variantFile = paths->find(file+"_"+std::to_string(i)+extension);
if (!fs::exists(variantFile)) {
break;
}
baseSound->variants.emplace_back(audio::load_sound(variantFile, keepPCM));
}
assets->store(baseSound.release(), name);
}
catch (std::runtime_error& err) {
std::cerr << err.what() << std::endl;
return false;
} }
return true; // looking for 'sound_name_0' as base sound
auto variantFile = paths->find(file+"_0"+extension);
if (fs::exists(variantFile)) {
baseSound.reset(audio::load_sound(variantFile, keepPCM));
}
// loading sound variants
for (uint i = 1; ; i++) {
auto variantFile = paths->find(file+"_"+std::to_string(i)+extension);
if (!fs::exists(variantFile)) {
break;
}
baseSound->variants.emplace_back(audio::load_sound(variantFile, keepPCM));
}
if (baseSound == nullptr) {
throw std::runtime_error("could not to find sound: " + file);
}
auto sound = baseSound.release();
return [=](auto assets) {
assets->store(sound, name);
};
}
static void read_anim_file(
const std::string& animFile,
std::vector<std::pair<std::string, int>>& frameList
) {
auto root = files::read_json(animFile);
auto frameArr = root->list("frames");
float frameDuration = DEFAULT_FRAME_DURATION;
std::string frameName;
if (frameArr) {
for (size_t i = 0; i < frameArr->size(); i++) {
auto currentFrame = frameArr->list(i);
frameName = currentFrame->str(0);
if (currentFrame->size() > 1) {
frameDuration = currentFrame->integer(1);
}
frameList.emplace_back(frameName, frameDuration);
}
}
}
static TextureAnimation create_animation(
Atlas* srcAtlas,
Atlas* dstAtlas,
const std::string& name,
const std::set<std::string>& frameNames,
const std::vector<std::pair<std::string, int>>& frameList
) {
Texture* srcTex = srcAtlas->getTexture();
Texture* dstTex = dstAtlas->getTexture();
UVRegion region = dstAtlas->get(name);
TextureAnimation animation(srcTex, dstTex);
Frame frame;
uint dstWidth = dstTex->getWidth();
uint dstHeight = dstTex->getHeight();
uint srcWidth = srcTex->getWidth();
uint srcHeight = srcTex->getHeight();
frame.dstPos = glm::ivec2(region.u1 * dstWidth, region.v1 * dstHeight);
frame.size = glm::ivec2(region.u2 * dstWidth, region.v2 * dstHeight) - frame.dstPos;
for (const auto& elem : frameList) {
if (!srcAtlas->has(elem.first)) {
std::cerr << "Unknown frame name: " << elem.first << std::endl;
continue;
}
region = srcAtlas->get(elem.first);
if (elem.second > 0) {
frame.duration = static_cast<float>(elem.second) / 1000.0f;
}
frame.srcPos = glm::ivec2(region.u1 * srcWidth, srcHeight - region.v2 * srcHeight);
animation.addFrame(frame);
}
return animation;
}
inline bool contains(
const std::vector<std::pair<std::string, int>>& frameList,
const std::string& frameName
) {
for (const auto& elem : frameList) {
if (frameName == elem.first) {
return true;
}
}
return false;
} }
static bool animation( static bool animation(
Assets* assets, Assets* assets,
const ResPaths* paths, const ResPaths* paths,
const std::string directory, const std::string& atlasName,
const std::string name, const std::string& directory,
const std::string& name,
Atlas* dstAtlas Atlas* dstAtlas
) { ) {
std::string animsDir = directory + "/animations"; std::string animsDir = directory + "/animation";
std::string blocksDir = directory + "/blocks";
for (const auto& folder : paths->listdir(animsDir)) { for (const auto& folder : paths->listdir(animsDir)) {
if (!fs::is_directory(folder)) continue; if (!fs::is_directory(folder)) continue;
if (folder.filename().string() != name) continue; if (folder.filename().u8string() != name) continue;
if (fs::is_empty(folder)) continue; if (fs::is_empty(folder)) continue;
AtlasBuilder builder; AtlasBuilder builder;
appendAtlas(builder, paths->find(blocksDir + "/" + name + ".png")); append_atlas(builder, paths->find(directory + "/" + name + ".png"));
std::string animFile = folder.string() + "/animation.json";
std::vector<std::pair<std::string, float>> frameList;
std::vector<std::pair<std::string, int>> frameList;
std::string animFile = folder.u8string() + "/animation.json";
if (fs::exists(animFile)) { if (fs::exists(animFile)) {
auto root = files::read_json(animFile); read_anim_file(animFile, frameList);
auto frameArr = root->list("frames");
float frameDuration = DEFAULT_FRAME_DURATION;
std::string frameName;
if (frameArr) {
for (size_t i = 0; i < frameArr->size(); i++) {
auto currentFrame = frameArr->list(i);
frameName = currentFrame->str(0);
if (currentFrame->size() > 1)
frameDuration = static_cast<float>(currentFrame->integer(1)) / 1000;
frameList.emplace_back(frameName, frameDuration);
}
}
} }
for (const auto& file : paths->listdir(animsDir + "/" + name)) { for (const auto& file : paths->listdir(animsDir + "/" + name)) {
if (!frameList.empty()) { if (!frameList.empty() && !contains(frameList, file.stem().u8string())) {
bool contains = false; continue;
for (const auto& elem : frameList) {
if (file.stem() == elem.first) {
contains = true;
break;
}
}
if (!contains) continue;
} }
if (!appendAtlas(builder, file)) continue; if (!append_atlas(builder, file))
continue;
} }
auto srcAtlas = builder.build(2, true);
std::unique_ptr<Atlas> srcAtlas (builder.build(2));
Texture* srcTex = srcAtlas->getTexture();
Texture* dstTex = dstAtlas->getTexture();
TextureAnimation animation(srcTex, dstTex);
Frame frame;
UVRegion region = dstAtlas->get(name);
uint dstWidth = dstTex->getWidth();
uint dstHeight = dstTex->getHeight();
uint srcWidth = srcTex->getWidth();
uint srcHeight = srcTex->getHeight();
frame.dstPos = glm::ivec2(region.u1 * dstWidth, region.v1 * dstHeight);
frame.size = glm::ivec2(region.u2 * dstWidth, region.v2 * dstHeight) - frame.dstPos;
if (frameList.empty()) { if (frameList.empty()) {
for (const auto& elem : builder.getNames()) { for (const auto& frameName : builder.getNames()) {
region = srcAtlas->get(elem); frameList.emplace_back(frameName, 0);
frame.srcPos = glm::ivec2(region.u1 * srcWidth, srcHeight - region.v2 * srcHeight);
animation.addFrame(frame);
} }
} }
else { auto animation = create_animation(
for (const auto& elem : frameList) { srcAtlas.get(), dstAtlas, name, builder.getNames(), frameList
if (!srcAtlas->has(elem.first)) { );
std::cerr << "Unknown frame name: " << elem.first << std::endl; assets->store(srcAtlas.release(), atlasName + "/" + name + "_animation");
continue;
}
region = srcAtlas->get(elem.first);
frame.duration = elem.second;
frame.srcPos = glm::ivec2(region.u1 * srcWidth, srcHeight - region.v2 * srcHeight);
animation.addFrame(frame);
}
}
assets->store(srcAtlas.release(), name + "_animation");
assets->store(animation); assets->store(animation);
return true; return true;
} }
return true; return true;
@@ -1,5 +1,7 @@
#ifndef ASSETS_ASSET_LOADERS_H_ #ifndef ASSETS_ASSET_LOADERS_HPP_
#define ASSETS_ASSET_LOADERS_H_ #define ASSETS_ASSET_LOADERS_HPP_
#include "Assets.hpp"
#include <string> #include <string>
#include <memory> #include <memory>
@@ -12,50 +14,44 @@ struct AssetCfg;
/// @brief see AssetsLoader.h: aloader_func /// @brief see AssetsLoader.h: aloader_func
namespace assetload { namespace assetload {
bool texture( postfunc texture(
AssetsLoader&, AssetsLoader*,
Assets*,
const ResPaths* paths, const ResPaths* paths,
const std::string filename, const std::string filename,
const std::string name, const std::string name,
std::shared_ptr<AssetCfg> settings std::shared_ptr<AssetCfg> settings
); );
bool shader( postfunc shader(
AssetsLoader&, AssetsLoader*,
Assets*,
const ResPaths* paths, const ResPaths* paths,
const std::string filename, const std::string filename,
const std::string name, const std::string name,
std::shared_ptr<AssetCfg> settings std::shared_ptr<AssetCfg> settings
); );
bool atlas( postfunc atlas(
AssetsLoader&, AssetsLoader*,
Assets*,
const ResPaths* paths, const ResPaths* paths,
const std::string directory, const std::string directory,
const std::string name, const std::string name,
std::shared_ptr<AssetCfg> settings std::shared_ptr<AssetCfg> settings
); );
bool font( postfunc font(
AssetsLoader&, AssetsLoader*,
Assets*,
const ResPaths* paths, const ResPaths* paths,
const std::string filename, const std::string filename,
const std::string name, const std::string name,
std::shared_ptr<AssetCfg> settings std::shared_ptr<AssetCfg> settings
); );
bool layout( postfunc layout(
AssetsLoader&, AssetsLoader*,
Assets*,
const ResPaths* paths, const ResPaths* paths,
const std::string file, const std::string file,
const std::string name, const std::string name,
std::shared_ptr<AssetCfg> settings std::shared_ptr<AssetCfg> settings
); );
bool sound( postfunc sound(
AssetsLoader&, AssetsLoader*,
Assets*,
const ResPaths* paths, const ResPaths* paths,
const std::string file, const std::string file,
const std::string name, const std::string name,
@@ -63,4 +59,4 @@ namespace assetload {
); );
} }
#endif // ASSETS_ASSET_LOADERS_H_ #endif // ASSETS_ASSET_LOADERS_HPP_
+16 -10
View File
@@ -1,8 +1,13 @@
#include "ALAudio.h" #include "ALAudio.hpp"
#include "alutil.h"
#include "alutil.hpp"
#include "../../debug/Logger.hpp"
#include <string> #include <string>
#include <iostream> #include <iostream>
static debug::Logger logger("al-audio");
using namespace audio; using namespace audio;
ALSound::ALSound(ALAudio* al, uint buffer, std::shared_ptr<PCM> pcm, bool keepPCM) ALSound::ALSound(ALAudio* al, uint buffer, std::shared_ptr<PCM> pcm, bool keepPCM)
@@ -203,10 +208,10 @@ ALSpeaker::~ALSpeaker() {
} }
} }
void ALSpeaker::update(const Channel* channel, float masterVolume) { void ALSpeaker::update(const Channel* channel) {
if (source == 0) if (source == 0)
return; return;
float gain = this->volume * channel->getVolume()*masterVolume; float gain = this->volume * channel->getVolume();
AL_CHECK(alSourcef(source, AL_GAIN, gain)); AL_CHECK(alSourcef(source, AL_GAIN, gain));
if (!paused) { if (!paused) {
@@ -341,14 +346,14 @@ ALAudio::ALAudio(ALCdevice* device, ALCcontext* context)
alcGetIntegerv(device, ALC_ALL_ATTRIBUTES, size, &attrs[0]); alcGetIntegerv(device, ALC_ALL_ATTRIBUTES, size, &attrs[0]);
for (size_t i = 0; i < attrs.size(); ++i){ for (size_t i = 0; i < attrs.size(); ++i){
if (attrs[i] == ALC_MONO_SOURCES) { if (attrs[i] == ALC_MONO_SOURCES) {
std::cout << "AL: max mono sources: " << attrs[i+1] << std::endl; logger.info() << "max mono sources: " << attrs[i+1];
maxSources = attrs[i+1]; maxSources = attrs[i+1];
} }
} }
auto devices = getAvailableDevices(); auto devices = getAvailableDevices();
std::cout << "AL devices:" << std::endl; logger.info() << "devices:";
for (auto& name : devices) { for (auto& name : devices) {
std::cout << " " << name << std::endl; logger.info() << " " << name;
} }
} }
@@ -368,7 +373,7 @@ ALAudio::~ALAudio() {
AL_CHECK(alcMakeContextCurrent(context)); AL_CHECK(alcMakeContextCurrent(context));
alcDestroyContext(context); alcDestroyContext(context);
if (!alcCloseDevice(device)) { if (!alcCloseDevice(device)) {
std::cerr << "AL: device not closed!" << std::endl; logger.error() << "device not closed!";
} }
device = nullptr; device = nullptr;
context = nullptr; context = nullptr;
@@ -395,7 +400,7 @@ ALAudio* ALAudio::create() {
return nullptr; return nullptr;
} }
AL_CHECK(); AL_CHECK();
std::cout << "AL: initialized" << std::endl; logger.info() << "initialized";
return new ALAudio(device, context); return new ALAudio(device, context);
} }
@@ -406,7 +411,7 @@ uint ALAudio::getFreeSource(){
return source; return source;
} }
if (allsources.size() == maxSources){ if (allsources.size() == maxSources){
std::cerr << "attempted to create new source, but limit is " << maxSources << std::endl; logger.error() << "attempted to create new source, but limit is " << maxSources;
return 0; return 0;
} }
ALuint id; ALuint id;
@@ -467,6 +472,7 @@ void ALAudio::setListener(glm::vec3 position, glm::vec3 velocity, glm::vec3 at,
AL_CHECK(alListener3f(AL_POSITION, position.x, position.y, position.z)); AL_CHECK(alListener3f(AL_POSITION, position.x, position.y, position.z));
AL_CHECK(alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z)); AL_CHECK(alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z));
AL_CHECK(alListenerfv(AL_ORIENTATION, listenerOri)); AL_CHECK(alListenerfv(AL_ORIENTATION, listenerOri));
AL_CHECK(alListenerf(AL_GAIN, get_channel(0)->getVolume()));
} }
void ALAudio::update(double delta) { void ALAudio::update(double delta) {
@@ -1,5 +1,8 @@
#ifndef SRC_AUDIO_AUDIO_H_ #ifndef SRC_AUDIO_AUDIO_HPP_
#define SRC_AUDIO_AUDIO_H_ #define SRC_AUDIO_AUDIO_HPP_
#include "../audio.hpp"
#include "../../typedefs.hpp"
#include <queue> #include <queue>
#include <vector> #include <vector>
@@ -15,9 +18,6 @@
#include <AL/alc.h> #include <AL/alc.h>
#endif #endif
#include "../audio.h"
#include "../../typedefs.h"
namespace audio { namespace audio {
struct ALBuffer; struct ALBuffer;
class ALAudio; class ALAudio;
@@ -91,7 +91,7 @@ namespace audio {
ALSpeaker(ALAudio* al, uint source, int priority, int channel); ALSpeaker(ALAudio* al, uint source, int priority, int channel);
~ALSpeaker(); ~ALSpeaker();
void update(const Channel* channel, float masterVolume) override; void update(const Channel* channel) override;
int getChannel() const override; int getChannel() const override;
State getState() const override; State getState() const override;
@@ -168,4 +168,4 @@ namespace audio {
}; };
} }
#endif /* SRC_AUDIO_AUDIO_H_ */ #endif // SRC_AUDIO_AUDIO_HPP_
+1 -1
View File
@@ -1,4 +1,4 @@
#include "alutil.h" #include "alutil.hpp"
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@@ -1,5 +1,7 @@
#ifndef SRC_AUDIO_AUDIOUTIL_H_ #ifndef AUDIO_AUDIOUTIL_HPP_
#define SRC_AUDIO_AUDIOUTIL_H_ #define AUDIO_AUDIOUTIL_HPP_
#include "../../typedefs.hpp"
#include <string> #include <string>
#include <type_traits> #include <type_traits>
@@ -12,7 +14,6 @@
#endif #endif
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "../../typedefs.h"
#define AL_CHECK(STATEMENT) STATEMENT; AL::check_errors(__FILE__, __LINE__) #define AL_CHECK(STATEMENT) STATEMENT; AL::check_errors(__FILE__, __LINE__)
#define AL_GET_ERROR() AL::check_errors(__FILE__, __LINE__) #define AL_GET_ERROR() AL::check_errors(__FILE__, __LINE__)
@@ -80,4 +81,4 @@ namespace AL {
} }
} }
#endif /* SRC_AUDIO_AUDIOUTIL_H_ */ #endif // AUDIO_AUDIOUTIL_HPP_
+1 -1
View File
@@ -1,4 +1,4 @@
#include "NoAudio.h" #include "NoAudio.hpp"
using namespace audio; using namespace audio;
@@ -1,7 +1,7 @@
#ifndef AUDIO_NOAUDIO_H_ #ifndef AUDIO_NOAUDIO_HPP_
#define AUDIO_NOAUDIO_H_ #define AUDIO_NOAUDIO_HPP_
#include "audio.h" #include "audio.hpp"
namespace audio { namespace audio {
class NoSound : public Sound { class NoSound : public Sound {
@@ -85,4 +85,4 @@ namespace audio {
}; };
} }
#endif // AUDIO_NOAUDIO_H_ #endif // AUDIO_NOAUDIO_HPP_
+8 -9
View File
@@ -1,14 +1,14 @@
#include "audio.h" #include "audio.hpp"
#include "NoAudio.hpp"
#include "AL/ALAudio.hpp"
#include "../coders/wav.hpp"
#include "../coders/ogg.hpp"
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
#include "NoAudio.h"
#include "AL/ALAudio.h"
#include "../coders/wav.h"
#include "../coders/ogg.h"
namespace audio { namespace audio {
static speakerid_t nextId = 1; static speakerid_t nextId = 1;
static Backend* backend; static Backend* backend;
@@ -383,13 +383,12 @@ void audio::update(double delta) {
entry.second->update(delta); entry.second->update(delta);
} }
float masterVolume = channels.at(0)->getVolume();
for (auto it = speakers.begin(); it != speakers.end();) { for (auto it = speakers.begin(); it != speakers.end();) {
auto speaker = it->second.get(); auto speaker = it->second.get();
int speakerChannel = speaker->getChannel(); int speakerChannel = speaker->getChannel();
auto channel = get_channel(speakerChannel); auto channel = get_channel(speakerChannel);
if (channel != nullptr) { if (channel != nullptr) {
speaker->update(channel, speakerChannel == 0 ? 1.0f : masterVolume); speaker->update(channel);
} }
if (speaker->isStopped()) { if (speaker->isStopped()) {
streams.erase(it->first); streams.erase(it->first);
+28 -28
View File
@@ -1,11 +1,12 @@
#ifndef AUDIO_AUDIO_H_ #ifndef AUDIO_AUDIO_HPP_
#define AUDIO_AUDIO_H_ #define AUDIO_AUDIO_HPP_
#include "../typedefs.hpp"
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <filesystem> #include <filesystem>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "../typedefs.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
@@ -235,8 +236,7 @@ namespace audio {
/// @brief Synchronize the speaker with channel settings /// @brief Synchronize the speaker with channel settings
/// @param channel speaker channel /// @param channel speaker channel
/// @param masterVolume volume of the master channel virtual void update(const Channel* channel) = 0;
virtual void update(const Channel* channel, float masterVolume) = 0;
/// @brief Check speaker channel index /// @brief Check speaker channel index
virtual int getChannel() const = 0; virtual int getChannel() const = 0;
@@ -353,52 +353,52 @@ namespace audio {
/// @brief Initialize audio system or use no audio mode /// @brief Initialize audio system or use no audio mode
/// @param enabled try to initialize actual audio /// @param enabled try to initialize actual audio
extern void initialize(bool enabled); void initialize(bool enabled);
/// @brief Load audio file info and PCM data /// @brief Load audio file info and PCM data
/// @param file audio file /// @param file audio file
/// @param headerOnly read header only /// @param headerOnly read header only
/// @throws std::runtime_error if I/O error ocurred or format is unknown /// @throws std::runtime_error if I/O error ocurred or format is unknown
/// @return PCM audio data /// @return PCM audio data
extern PCM* load_PCM(const fs::path& file, bool headerOnly); PCM* load_PCM(const fs::path& file, bool headerOnly);
/// @brief Load sound from file /// @brief Load sound from file
/// @param file audio file path /// @param file audio file path
/// @param keepPCM store PCM data in sound to make it accessible with Sound::getPCM /// @param keepPCM store PCM data in sound to make it accessible with Sound::getPCM
/// @throws std::runtime_error if I/O error ocurred or format is unknown /// @throws std::runtime_error if I/O error ocurred or format is unknown
/// @return new Sound instance /// @return new Sound instance
extern Sound* load_sound(const fs::path& file, bool keepPCM); Sound* load_sound(const fs::path& file, bool keepPCM);
/// @brief Create new sound from PCM data /// @brief Create new sound from PCM data
/// @param pcm PCM data /// @param pcm PCM data
/// @param keepPCM store PCM data in sound to make it accessible with Sound::getPCM /// @param keepPCM store PCM data in sound to make it accessible with Sound::getPCM
/// @return new Sound instance /// @return new Sound instance
extern Sound* create_sound(std::shared_ptr<PCM> pcm, bool keepPCM); Sound* create_sound(std::shared_ptr<PCM> pcm, bool keepPCM);
/// @brief Open new PCM stream from file /// @brief Open new PCM stream from file
/// @param file audio file path /// @param file audio file path
/// @throws std::runtime_error if I/O error ocurred or format is unknown /// @throws std::runtime_error if I/O error ocurred or format is unknown
/// @return new PCMStream instance /// @return new PCMStream instance
extern PCMStream* open_PCM_stream(const fs::path& file); PCMStream* open_PCM_stream(const fs::path& file);
/// @brief Open new audio stream from file /// @brief Open new audio stream from file
/// @param file audio file path /// @param file audio file path
/// @param keepSource store PCMStream in stream to make it accessible with Stream::getSource /// @param keepSource store PCMStream in stream to make it accessible with Stream::getSource
/// @return new Stream instance /// @return new Stream instance
extern Stream* open_stream(const fs::path& file, bool keepSource); Stream* open_stream(const fs::path& file, bool keepSource);
/// @brief Open new audio stream from source /// @brief Open new audio stream from source
/// @param stream PCM data source /// @param stream PCM data source
/// @param keepSource store PCMStream in stream to make it accessible with Stream::getSource /// @param keepSource store PCMStream in stream to make it accessible with Stream::getSource
/// @return new Stream instance /// @return new Stream instance
extern Stream* open_stream(std::shared_ptr<PCMStream> stream, bool keepSource); Stream* open_stream(std::shared_ptr<PCMStream> stream, bool keepSource);
/// @brief Configure 3D listener /// @brief Configure 3D listener
/// @param position listener position /// @param position listener position
/// @param velocity listener velocity (used for Doppler effect) /// @param velocity listener velocity (used for Doppler effect)
/// @param lookAt point the listener look at /// @param lookAt point the listener look at
/// @param up camera up vector /// @param up camera up vector
extern void set_listener( void set_listener(
glm::vec3 position, glm::vec3 position,
glm::vec3 velocity, glm::vec3 velocity,
glm::vec3 lookAt, glm::vec3 lookAt,
@@ -416,7 +416,7 @@ namespace audio {
/// (PRIORITY_LOW, PRIORITY_NORMAL, PRIORITY_HIGH) /// (PRIORITY_LOW, PRIORITY_NORMAL, PRIORITY_HIGH)
/// @param channel channel index /// @param channel channel index
/// @return speaker id or 0 /// @return speaker id or 0
extern speakerid_t play( speakerid_t play(
Sound* sound, Sound* sound,
glm::vec3 position, glm::vec3 position,
bool relative, bool relative,
@@ -436,7 +436,7 @@ namespace audio {
/// @param loop loop stream /// @param loop loop stream
/// @param channel channel index /// @param channel channel index
/// @return speaker id or 0 /// @return speaker id or 0
extern speakerid_t play( speakerid_t play(
std::shared_ptr<Stream> stream, std::shared_ptr<Stream> stream,
glm::vec3 position, glm::vec3 position,
bool relative, bool relative,
@@ -455,7 +455,7 @@ namespace audio {
/// @param loop loop stream /// @param loop loop stream
/// @param channel channel index /// @param channel channel index
/// @return speaker id or 0 /// @return speaker id or 0
extern speakerid_t play_stream( speakerid_t play_stream(
const fs::path& file, const fs::path& file,
glm::vec3 position, glm::vec3 position,
bool relative, bool relative,
@@ -468,49 +468,49 @@ namespace audio {
/// @brief Get speaker by id /// @brief Get speaker by id
/// @param id speaker id /// @param id speaker id
/// @return speaker or nullptr /// @return speaker or nullptr
extern Speaker* get_speaker(speakerid_t id); Speaker* get_speaker(speakerid_t id);
/// @brief Create new channel. /// @brief Create new channel.
/// All non-builtin channels will be destroyed on audio::reset() call /// All non-builtin channels will be destroyed on audio::reset() call
/// @param name channel name /// @param name channel name
/// @return new channel index /// @return new channel index
extern int create_channel(const std::string& name); int create_channel(const std::string& name);
/// @brief Get channel index by name /// @brief Get channel index by name
/// @param name channel name /// @param name channel name
/// @return channel index or -1 /// @return channel index or -1
extern int get_channel_index(const std::string& name); int get_channel_index(const std::string& name);
/// @brief Get channel by index. 0 - is master channel /// @brief Get channel by index. 0 - is master channel
/// @param index channel index /// @param index channel index
/// @return channel or nullptr /// @return channel or nullptr
extern Channel* get_channel(int index); Channel* get_channel(int index);
/// @brief Get channel by name. /// @brief Get channel by name.
/// @param name channel name /// @param name channel name
/// @return channel or nullptr /// @return channel or nullptr
extern Channel* get_channel(const std::string& name); Channel* get_channel(const std::string& name);
/// @brief Get stream associated with speaker /// @brief Get stream associated with speaker
/// @param id speaker id /// @param id speaker id
/// @return stream or nullptr /// @return stream or nullptr
extern std::shared_ptr<Stream> get_associated_stream(speakerid_t id); std::shared_ptr<Stream> get_associated_stream(speakerid_t id);
/// @brief Get alive speakers number (including paused) /// @brief Get alive speakers number (including paused)
extern size_t count_speakers(); size_t count_speakers();
/// @brief Get playing streams number (including paused) /// @brief Get playing streams number (including paused)
extern size_t count_streams(); size_t count_streams();
/// @brief Update audio streams and sound instanced /// @brief Update audio streams and sound instanced
/// @param delta time elapsed since the last update (seconds) /// @param delta time elapsed since the last update (seconds)
extern void update(double delta); void update(double delta);
/// @brief Stop all playing audio in channel, reset channel state /// @brief Stop all playing audio in channel, reset channel state
extern void reset_channel(int channel); void reset_channel(int channel);
/// @brief Finalize audio system /// @brief Finalize audio system
extern void close(); void close();
}; };
#endif // AUDIO_AUDIO_H_ #endif // AUDIO_AUDIO_HPP_
+8 -6
View File
@@ -1,11 +1,13 @@
#include "GLSLExtension.h" #include "GLSLExtension.hpp"
#include "../util/stringutil.hpp"
#include "../typedefs.hpp"
#include "../files/files.hpp"
#include "../files/engine_paths.hpp"
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include "../util/stringutil.h"
#include "../typedefs.h"
#include "../files/files.h"
#include "../files/engine_paths.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
@@ -81,7 +83,7 @@ inline void source_line(std::stringstream& ss, uint linenum) {
ss << "#line " << linenum << "\n"; ss << "#line " << linenum << "\n";
} }
const std::string GLSLExtension::process(const fs::path file, const std::string& source) { const std::string GLSLExtension::process(const fs::path& file, const std::string& source) {
std::stringstream ss; std::stringstream ss;
size_t pos = 0; size_t pos = 0;
uint linenum = 1; uint linenum = 1;
@@ -1,5 +1,5 @@
#ifndef CODERS_GLSL_EXTESION_H_ #ifndef CODERS_GLSL_EXTESION_HPP_
#define CODERS_GLSL_EXTESION_H_ #define CODERS_GLSL_EXTESION_HPP_
#include <string> #include <string>
#include <vector> #include <vector>
@@ -29,7 +29,10 @@ public:
bool hasHeader(const std::string& name) const; bool hasHeader(const std::string& name) const;
bool hasDefine(const std::string& name) const; bool hasDefine(const std::string& name) const;
const std::string process(const std::filesystem::path file, const std::string& source); const std::string process(
const std::filesystem::path& file,
const std::string& source
);
}; };
#endif // CODERS_GLSL_EXTESION_H_ #endif // CODERS_GLSL_EXTESION_HPP_
+24 -21
View File
@@ -1,29 +1,32 @@
#include "binary_json.h" #include "binary_json.hpp"
#include "gzip.hpp"
#include "byte_utils.hpp"
#include "../data/dynamic.hpp"
#include <stdexcept> #include <stdexcept>
#include "gzip.h"
#include "byte_utils.h"
using namespace json; using namespace json;
using namespace dynamic; using namespace dynamic;
static void to_binary(ByteBuilder& builder, const Value* value) { static void to_binary(ByteBuilder& builder, const Value* value) {
switch (value->type) { switch (value->type) {
case valtype::none:
throw std::runtime_error("none value is not implemented");
case valtype::map: { case valtype::map: {
std::vector<ubyte> bytes = to_binary(value->value.map); std::vector<ubyte> bytes = to_binary(std::get<Map*>(value->value));
builder.put(bytes.data(), bytes.size()); builder.put(bytes.data(), bytes.size());
break; break;
} }
case valtype::list: case valtype::list:
builder.put(BJSON_TYPE_LIST); builder.put(BJSON_TYPE_LIST);
for (auto& element : value->value.list->values) { for (auto& element : std::get<List*>(value->value)->values) {
to_binary(builder, element.get()); to_binary(builder, element.get());
} }
builder.put(BJSON_END); builder.put(BJSON_END);
break; break;
case valtype::integer: { case valtype::integer: {
int64_t val = value->value.integer; auto val = std::get<integer_t>(value->value);
if (val >= 0 && val <= 255) { if (val >= 0 && val <= 255) {
builder.put(BJSON_TYPE_BYTE); builder.put(BJSON_TYPE_BYTE);
builder.put(val); builder.put(val);
@@ -41,14 +44,14 @@ static void to_binary(ByteBuilder& builder, const Value* value) {
} }
case valtype::number: case valtype::number:
builder.put(BJSON_TYPE_NUMBER); builder.put(BJSON_TYPE_NUMBER);
builder.putFloat64(value->value.decimal); builder.putFloat64(std::get<number_t>(value->value));
break; break;
case valtype::boolean: case valtype::boolean:
builder.put(BJSON_TYPE_FALSE + value->value.boolean); builder.put(BJSON_TYPE_FALSE + std::get<bool>(value->value));
break; break;
case valtype::string: case valtype::string:
builder.put(BJSON_TYPE_STRING); builder.put(BJSON_TYPE_STRING);
builder.put(*value->value.str); builder.put(std::get<std::string>(value->value));
break; break;
} }
} }
@@ -88,40 +91,40 @@ static Value* value_from_binary(ByteReader& reader) {
case BJSON_TYPE_DOCUMENT: case BJSON_TYPE_DOCUMENT:
type = valtype::map; type = valtype::map;
reader.getInt32(); reader.getInt32();
val.map = object_from_binary(reader); val = object_from_binary(reader);
break; break;
case BJSON_TYPE_LIST: case BJSON_TYPE_LIST:
type = valtype::list; type = valtype::list;
val.list = array_from_binary(reader); val = array_from_binary(reader);
break; break;
case BJSON_TYPE_BYTE: case BJSON_TYPE_BYTE:
type = valtype::integer; type = valtype::integer;
val.integer = reader.get(); val = static_cast<integer_t>(reader.get());
break; break;
case BJSON_TYPE_INT16: case BJSON_TYPE_INT16:
type = valtype::integer; type = valtype::integer;
val.integer = reader.getInt16(); val = static_cast<integer_t>(reader.getInt16());
break; break;
case BJSON_TYPE_INT32: case BJSON_TYPE_INT32:
type = valtype::integer; type = valtype::integer;
val.integer = reader.getInt32(); val = static_cast<integer_t>(reader.getInt32());
break; break;
case BJSON_TYPE_INT64: case BJSON_TYPE_INT64:
type = valtype::integer; type = valtype::integer;
val.integer = reader.getInt64(); val = reader.getInt64();
break; break;
case BJSON_TYPE_NUMBER: case BJSON_TYPE_NUMBER:
type = valtype::number; type = valtype::number;
val.decimal = reader.getFloat64(); val = reader.getFloat64();
break; break;
case BJSON_TYPE_FALSE: case BJSON_TYPE_FALSE:
case BJSON_TYPE_TRUE: case BJSON_TYPE_TRUE:
type = valtype::boolean; type = valtype::boolean;
val.boolean = typecode - BJSON_TYPE_FALSE; val = (typecode - BJSON_TYPE_FALSE) != 0;
break; break;
case BJSON_TYPE_STRING: case BJSON_TYPE_STRING:
type = valtype::string; type = valtype::string;
val.str = new std::string(reader.getString()); val = reader.getString();
break; break;
default: default:
throw std::runtime_error( throw std::runtime_error(
@@ -166,8 +169,8 @@ std::unique_ptr<Map> json::from_binary(const ubyte* src, size_t size) {
if (value->type != valtype::map) { if (value->type != valtype::map) {
throw std::runtime_error("root value is not an object"); throw std::runtime_error("root value is not an object");
} }
std::unique_ptr<Map> obj (value->value.map); std::unique_ptr<Map> obj (std::get<Map*>(value->value));
value->value.map = nullptr; value->value = (Map*)nullptr;
return obj; return obj;
} }
} }
@@ -1,9 +1,14 @@
#ifndef CODERS_BINARY_JSON_H_ #ifndef CODERS_BINARY_JSON_HPP_
#define CODERS_BINARY_JSON_H_ #define CODERS_BINARY_JSON_HPP_
#include "../typedefs.hpp"
#include <vector> #include <vector>
#include <memory> #include <memory>
#include "../data/dynamic.h"
namespace dynamic {
class Map;
}
namespace json { namespace json {
const int BJSON_END = 0x0; const int BJSON_END = 0x0;
@@ -25,4 +30,4 @@ namespace json {
extern std::unique_ptr<dynamic::Map> from_binary(const ubyte* src, size_t size); extern std::unique_ptr<dynamic::Map> from_binary(const ubyte* src, size_t size);
} }
#endif // CODERS_BINARY_JSON_H_ #endif // CODERS_BINARY_JSON_HPP_
+1 -1
View File
@@ -1,4 +1,4 @@
#include "byte_utils.h" #include "byte_utils.hpp"
#include <cstring> #include <cstring>
#include <limits> #include <limits>
@@ -1,9 +1,10 @@
#ifndef CODERS_BYTE_UTILS_H_ #ifndef CODERS_BYTE_UTILS_HPP_
#define CODERS_BYTE_UTILS_H_ #define CODERS_BYTE_UTILS_HPP_
#include "../typedefs.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
#include "../typedefs.h"
/* byteorder: little-endian */ /* byteorder: little-endian */
class ByteBuilder { class ByteBuilder {
@@ -44,7 +45,7 @@ public:
std::vector<ubyte> build(); std::vector<ubyte> build();
}; };
/* byteorder: little-endian */ /// byteorder: little-endian
class ByteReader { class ByteReader {
const ubyte* data; const ubyte* data;
size_t size; size_t size;
@@ -54,26 +55,29 @@ public:
ByteReader(const ubyte* data); ByteReader(const ubyte* data);
void checkMagic(const char* data, size_t size); void checkMagic(const char* data, size_t size);
/* Read one byte (unsigned 8 bit integer) */ /// @brief Read one byte (unsigned 8 bit integer)
ubyte get(); ubyte get();
/* Read one byte (unsigned 8 bit integer) without pointer move */ /// @brief Read one byte (unsigned 8 bit integer) without pointer move
ubyte peek(); ubyte peek();
/* Read signed 16 bit integer */ /// @brief Read signed 16 bit integer
int16_t getInt16(); int16_t getInt16();
/* Read signed 32 bit integer */ /// @brief Read signed 32 bit integer
int32_t getInt32(); int32_t getInt32();
/* Read signed 64 bit integer */ /// @brief Read signed 64 bit integer
int64_t getInt64(); int64_t getInt64();
/* Read 32 bit floating-point number */ /// @brief Read 32 bit floating-point number
float getFloat32(); float getFloat32();
/* Read 64 bit floating-point number */ /// @brief Read 64 bit floating-point number
double getFloat64(); double getFloat64();
/// @brief Read C-String
const char* getCString(); const char* getCString();
/// @brief Read string with unsigned 32 bit number before (length)
std::string getString(); std::string getString();
/// @return true if there is at least one byte remains
bool hasNext() const; bool hasNext() const;
const ubyte* pointer() const; const ubyte* pointer() const;
void skip(size_t n); void skip(size_t n);
}; };
#endif // CODERS_BYTE_UTILS_H_ #endif // CODERS_BYTE_UTILS_HPP_
+331 -344
View File
@@ -1,344 +1,331 @@
#include "commons.h" #include "commons.hpp"
#include <sstream> #include "../util/stringutil.hpp"
#include <stdexcept>
#include <math.h> #include <sstream>
#include <stdexcept>
inline double power(double base, int64_t power) { #include <math.h>
double result = 1.0;
for (int64_t i = 0; i < power; i++) { inline double power(double base, int64_t power) {
result *= base; double result = 1.0;
} for (int64_t i = 0; i < power; i++) {
return result; result *= base;
} }
return result;
parsing_error::parsing_error( }
std::string message,
std::string filename, parsing_error::parsing_error(
std::string source, std::string message,
uint pos, std::string filename,
uint line, std::string source,
uint linestart) uint pos,
: std::runtime_error(message), filename(filename), source(source), uint line,
pos(pos), line(line), linestart(linestart) { uint linestart)
} : std::runtime_error(message), filename(filename), source(source),
pos(pos), line(line), linestart(linestart) {
std::string parsing_error::errorLog() const { }
std::stringstream ss;
uint linepos = pos - linestart; std::string parsing_error::errorLog() const {
ss << "parsing error in file '" << filename; std::stringstream ss;
ss << "' at " << (line+1) << ":" << linepos << ": " << this->what() << "\n"; uint linepos = pos - linestart;
size_t end = source.find("\n", linestart); ss << "parsing error in file '" << filename;
if (end == std::string::npos) { ss << "' at " << (line+1) << ":" << linepos << ": " << this->what() << "\n";
end = source.length(); size_t end = source.find("\n", linestart);
} if (end == std::string::npos) {
ss << source.substr(linestart, end-linestart) << "\n"; end = source.length();
for (uint i = 0; i < linepos; i++) { }
ss << " "; ss << source.substr(linestart, end-linestart) << "\n";
} for (uint i = 0; i < linepos; i++) {
ss << "^"; ss << " ";
return ss.str(); }
ss << "^";
} return ss.str();
}
std::string escape_string(std::string s) {
std::stringstream ss; BasicParser::BasicParser(
ss << '"'; const std::string& file,
for (char c : s) { const std::string& source
switch (c) { ) : filename(file), source(source) {
case '\n': ss << "\\n"; break; }
case '\r': ss << "\\r"; break;
case '\t': ss << "\\t"; break; void BasicParser::skipWhitespace() {
case '\f': ss << "\\f"; break; while (hasNext()) {
case '\b': ss << "\\b"; break; char next = source[pos];
case '"': ss << "\\\""; break; if (next == '\n') {
case '\\': ss << "\\\\"; break; line++;
default: linestart = ++pos;
if (c < ' ') { continue;
ss << "\\" << std::oct << uint(ubyte(c)); }
break; if (is_whitespace(next)) {
} pos++;
ss << c; } else {
break; break;
} }
} }
ss << '"'; }
return ss.str();
} void BasicParser::skip(size_t n) {
n = std::min(n, source.length()-pos);
BasicParser::BasicParser(std::string file, std::string source) : filename(file), source(source) {
} for (size_t i = 0; i < n; i++) {
char next = source[pos++];
void BasicParser::skipWhitespace() { if (next == '\n') {
while (hasNext()) { line++;
char next = source[pos]; linestart = pos;
if (next == '\n') { }
line++; }
linestart = ++pos; }
continue;
} void BasicParser::skipLine() {
if (is_whitespace(next)) { while (hasNext()) {
pos++; if (source[pos] == '\n') {
} else { pos++;
break; linestart = pos;
} line++;
} break;
} }
pos++;
void BasicParser::skip(size_t n) { }
n = std::min(n, source.length()-pos); }
for (size_t i = 0; i < n; i++) { bool BasicParser::skipTo(const std::string& substring) {
char next = source[pos++]; size_t idx = source.find(substring, pos);
if (next == '\n') { if (idx == std::string::npos) {
line++; skip(source.length()-pos);
linestart = pos; return false;
} } else {
} skip(idx-pos);
} return true;
}
void BasicParser::skipLine() { }
while (hasNext()) {
if (source[pos] == '\n') { bool BasicParser::hasNext() {
pos++; return pos < source.length();
linestart = pos; }
line++;
break; bool BasicParser::isNext(const std::string& substring) {
} if (source.length() - pos < substring.length()) {
pos++; return false;
} }
} return source.substr(pos, substring.length()) == substring;
}
bool BasicParser::skipTo(const std::string& substring) {
size_t idx = source.find(substring, pos); char BasicParser::nextChar() {
if (idx == std::string::npos) { if (!hasNext()) {
skip(source.length()-pos); throw error("unexpected end");
return false; }
} else { return source[pos++];
skip(idx-pos); }
return true;
} void BasicParser::expect(char expected) {
} char c = peek();
if (c != expected) {
bool BasicParser::hasNext() { throw error("'"+std::string({expected})+"' expected");
return pos < source.length(); }
} pos++;
}
bool BasicParser::isNext(const std::string& substring) {
if (source.length() - pos < substring.length()) { void BasicParser::expect(const std::string& substring) {
return false; if (substring.empty())
} return;
return source.substr(pos, substring.length()) == substring; for (uint i = 0; i < substring.length(); i++) {
} if (source.length() <= pos + i || source[pos+i] != substring[i]) {
throw error(util::quote(substring)+" expected");
char BasicParser::nextChar() { }
if (!hasNext()) { }
throw error("unexpected end"); pos += substring.length();
} }
return source[pos++];
} void BasicParser::expectNewLine() {
while (hasNext()) {
void BasicParser::expect(char expected) { char next = source[pos];
char c = peek(); if (next == '\n') {
if (c != expected) { line++;
throw error("'"+std::string({expected})+"' expected"); linestart = ++pos;
} return;
pos++; }
} if (is_whitespace(next)) {
pos++;
void BasicParser::expect(const std::string& substring) { } else {
if (substring.empty()) throw error("line separator expected");
return; }
for (uint i = 0; i < substring.length(); i++) { }
if (source.length() <= pos + i || source[pos+i] != substring[i]) { }
throw error(escape_string(substring)+" expected");
} void BasicParser::goBack() {
} if (pos) pos--;
pos += substring.length(); }
}
char BasicParser::peek() {
void BasicParser::expectNewLine() { skipWhitespace();
while (hasNext()) { if (pos >= source.length()) {
char next = source[pos]; throw error("unexpected end");
if (next == '\n') { }
line++; return source[pos];
linestart = ++pos; }
return;
} std::string BasicParser::readUntil(char c) {
if (is_whitespace(next)) { int start = pos;
pos++; while (hasNext() && source[pos] != c) {
} else { pos++;
throw error("line separator expected"); }
} return source.substr(start, pos-start);
} }
}
std::string BasicParser::parseName() {
void BasicParser::goBack() { char c = peek();
if (pos) pos--; if (!is_identifier_start(c)) {
} if (c == '"') {
pos++;
char BasicParser::peek() { return parseString(c);
skipWhitespace(); }
if (pos >= source.length()) { throw error("identifier expected");
throw error("unexpected end"); }
} int start = pos;
return source[pos]; while (hasNext() && is_identifier_part(source[pos])) {
} pos++;
}
std::string BasicParser::parseName() { return source.substr(start, pos-start);
char c = peek(); }
if (!is_identifier_start(c)) {
if (c == '"') { int64_t BasicParser::parseSimpleInt(int base) {
pos++; char c = peek();
return parseString(c); int index = hexchar2int(c);
} if (index == -1 || index >= base) {
throw error("identifier expected"); throw error("invalid number literal");
} }
int start = pos; int64_t value = index;
while (hasNext() && is_identifier_part(source[pos])) { pos++;
pos++; while (hasNext()) {
} c = source[pos];
return source.substr(start, pos-start); while (c == '_') {
} c = source[++pos];
}
int64_t BasicParser::parseSimpleInt(int base) { index = hexchar2int(c);
char c = peek(); if (index == -1 || index >= base) {
int index = hexchar2int(c); return value;
if (index == -1 || index >= base) { }
throw error("invalid number literal"); value *= base;
} value += index;
int64_t value = index; pos++;
pos++; }
while (hasNext()) { return value;
c = source[pos]; }
while (c == '_') {
c = source[++pos]; bool BasicParser::parseNumber(int sign, number_u& out) {
} char c = peek();
index = hexchar2int(c); int base = 10;
if (index == -1 || index >= base) { if (c == '0' && pos + 1 < source.length() &&
return value; (base = is_box(source[pos+1])) != 10) {
} pos += 2;
value *= base; out = parseSimpleInt(base);
value += index; return true;
pos++; } else if (c == 'i' && pos + 2 < source.length() && source[pos+1] == 'n' && source[pos+2] == 'f') {
} pos += 3;
return value; out = INFINITY * sign;
} return false;
} else if (c == 'n' && pos + 2 < source.length() && source[pos+1] == 'a' && source[pos+2] == 'n') {
bool BasicParser::parseNumber(int sign, number_u& out) { pos += 3;
char c = peek(); out = NAN * sign;
int base = 10; return false;
if (c == '0' && pos + 1 < source.length() && }
(base = is_box(source[pos+1])) != 10) { int64_t value = parseSimpleInt(base);
pos += 2; if (!hasNext()) {
out.ival = parseSimpleInt(base); out = value * sign;
return true; return true;
} else if (c == 'i' && pos + 2 < source.length() && source[pos+1] == 'n' && source[pos+2] == 'f') { }
pos += 3; c = source[pos];
out.fval = INFINITY * sign; if (c == 'e' || c == 'E') {
return false; pos++;
} else if (c == 'n' && pos + 2 < source.length() && source[pos+1] == 'a' && source[pos+2] == 'n') { int s = 1;
pos += 3; if (peek() == '-') {
out.fval = NAN * sign; s = -1;
return false; pos++;
} } else if (peek() == '+'){
int64_t value = parseSimpleInt(base); pos++;
if (!hasNext()) { }
out.ival = value * sign; out = sign * value * power(10.0, s * parseSimpleInt(10));
return true; return false;
} }
c = source[pos]; if (c == '.') {
if (c == 'e' || c == 'E') { pos++;
pos++; int64_t expo = 1;
int s = 1; while (hasNext() && source[pos] == '0') {
if (peek() == '-') { expo *= 10;
s = -1; pos++;
pos++; }
} else if (peek() == '+'){ int64_t afterdot = 0;
pos++; if (hasNext() && is_digit(source[pos])) {
} afterdot = parseSimpleInt(10);
out.fval = sign * value * power(10.0, s * parseSimpleInt(10)); }
return false; expo *= power(10, fmax(0, log10(afterdot) + 1));
} c = source[pos];
if (c == '.') {
pos++; double dvalue = (value + (afterdot / (double)expo));
int64_t expo = 1; if (c == 'e' || c == 'E') {
while (hasNext() && source[pos] == '0') { pos++;
expo *= 10; int s = 1;
pos++; if (peek() == '-') {
} s = -1;
int64_t afterdot = 0; pos++;
if (hasNext() && is_digit(source[pos])) { } else if (peek() == '+'){
afterdot = parseSimpleInt(10); pos++;
} }
expo *= power(10, fmax(0, log10(afterdot) + 1)); out = sign * dvalue * power(10.0, s * parseSimpleInt(10));
c = source[pos]; return false;
}
double dvalue = (value + (afterdot / (double)expo)); out = sign * dvalue;
if (c == 'e' || c == 'E') { return false;
pos++; }
int s = 1; out = sign * value;
if (peek() == '-') { return true;
s = -1; }
pos++;
} else if (peek() == '+'){ std::string BasicParser::parseString(char quote, bool closeRequired) {
pos++; std::stringstream ss;
} while (hasNext()) {
out.fval = sign * dvalue * power(10.0, s * parseSimpleInt(10)); char c = source[pos];
return false; if (c == quote) {
} pos++;
out.fval = sign * dvalue; return ss.str();
return false; }
} if (c == '\\') {
out.ival = sign * value; pos++;
return true; c = nextChar();
} if (c >= '0' && c <= '7') {
pos--;
std::string BasicParser::parseString(char quote, bool closeRequired) { ss << (char)parseSimpleInt(8);
std::stringstream ss; continue;
while (hasNext()) { }
char c = source[pos]; switch (c) {
if (c == quote) { case 'n': ss << '\n'; break;
pos++; case 'r': ss << '\r'; break;
return ss.str(); case 'b': ss << '\b'; break;
} case 't': ss << '\t'; break;
if (c == '\\') { case 'f': ss << '\f'; break;
pos++; case '\'': ss << '\\'; break;
c = nextChar(); case '"': ss << '"'; break;
if (c >= '0' && c <= '7') { case '\\': ss << '\\'; break;
pos--; case '/': ss << '/'; break;
ss << (char)parseSimpleInt(8); case '\n': pos++; continue;
continue; default:
} throw error("'\\" + std::string({c}) +
switch (c) { "' is an illegal escape");
case 'n': ss << '\n'; break; }
case 'r': ss << '\r'; break; continue;
case 'b': ss << '\b'; break; }
case 't': ss << '\t'; break; if (c == '\n' && closeRequired) {
case 'f': ss << '\f'; break; throw error("non-closed string literal");
case '\'': ss << '\\'; break; }
case '"': ss << '"'; break; ss << c;
case '\\': ss << '\\'; break; pos++;
case '/': ss << '/'; break; }
case '\n': pos++; continue; if (closeRequired) {
default: throw error("unexpected end");
throw error("'\\" + std::string({c}) + }
"' is an illegal escape"); return ss.str();
} }
continue;
} parsing_error BasicParser::error(std::string message) {
if (c == '\n' && closeRequired) { return parsing_error(message, filename, source, pos, line, linestart);
throw error("non-closed string literal"); }
}
ss << c;
pos++;
}
if (closeRequired) {
throw error("unexpected end");
}
return ss.str();
}
parsing_error BasicParser::error(std::string message) {
return parsing_error(message, filename, source, pos, line, linestart);
}
+23 -25
View File
@@ -1,14 +1,10 @@
#ifndef CODERS_COMMONS_H_ #ifndef CODERS_COMMONS_HPP_
#define CODERS_COMMONS_H_ #define CODERS_COMMONS_HPP_
#include "../typedefs.hpp"
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
#include "../typedefs.h"
union number_u {
double fval;
int64_t ival;
};
inline int is_box(int c) { inline int is_box(int c) {
switch (c) { switch (c) {
@@ -54,8 +50,6 @@ inline int hexchar2int(int c) {
return -1; return -1;
} }
extern std::string escape_string(std::string s);
class parsing_error : public std::runtime_error { class parsing_error : public std::runtime_error {
public: public:
std::string filename; std::string filename;
@@ -64,20 +58,21 @@ public:
uint line; uint line;
uint linestart; uint linestart;
parsing_error(std::string message, parsing_error(
std::string filename, std::string message,
std::string source, std::string filename,
uint pos, std::string source,
uint line, uint pos,
uint linestart); uint line,
uint linestart
);
std::string errorLog() const; std::string errorLog() const;
}; };
class BasicParser { class BasicParser {
protected: protected:
std::string filename; const std::string& filename;
std::string source; const std::string& source;
uint pos = 0; uint pos = 0;
uint line = 1; uint line = 1;
uint linestart = 0; uint linestart = 0;
@@ -88,21 +83,24 @@ protected:
bool skipTo(const std::string& substring); bool skipTo(const std::string& substring);
void expect(char expected); void expect(char expected);
void expect(const std::string& substring); void expect(const std::string& substring);
char peek();
char nextChar();
bool hasNext();
bool isNext(const std::string& substring); bool isNext(const std::string& substring);
void expectNewLine(); void expectNewLine();
void goBack(); void goBack();
std::string parseName();
int64_t parseSimpleInt(int base); int64_t parseSimpleInt(int base);
bool parseNumber(int sign, number_u& out); bool parseNumber(int sign, number_u& out);
std::string parseString(char chr, bool closeRequired=true); std::string parseString(char chr, bool closeRequired=true);
parsing_error error(std::string message); parsing_error error(std::string message);
BasicParser(std::string filename, std::string source); public:
std::string readUntil(char c);
std::string parseName();
bool hasNext();
char peek();
char nextChar();
BasicParser(const std::string& file, const std::string& source);
}; };
#endif // CODERS_COMMONS_H_ #endif // CODERS_COMMONS_HPP_
+3 -2
View File
@@ -1,10 +1,11 @@
#include "gzip.h" #include "gzip.hpp"
#include "byte_utils.hpp"
#define ZLIB_CONST #define ZLIB_CONST
#include <zlib.h> #include <zlib.h>
#include <math.h> #include <math.h>
#include <memory> #include <memory>
#include "byte_utils.h"
std::vector<ubyte> gzip::compress(const ubyte* src, size_t size) { std::vector<ubyte> gzip::compress(const ubyte* src, size_t size) {
size_t buffer_size = 23+size*1.01; size_t buffer_size = 23+size*1.01;
+4 -4
View File
@@ -1,8 +1,8 @@
#ifndef CODERS_GZIP_H_ #ifndef CODERS_GZIP_HPP_
#define CODERS_GZIP_H_ #define CODERS_GZIP_HPP_
#include "../typedefs.hpp"
#include <vector> #include <vector>
#include "../typedefs.h"
namespace gzip { namespace gzip {
const unsigned char MAGIC[] = "\x1F\x8B"; const unsigned char MAGIC[] = "\x1F\x8B";
@@ -18,4 +18,4 @@ namespace gzip {
std::vector<ubyte> decompress(const ubyte* src, size_t size); std::vector<ubyte> decompress(const ubyte* src, size_t size);
} }
#endif // CODERS_GZIP_H_ #endif // CODERS_GZIP_HPP_
+49
View File
@@ -0,0 +1,49 @@
#include "imageio.hpp"
#include "png.hpp"
#include "../graphics/core/ImageData.hpp"
#include <filesystem>
#include <functional>
#include <unordered_map>
namespace fs = std::filesystem;
using image_reader = std::function<std::unique_ptr<ImageData>(const std::string&)>;
using image_writer = std::function<void(const std::string&, const ImageData*)>;
static std::unordered_map<std::string, image_reader> readers {
{".png", png::load_image},
};
static std::unordered_map<std::string, image_writer> writers {
{".png", png::write_image},
};
bool imageio::is_read_supported(const std::string& extension) {
return readers.find(extension) != readers.end();
}
bool imageio::is_write_supported(const std::string& extension) {
return writers.find(extension) != writers.end();
}
inline std::string extensionOf(const std::string& filename) {
return fs::u8path(filename).extension().u8string();
}
std::unique_ptr<ImageData> imageio::read(const std::string& filename) {
auto found = readers.find(extensionOf(filename));
if (found == readers.end()) {
throw std::runtime_error("file format is not supported (read): "+filename);
}
return std::unique_ptr<ImageData>(found->second(filename));
}
void imageio::write(const std::string& filename, const ImageData* image) {
auto found = writers.find(extensionOf(filename));
if (found == writers.end()) {
throw std::runtime_error("file format is not supported (write): "+filename);
}
return found->second(filename, image);
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef CODERS_IMAGEIO_HPP_
#define CODERS_IMAGEIO_HPP_
#include <string>
#include <memory>
class ImageData;
namespace imageio {
inline const std::string PNG = ".png";
bool is_read_supported(const std::string& extension);
bool is_write_supported(const std::string& extension);
std::unique_ptr<ImageData> read(const std::string& filename);
void write(const std::string& filename, const ImageData* image);
}
#endif // CODERS_IMAGEIO_HPP_
+27 -26
View File
@@ -1,13 +1,13 @@
#include "json.h" #include "json.hpp"
#include "../data/dynamic.hpp"
#include "../util/stringutil.hpp"
#include <math.h> #include <math.h>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <memory> #include <memory>
#include "commons.h"
#include "../data/dynamic.h"
using namespace json; using namespace json;
using namespace dynamic; using namespace dynamic;
@@ -42,10 +42,11 @@ void stringify(const Value* value,
const std::string& indentstr, const std::string& indentstr,
bool nice) { bool nice) {
if (value->type == valtype::map) { if (value->type == valtype::map) {
stringifyObj(value->value.map, ss, indent, indentstr, nice); auto map = std::get<Map*>(value->value);
stringifyObj(map, ss, indent, indentstr, nice);
} }
else if (value->type == valtype::list) { else if (value->type == valtype::list) {
auto list = value->value.list; auto list = std::get<List*>(value->value);
if (list->size() == 0) { if (list->size() == 0) {
ss << "[]"; ss << "[]";
return; return;
@@ -66,14 +67,14 @@ void stringify(const Value* value,
} }
ss << ']'; ss << ']';
} else if (value->type == valtype::boolean) { } else if (value->type == valtype::boolean) {
ss << (value->value.boolean ? "true" : "false"); ss << (std::get<bool>(value->value) ? "true" : "false");
} else if (value->type == valtype::number) { } else if (value->type == valtype::number) {
ss << std::setprecision(15); ss << std::setprecision(15);
ss << value->value.decimal; ss << std::get<number_t>(value->value);
} else if (value->type == valtype::integer) { } else if (value->type == valtype::integer) {
ss << value->value.integer; ss << std::get<integer_t>(value->value);
} else if (value->type == valtype::string) { } else if (value->type == valtype::string) {
ss << escape_string(*value->value.str); ss << util::escape(std::get<std::string>(value->value));
} }
} }
@@ -94,7 +95,7 @@ void stringifyObj(const Map* obj,
newline(ss, nice, indent, indentstr); newline(ss, nice, indent, indentstr);
} }
Value* value = entry.second.get(); Value* value = entry.second.get();
ss << escape_string(key) << ": "; ss << util::escape(key) << ": ";
stringify(value, ss, indent+1, indentstr, nice); stringify(value, ss, indent+1, indentstr, nice);
index++; index++;
if (index < obj->values.size()) { if (index < obj->values.size()) {
@@ -116,8 +117,8 @@ std::string json::stringify(
return ss.str(); return ss.str();
} }
Parser::Parser(std::string filename, std::string source) Parser::Parser(const std::string& filename, const std::string& source)
: BasicParser(filename, source) { : BasicParser(filename, source) {
} }
Map* Parser::parse() { Map* Parser::parse() {
@@ -189,10 +190,10 @@ Value* Parser::parseValue() {
number_u num; number_u num;
valtype type; valtype type;
if (parseNumber(next == '-' ? -1 : 1, num)) { if (parseNumber(next == '-' ? -1 : 1, num)) {
val.integer = num.ival; val = std::get<integer_t>(num);
type = valtype::integer; type = valtype::integer;
} else { } else {
val.decimal = num.fval; val = std::get<number_t>(num);
type = valtype::number; type = valtype::number;
} }
return new Value(type, val); return new Value(type, val);
@@ -200,53 +201,53 @@ Value* Parser::parseValue() {
if (is_identifier_start(next)) { if (is_identifier_start(next)) {
std::string literal = parseName(); std::string literal = parseName();
if (literal == "true") { if (literal == "true") {
val.boolean = true; val = true;
return new Value(valtype::boolean, val); return new Value(valtype::boolean, val);
} else if (literal == "false") { } else if (literal == "false") {
val.boolean = false; val = false;
return new Value(valtype::boolean, val); return new Value(valtype::boolean, val);
} else if (literal == "inf") { } else if (literal == "inf") {
val.decimal = INFINITY; val = INFINITY;
return new Value(valtype::number, val); return new Value(valtype::number, val);
} else if (literal == "nan") { } else if (literal == "nan") {
val.decimal = NAN; val = NAN;
return new Value(valtype::number, val); return new Value(valtype::number, val);
} }
throw error("invalid literal "); throw error("invalid literal ");
} }
if (next == '{') { if (next == '{') {
val.map = parseObject(); val = parseObject();
return new Value(valtype::map, val); return new Value(valtype::map, val);
} }
if (next == '[') { if (next == '[') {
val.list = parseList(); val = parseList();
return new Value(valtype::list, val); return new Value(valtype::list, val);
} }
if (is_digit(next)) { if (is_digit(next)) {
number_u num; number_u num;
valtype type; valtype type;
if (parseNumber(1, num)) { if (parseNumber(1, num)) {
val.integer = num.ival; val = std::get<integer_t>(num);
type = valtype::integer; type = valtype::integer;
} else { } else {
val.decimal = num.fval; val = std::get<number_t>(num);
type = valtype::number; type = valtype::number;
} }
return new Value(type, val); return new Value(type, val);
} }
if (next == '"' || next == '\'') { if (next == '"' || next == '\'') {
pos++; pos++;
val.str = new std::string(parseString(next)); val = parseString(next);
return new Value(valtype::string, val); return new Value(valtype::string, val);
} }
throw error("unexpected character '"+std::string({next})+"'"); throw error("unexpected character '"+std::string({next})+"'");
} }
std::unique_ptr<Map> json::parse(std::string filename, std::string source) { std::unique_ptr<Map> json::parse(const std::string& filename, const std::string& source) {
Parser parser(filename, source); Parser parser(filename, source);
return std::unique_ptr<Map>(parser.parse()); return std::unique_ptr<Map>(parser.parse());
} }
std::unique_ptr<Map> json::parse(std::string source) { std::unique_ptr<Map> json::parse(const std::string& source) {
return parse("<string>", source); return parse("<string>", source);
} }
+11 -11
View File
@@ -1,5 +1,10 @@
#ifndef CODERS_JSON_H_ #ifndef CODERS_JSON_HPP_
#define CODERS_JSON_H_ #define CODERS_JSON_HPP_
#include "commons.hpp"
#include "binary_json.hpp"
#include "../typedefs.hpp"
#include <vector> #include <vector>
#include <string> #include <string>
@@ -7,11 +12,6 @@
#include <stdexcept> #include <stdexcept>
#include <unordered_map> #include <unordered_map>
#include "commons.h"
#include "../typedefs.h"
#include "binary_json.h"
namespace dynamic { namespace dynamic {
class Map; class Map;
class List; class List;
@@ -24,13 +24,13 @@ namespace json {
dynamic::Map* parseObject(); dynamic::Map* parseObject();
dynamic::Value* parseValue(); dynamic::Value* parseValue();
public: public:
Parser(std::string filename, std::string source); Parser(const std::string& filename, const std::string& source);
dynamic::Map* parse(); dynamic::Map* parse();
}; };
extern std::unique_ptr<dynamic::Map> parse(std::string filename, std::string source); extern std::unique_ptr<dynamic::Map> parse(const std::string& filename, const std::string& source);
extern std::unique_ptr<dynamic::Map> parse(std::string source); extern std::unique_ptr<dynamic::Map> parse(const std::string& source);
extern std::string stringify( extern std::string stringify(
const dynamic::Map* obj, const dynamic::Map* obj,
@@ -38,4 +38,4 @@ namespace json {
const std::string& indent); const std::string& indent);
} }
#endif // CODERS_JSON_H_ #endif // CODERS_JSON_HPP_
+8 -6
View File
@@ -1,12 +1,14 @@
#include "ogg.h" #include "ogg.hpp"
#include "../debug/Logger.hpp"
#include "../audio/audio.hpp"
#include "../typedefs.hpp"
#include <string> #include <string>
#include <iostream>
#include <vorbis/codec.h> #include <vorbis/codec.h>
#include <vorbis/vorbisfile.h> #include <vorbis/vorbisfile.h>
#include "../audio/audio.h" static debug::Logger logger("ogg");
#include "../typedefs.h"
using namespace audio; using namespace audio;
@@ -56,7 +58,7 @@ audio::PCM* ogg::load_pcm(const std::filesystem::path& file, bool headerOnly) {
if (ret == 0) { if (ret == 0) {
eof = true; eof = true;
} else if (ret < 0) { } else if (ret < 0) {
std::cerr << "ogg::load_pcm: " << vorbis_error_message(ret) << std::endl; logger.error() << "ogg::load_pcm: " << vorbis_error_message(ret);
} else { } else {
data.insert(data.end(), std::begin(buffer), std::begin(buffer)+ret); data.insert(data.end(), std::begin(buffer), std::begin(buffer)+ret);
} }
@@ -98,7 +100,7 @@ public:
int bitstream = 0; int bitstream = 0;
long bytes = ov_read(&vf, buffer, bufferSize, 0, 2, true, &bitstream); long bytes = ov_read(&vf, buffer, bufferSize, 0, 2, true, &bitstream);
if (bytes < 0) { if (bytes < 0) {
std::cerr << "ogg::load_pcm: " << vorbis_error_message(bytes) << " " << bytes << std::endl; logger.error() << "ogg::load_pcm: " << vorbis_error_message(bytes) << " " << bytes;
return PCMStream::ERROR; return PCMStream::ERROR;
} }
return bytes; return bytes;
+3 -3
View File
@@ -1,5 +1,5 @@
#ifndef CODERS_OGG_H_ #ifndef CODERS_OGG_HPP_
#define CODERS_OGG_H_ #define CODERS_OGG_HPP_
#include <filesystem> #include <filesystem>
@@ -13,4 +13,4 @@ namespace ogg {
extern audio::PCMStream* create_stream(const std::filesystem::path& file); extern audio::PCMStream* create_stream(const std::filesystem::path& file);
} }
#endif // CODERS_OGG_H_ #endif // CODERS_OGG_HPP_
+191 -204
View File
@@ -1,12 +1,14 @@
#include "png.h" #include "png.hpp"
#include "../graphics/core/ImageData.hpp"
#include "../graphics/core/Texture.hpp"
#include "../files/files.hpp"
#include "../debug/Logger.hpp"
#include <iostream> #include <iostream>
#include <memory>
#include <GL/glew.h> #include <GL/glew.h>
#include "../graphics/ImageData.h" static debug::Logger logger("png-coder");
#include "../graphics/Texture.h"
#include "../files/files.h"
#ifndef _WIN32 #ifndef _WIN32
#define LIBPNG #define LIBPNG
@@ -19,78 +21,76 @@
int _png_write(const char* filename, uint width, uint height, const ubyte* data, bool alpha) { int _png_write(const char* filename, uint width, uint height, const ubyte* data, bool alpha) {
uint pixsize = alpha ? 4 : 3; uint pixsize = alpha ? 4 : 3;
// Open file for writing (binary mode) // Open file for writing (binary mode)
FILE* fp = fopen(filename, "wb"); FILE* fp = fopen(filename, "wb");
if (fp == nullptr) { if (fp == nullptr) {
fprintf(stderr, "Could not open file %s for writing\n", filename); logger.error() << "could not open file " << filename << " for writing";
fclose(fp); fclose(fp);
return 1; return 1;
} }
// Initialize write structure // Initialize write structure
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (png_ptr == nullptr) { if (png_ptr == nullptr) {
fprintf(stderr, "Could not allocate write struct\n"); logger.error() << "could not allocate write struct";
fclose(fp); fclose(fp);
png_destroy_write_struct(&png_ptr, (png_infopp)nullptr); return 1;
return 1; }
}
// Initialize info structure // Initialize info structure
png_infop info_ptr = png_create_info_struct(png_ptr); png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == nullptr) { if (info_ptr == nullptr) {
fprintf(stderr, "Could not allocate info struct\n"); logger.error() << "could not allocate info struct";
fclose(fp); fclose(fp);
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
png_destroy_write_struct(&png_ptr, (png_infopp)nullptr); png_destroy_write_struct(&png_ptr, (png_infopp)nullptr);
return 1; return 1;
} }
// Setup Exception handling // Setup Exception handling
if (setjmp(png_jmpbuf(png_ptr))) { if (setjmp(png_jmpbuf(png_ptr))) {
fprintf(stderr, "Error during png creation\n"); logger.error() << "error during png creation";
fclose(fp); fclose(fp);
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
png_destroy_write_struct(&png_ptr, (png_infopp)nullptr); png_destroy_write_struct(&png_ptr, &info_ptr);
return 1; return 1;
} }
png_init_io(png_ptr, fp); png_init_io(png_ptr, fp);
// Write header (8 bit colour depth) // Write header (8 bit colour depth)
png_set_IHDR(png_ptr, info_ptr, width, height, png_set_IHDR(png_ptr, info_ptr, width, height,
8, 8,
alpha ? PNG_COLOR_TYPE_RGBA : alpha ? PNG_COLOR_TYPE_RGBA :
PNG_COLOR_TYPE_RGB, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE); PNG_FILTER_TYPE_BASE);
png_write_info(png_ptr, info_ptr); png_write_info(png_ptr, info_ptr);
std::unique_ptr<png_byte[]> row(new png_byte[pixsize * width]); auto row = std::make_unique<png_byte[]>(pixsize * width);
// Write image data
// Write image data for (uint y = 0; y < height; y++) {
for (uint y = 0; y < height; y++) { for (uint x = 0; x < width; x++) {
for (uint x = 0; x < width; x++) {
for (uint i = 0; i < pixsize; i++) { for (uint i = 0; i < pixsize; i++) {
row[x * pixsize + i] = (png_byte)data[(y * width + x) * pixsize + i]; row[x * pixsize + i] = (png_byte)data[(y * width + x) * pixsize + i];
} }
} }
png_write_row(png_ptr, row.get()); png_write_row(png_ptr, row.get());
} }
// End write // End write
png_write_end(png_ptr, nullptr); png_write_end(png_ptr, nullptr);
fclose(fp); fclose(fp);
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
png_destroy_write_struct(&png_ptr, (png_infopp)nullptr); png_destroy_write_struct(&png_ptr, &info_ptr);
return 0; return 0;
} }
ImageData* _png_load(const char* file){ std::unique_ptr<ImageData> _png_load(const char* file){
FILE* fp = nullptr; FILE* fp = nullptr;
if ((fp = fopen(file, "rb")) == nullptr) { if ((fp = fopen(file, "rb")) == nullptr) {
return nullptr; return nullptr;
@@ -175,12 +175,12 @@ ImageData* _png_load(const char* file){
format = ImageFormat::rgb888; format = ImageFormat::rgb888;
break; break;
default: default:
printf("Color type %d not supported!\n", color_type); logger.error() << "color type " << color_type << " is not supported!";
png_destroy_read_struct(&png, &info, &end_info); png_destroy_read_struct(&png, &info, &end_info);
fclose(fp); fclose(fp);
return nullptr; return nullptr;
} }
ImageData* image = new ImageData(format, width, height, (void*)image_data.release()); auto image = std::make_unique<ImageData>(format, width, height, (void*)image_data.release());
png_destroy_read_struct(&png, &info, &end_info); png_destroy_read_struct(&png, &info, &end_info);
fclose(fp); fclose(fp);
return image; return image;
@@ -194,172 +194,159 @@ ImageData* _png_load(const char* file){
static const int SPNG_SUCCESS = 0; static const int SPNG_SUCCESS = 0;
//returns spng result code //returns spng result code
int _png_write(const char* filename, uint width, uint height, const ubyte* data, bool alpha) { int _png_write(const char* filename, uint width, uint height, const ubyte* data, bool alpha) {
int fmt; int fmt;
int ret = 0; int ret = 0;
spng_ctx* ctx = nullptr; spng_ctx* ctx = nullptr;
spng_ihdr ihdr = { 0 }; spng_ihdr ihdr = { 0 };
uint pixsize = alpha ? 4 : 3; uint pixsize = alpha ? 4 : 3;
ctx = spng_ctx_new(SPNG_CTX_ENCODER); ctx = spng_ctx_new(SPNG_CTX_ENCODER);
spng_set_option(ctx, SPNG_ENCODE_TO_BUFFER, 1); spng_set_option(ctx, SPNG_ENCODE_TO_BUFFER, 1);
ihdr.width = width; ihdr.width = width;
ihdr.height = height; ihdr.height = height;
ihdr.color_type = alpha ? SPNG_COLOR_TYPE_TRUECOLOR_ALPHA : SPNG_COLOR_TYPE_TRUECOLOR; ihdr.color_type = alpha ? SPNG_COLOR_TYPE_TRUECOLOR_ALPHA : SPNG_COLOR_TYPE_TRUECOLOR;
ihdr.bit_depth = 8; ihdr.bit_depth = 8;
spng_set_ihdr(ctx, &ihdr); spng_set_ihdr(ctx, &ihdr);
fmt = SPNG_FMT_PNG; fmt = SPNG_FMT_PNG;
ret = spng_encode_image(ctx, data, (size_t)width * (size_t)height * pixsize , fmt, SPNG_ENCODE_FINALIZE); ret = spng_encode_image(ctx, data, (size_t)width * (size_t)height * pixsize , fmt, SPNG_ENCODE_FINALIZE);
if (ret != SPNG_SUCCESS) { if (ret != SPNG_SUCCESS) {
printf("spng_encode_image() error: %s\n", spng_strerror(ret)); logger.error() << "spng_encode_image() error: " << spng_strerror(ret);
fflush(stdout); spng_ctx_free(ctx);
spng_ctx_free(ctx); return ret;
return ret; }
}
size_t png_size; size_t png_size;
void* png_buf = spng_get_png_buffer(ctx, &png_size, &ret); void* png_buf = spng_get_png_buffer(ctx, &png_size, &ret);
if (png_buf == nullptr) { if (png_buf == nullptr) {
printf("spng_get_png_buffer() error: %s\n", spng_strerror(ret)); logger.error() << "spng_get_png_buffer() error: " << spng_strerror(ret);
} }
else { else {
files::write_bytes(filename, (const unsigned char*)png_buf, png_size); files::write_bytes(filename, (const unsigned char*)png_buf, png_size);
} }
fflush(stdout); spng_ctx_free(ctx);
spng_ctx_free(ctx); return ret;
return ret;
} }
ImageData* _png_load(const char* file){ std::unique_ptr<ImageData> _png_load(const char* file){
int r = 0; int r = 0;
FILE *png = nullptr; FILE *png = nullptr;
char *pngbuf = nullptr; char *pngbuf = nullptr;
spng_ctx *ctx = nullptr; spng_ctx *ctx = nullptr;
unsigned char *out = nullptr; unsigned char *out = nullptr;
png = fopen(file, "rb"); png = fopen(file, "rb");
if (png == nullptr){ if (png == nullptr){
std::cerr << "could not to open file " << file << std::endl; logger.error() << "could not to open file " << file;
return nullptr; return nullptr;
} }
fseek(png, 0, SEEK_END); fseek(png, 0, SEEK_END);
long siz_pngbuf = ftell(png); long siz_pngbuf = ftell(png);
rewind(png); rewind(png);
if(siz_pngbuf < 1) { if(siz_pngbuf < 1) {
fclose(png); fclose(png);
std::cerr << "could not to read file " << file << std::endl; logger.error() << "could not to read file " << file;
return nullptr; return nullptr;
} }
pngbuf = new char[siz_pngbuf]; pngbuf = new char[siz_pngbuf];
if(fread(pngbuf, siz_pngbuf, 1, png) != 1){ //check of read elements count if(fread(pngbuf, siz_pngbuf, 1, png) != 1){ //check of read elements count
fclose(png); fclose(png);
delete[] pngbuf; delete[] pngbuf;
std::cerr << "fread() failed" << std::endl; logger.error() << "fread() failed: " << file;
return nullptr; return nullptr;
} }
fclose(png); // <- finally closing file fclose(png); // <- finally closing file
ctx = spng_ctx_new(0); ctx = spng_ctx_new(0);
if (ctx == nullptr){ if (ctx == nullptr){
delete[] pngbuf; delete[] pngbuf;
std::cerr << "spng_ctx_new() failed" << std::endl; logger.error() << "spng_ctx_new() failed";
return nullptr; return nullptr;
} }
r = spng_set_crc_action(ctx, SPNG_CRC_USE, SPNG_CRC_USE); r = spng_set_crc_action(ctx, SPNG_CRC_USE, SPNG_CRC_USE);
if (r != SPNG_SUCCESS){ if (r != SPNG_SUCCESS){
delete[] pngbuf; delete[] pngbuf;
spng_ctx_free(ctx); spng_ctx_free(ctx);
std::cerr << "spng_set_crc_action() error: " << spng_strerror(r) << std::endl; logger.error() << "spng_set_crc_action(): " << spng_strerror(r);
return nullptr; return nullptr;
} }
r = spng_set_png_buffer(ctx, pngbuf, siz_pngbuf); r = spng_set_png_buffer(ctx, pngbuf, siz_pngbuf);
if (r != SPNG_SUCCESS){ if (r != SPNG_SUCCESS){
delete[] pngbuf; delete[] pngbuf;
spng_ctx_free(ctx); spng_ctx_free(ctx);
std::cerr << "spng_set_png_buffer() error: " << spng_strerror(r) << std::endl; logger.error() << "spng_set_png_buffer(): " << spng_strerror(r);
return nullptr; return nullptr;
} }
spng_ihdr ihdr; spng_ihdr ihdr;
r = spng_get_ihdr(ctx, &ihdr); r = spng_get_ihdr(ctx, &ihdr);
if (r != SPNG_SUCCESS){ if (r != SPNG_SUCCESS){
delete[] pngbuf; delete[] pngbuf;
spng_ctx_free(ctx); spng_ctx_free(ctx);
std::cerr << "spng_get_ihdr() error: " << spng_strerror(r) << std::endl; logger.error() << "spng_get_ihdr(): " << spng_strerror(r);
return nullptr; return nullptr;
} }
//// Unused "something"
//const char *clr_type_str;
//if(ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE)
// clr_type_str = "grayscale";
//else if(ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR)
// clr_type_str = "truecolor";
//else if(ihdr.color_type == SPNG_COLOR_TYPE_INDEXED)
// clr_type_str = "indexed color";
//else if(ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA)
// clr_type_str = "grayscale with alpha";
//else
// clr_type_str = "truecolor with alpha";
size_t out_size; size_t out_size;
r = spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &out_size); r = spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &out_size);
if (r != SPNG_SUCCESS){ if (r != SPNG_SUCCESS){
delete[] pngbuf; delete[] pngbuf;
spng_ctx_free(ctx); spng_ctx_free(ctx);
std::cerr << "spng_decoded_image_size() error: " << spng_strerror(r) << std::endl; logger.error() << "spng_decoded_image_size(): " << spng_strerror(r);
return nullptr; return nullptr;
} }
out = new unsigned char[out_size]; out = new unsigned char[out_size];
r = spng_decode_image(ctx, out, out_size, SPNG_FMT_RGBA8, 0); r = spng_decode_image(ctx, out, out_size, SPNG_FMT_RGBA8, 0);
if (r != SPNG_SUCCESS){ if (r != SPNG_SUCCESS){
delete[] out; delete[] out;
delete[] pngbuf; delete[] pngbuf;
spng_ctx_free(ctx); spng_ctx_free(ctx);
std::cerr << "spng_decode_image() error: " << spng_strerror(r) << std::endl; logger.error() << "spng_decode_image(): " << spng_strerror(r);
return nullptr; return nullptr;
} }
unsigned char* flipped = new unsigned char[out_size]; unsigned char* flipped = new unsigned char[out_size];
for (size_t i = 0; i < ihdr.height; i+=1){ for (size_t i = 0; i < ihdr.height; i+=1){
size_t rowsize = ihdr.width*4; size_t rowsize = ihdr.width*4;
for (size_t j = 0; j < rowsize; j++){ for (size_t j = 0; j < rowsize; j++){
flipped[(ihdr.height-i-1)*rowsize+j] = out[i*rowsize+j]; flipped[(ihdr.height-i-1)*rowsize+j] = out[i*rowsize+j];
} }
} }
delete[] out; // <- finally delete out // no, delete spng usage delete[] out; // <- finally delete out // no, delete spng usage
ImageData* image = new ImageData(ImageFormat::rgba8888, ihdr.width, ihdr.height, (void*)flipped); auto image = std::make_unique<ImageData>(ImageFormat::rgba8888, ihdr.width, ihdr.height, (void*)flipped);
delete[] pngbuf; delete[] pngbuf;
spng_ctx_free(ctx); spng_ctx_free(ctx);
return image; return image;
} }
#endif #endif
ImageData* png::load_image(std::string filename) { std::unique_ptr<ImageData> png::load_image(const std::string& filename) {
ImageData* image (_png_load(filename.c_str())); auto image = _png_load(filename.c_str());
if (image == nullptr) { if (image == nullptr) {
std::cerr << "Could not load image " << filename << std::endl; throw std::runtime_error("could not load image "+filename);
return nullptr; }
}
return image; return image;
} }
Texture* png::load_texture(std::string filename) { std::unique_ptr<Texture> png::load_texture(const std::string& filename) {
std::unique_ptr<ImageData> image (_png_load(filename.c_str())); auto image = load_image(filename);
if (image == nullptr){ auto texture = Texture::from(image.get());
std::cerr << "Could not load texture " << filename << std::endl;
return nullptr;
}
auto texture = Texture::from(image.get());
texture->setNearestFilter(); texture->setNearestFilter();
return texture; return texture;
} }
void png::write_image(std::string filename, const ImageData* image) { void png::write_image(const std::string& filename, const ImageData* image) {
_png_write(filename.c_str(), image->getWidth(), image->getHeight(), (const ubyte*)image->getData(), image->getFormat() == ImageFormat::rgba8888); _png_write(
} filename.c_str(),
image->getWidth(),
image->getHeight(),
(const ubyte*)image->getData(),
image->getFormat() == ImageFormat::rgba8888
);
}
-16
View File
@@ -1,16 +0,0 @@
#ifndef CODERS_PNG_H_
#define CODERS_PNG_H_
#include <string>
#include "../typedefs.h"
class Texture;
class ImageData;
namespace png {
extern ImageData* load_image(std::string filename);
extern void write_image(std::string filename, const ImageData* image);
extern Texture* load_texture(std::string filename);
}
#endif /* CODERS_PNG_H_ */
+16
View File
@@ -0,0 +1,16 @@
#ifndef CODERS_PNG_HPP_
#define CODERS_PNG_HPP_
#include <memory>
#include <string>
class Texture;
class ImageData;
namespace png {
std::unique_ptr<ImageData> load_image(const std::string& filename);
void write_image(const std::string& filename, const ImageData* image);
std::unique_ptr<Texture> load_texture(const std::string& filename);
}
#endif // CODERS_PNG_HPP_
+90
View File
@@ -0,0 +1,90 @@
#include "rle.hpp"
size_t rle::decode(const ubyte* src, size_t srclen, ubyte* dst) {
size_t offset = 0;
for (size_t i = 0; i < srclen;) {
ubyte len = src[i++];
ubyte c = src[i++];
for (size_t j = 0; j <= len; j++) {
dst[offset++] = c;
}
}
return offset;
}
size_t rle::encode(const ubyte* src, size_t srclen, ubyte* dst) {
if (srclen == 0) {
return 0;
}
size_t offset = 0;
ubyte counter = 0;
ubyte c = src[0];
for (size_t i = 1; i < srclen; i++) {
ubyte cnext = src[i];
if (cnext != c || counter == 255) {
dst[offset++] = counter;
dst[offset++] = c;
c = cnext;
counter = 0;
}
else {
counter++;
}
}
dst[offset++] = counter;
dst[offset++] = c;
return offset;
}
size_t extrle::decode(const ubyte* src, size_t srclen, ubyte* dst) {
size_t offset = 0;
for (size_t i = 0; i < srclen;) {
uint len = src[i++];
if (len & 0x80) {
len &= 0x7F;
len |= ((uint)src[i++]) << 7;
}
ubyte c = src[i++];
for (size_t j = 0; j <= len; j++) {
dst[offset++] = c;
}
}
return offset;
}
size_t extrle::encode(const ubyte* src, size_t srclen, ubyte* dst) {
if (srclen == 0) {
return 0;
}
size_t offset = 0;
uint counter = 0;
ubyte c = src[0];
for (size_t i = 1; i < srclen; i++) {
ubyte cnext = src[i];
if (cnext != c || counter == max_sequence) {
if (counter >= 0x80) {
dst[offset++] = 0x80 | (counter & 0x7F);
dst[offset++] = counter >> 7;
}
else {
dst[offset++] = counter;
}
dst[offset++] = c;
c = cnext;
counter = 0;
}
else {
counter++;
}
}
if (counter >= 0x80) {
dst[offset++] = 0x80 | (counter & 0x7F);
dst[offset++] = counter >> 7;
}
else {
dst[offset++] = counter;
}
dst[offset++] = c;
return offset;
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef CODERS_RLE_HPP_
#define CODERS_RLE_HPP_
#include "../typedefs.hpp"
namespace rle {
size_t encode(const ubyte* src, size_t length, ubyte* dst);
size_t decode(const ubyte* src, size_t length, ubyte* dst);
}
namespace extrle {
constexpr uint max_sequence = 0x7FFF;
size_t encode(const ubyte* src, size_t length, ubyte* dst);
size_t decode(const ubyte* src, size_t length, ubyte* dst);
}
#endif // CODERS_RLE_HPP_
+135 -249
View File
@@ -1,249 +1,135 @@
#include "toml.h" #include "toml.hpp"
#include "commons.h"
#include "commons.hpp"
#include <math.h> #include "../data/setting.hpp"
#include <iostream> #include "../data/dynamic.hpp"
#include <iomanip> #include "../util/stringutil.hpp"
#include <sstream> #include "../files/settings_io.hpp"
#include <assert.h>
#include <math.h>
using std::string; #include <iostream>
#include <iomanip>
using namespace toml; #include <sstream>
#include <assert.h>
Section::Section(string name) : name(name) {
} using namespace toml;
void Section::add(std::string name, Field field) { class Reader : public BasicParser {
if (fields.find(name) != fields.end()) { SettingsHandler& handler;
throw std::runtime_error("field duplication");
} void skipWhitespace() override {
fields[name] = field; BasicParser::skipWhitespace();
keyOrder.push_back(name); if (hasNext() && source[pos] == '#') {
} skipLine();
if (hasNext() && is_whitespace(peek())) {
void Section::add(string name, bool* ptr) { skipWhitespace();
add(name, {fieldtype::ftbool, ptr}); }
} }
}
void Section::add(string name, int* ptr) { void readSection(const std::string& section) {
add(name, {fieldtype::ftint, ptr}); while (hasNext()) {
} skipWhitespace();
if (!hasNext()) {
void Section::add(string name, uint* ptr) { break;
add(name, {fieldtype::ftuint, ptr}); }
} char c = nextChar();
if (c == '[') {
void Section::add(string name, float* ptr) { std::string name = parseName();
add(name, {fieldtype::ftfloat, ptr}); pos++;
} readSection(name);
return;
void Section::add(string name, string* ptr) { }
add(name, {fieldtype::ftstring, ptr}); pos--;
} std::string name = section+"."+parseName();
expect('=');
string Section::getName() const { c = peek();
return name; if (is_digit(c)) {
} number_u num;
parseNumber(1, num);
const Field* Section::field(std::string name) const { if (handler.has(name)) {
auto found = fields.find(name); handler.setValue(name, *dynamic::Value::of(num));
if (found == fields.end()) { }
return nullptr; } else if (c == '-' || c == '+') {
} int sign = c == '-' ? -1 : 1;
return &found->second; pos++;
} number_u num;
parseNumber(sign, num);
const std::vector<std::string>& Section::keys() const { if (handler.has(name)) {
return keyOrder; handler.setValue(name, *dynamic::Value::of(num));
} }
} else if (is_identifier_start(c)) {
Wrapper::~Wrapper() { std::string identifier = parseName();
for (auto entry : sections) { if (handler.has(name)) {
delete entry.second; if (identifier == "true" || identifier == "false") {
} bool flag = identifier == "true";
} handler.setValue(name, *dynamic::Value::boolean(flag));
} else if (identifier == "inf") {
Section& Wrapper::add(std::string name) { handler.setValue(name, *dynamic::Value::of(INFINITY));
if (sections.find(name) != sections.end()) { } else if (identifier == "nan") {
throw std::runtime_error("section duplication"); handler.setValue(name, *dynamic::Value::of(NAN));
} }
Section* section = new Section(name); }
sections[name] = section; } else if (c == '"' || c == '\'') {
keyOrder.push_back(name); pos++;
return *section; std::string str = parseString(c);
} if (handler.has(name)) {
handler.setValue(name, *dynamic::Value::of(str));
Section* Wrapper::section(std::string name) { }
auto found = sections.find(name); } else {
if (found == sections.end()) { throw error("feature is not supported");
return nullptr; }
} expectNewLine();
return found->second; }
} }
std::string Wrapper::write() const { public:
std::stringstream ss; Reader(
for (string key : keyOrder) { SettingsHandler& handler,
const Section* section = sections.at(key); const std::string& file,
ss << "[" << key << "]\n"; const std::string& source)
for (const string& key : section->keys()) { : BasicParser(file, source), handler(handler) {
ss << key << " = "; }
const Field* field = section->field(key);
assert(field != nullptr); void read() {
switch (field->type) { skipWhitespace();
case fieldtype::ftbool: if (!hasNext()) {
ss << (*((bool*)field->ptr) ? "true" : "false"); return;
break; }
case fieldtype::ftint: ss << *((int*)field->ptr); break; readSection("");
case fieldtype::ftuint: ss << *((uint*)field->ptr); break; }
case fieldtype::ftfloat: ss << *((float*)field->ptr); break; };
case fieldtype::ftstring:
ss << escape_string(*((const string*)field->ptr)); void toml::parse(
break; SettingsHandler& handler,
} const std::string& file,
ss << "\n"; const std::string& source
} ) {
ss << "\n"; Reader reader(handler, file, source);
} reader.read();
return ss.str(); }
}
std::string toml::stringify(SettingsHandler& handler) {
Reader::Reader(Wrapper* wrapper, string file, string source) : BasicParser(file, source), wrapper(wrapper) { auto& sections = handler.getSections();
}
std::stringstream ss;
void Reader::skipWhitespace() { for (auto& section : sections) {
BasicParser::skipWhitespace(); ss << "[" << section.name << "]\n";
if (hasNext() && source[pos] == '#') { for (const std::string& key : section.keys) {
skipLine(); ss << key << " = ";
if (hasNext() && is_whitespace(peek())) { auto setting = handler.getSetting(section.name+"."+key);
skipWhitespace(); assert(setting != nullptr);
} if (auto integer = dynamic_cast<IntegerSetting*>(setting)) {
} ss << integer->get();
} } else if (auto number = dynamic_cast<NumberSetting*>(setting)) {
ss << number->get();
void Reader::read() { } else if (auto flag = dynamic_cast<FlagSetting*>(setting)) {
skipWhitespace(); ss << (flag->get() ? "true" : "false");
if (!hasNext()) { } else if (auto string = dynamic_cast<StringSetting*>(setting)) {
return; ss << util::escape(string->get());
} }
readSection(nullptr); ss << "\n";
} }
ss << "\n";
inline bool is_numeric_type(fieldtype type) { }
return type == fieldtype::ftint || type == fieldtype::ftfloat; return ss.str();
} }
void Section::set(string name, double value) {
const Field* field = this->field(name);
if (field == nullptr) {
std::cerr << "warning: unknown key '" << name << "'" << std::endl;
} else {
switch (field->type) {
case fieldtype::ftbool: *(bool*)(field->ptr) = fabs(value) > 0.0; break;
case fieldtype::ftint: *(int*)(field->ptr) = value; break;
case fieldtype::ftuint: *(uint*)(field->ptr) = value; break;
case fieldtype::ftfloat: *(float*)(field->ptr) = value; break;
case fieldtype::ftstring: *(string*)(field->ptr) = std::to_string(value); break;
default:
std::cerr << "error: type error for key '" << name << "'" << std::endl;
}
}
}
void Section::set(std::string name, bool value) {
const Field* field = this->field(name);
if (field == nullptr) {
std::cerr << "warning: unknown key '" << name << "'" << std::endl;
} else {
switch (field->type) {
case fieldtype::ftbool: *(bool*)(field->ptr) = value; break;
case fieldtype::ftint: *(int*)(field->ptr) = (int)value; break;
case fieldtype::ftuint: *(uint*)(field->ptr) = (uint)value; break;
case fieldtype::ftfloat: *(float*)(field->ptr) = (float)value; break;
case fieldtype::ftstring: *(string*)(field->ptr) = value ? "true" : "false"; break;
default:
std::cerr << "error: type error for key '" << name << "'" << std::endl;
}
}
}
void Section::set(std::string name, std::string value) {
const Field* field = this->field(name);
if (field == nullptr) {
std::cerr << "warning: unknown key '" << name << "'" << std::endl;
} else {
switch (field->type) {
case fieldtype::ftstring: *(string*)(field->ptr) = value; break;
default:
std::cerr << "error: type error for key '" << name << "'" << std::endl;
}
}
}
void Reader::readSection(Section* section /*nullable*/) {
while (hasNext()) {
skipWhitespace();
if (!hasNext()) {
break;
}
char c = nextChar();
if (c == '[') {
string name = parseName();
Section* section = wrapper->section(name);
pos++;
readSection(section);
return;
}
pos--;
string name = parseName();
expect('=');
c = peek();
if (is_digit(c)) {
number_u num;
if (parseNumber(1, num)) {
if (section)
section->set(name, (double)num.ival);
} else {
if (section)
section->set(name, num.fval);
}
} else if (c == '-' || c == '+') {
int sign = c == '-' ? -1 : 1;
pos++;
number_u num;
if (parseNumber(sign, num)) {
if (section)
section->set(name, (double)num.ival);
} else {
if (section)
section->set(name, num.fval);
}
} else if (is_identifier_start(c)) {
string identifier = parseName();
if (identifier == "true" || identifier == "false") {
bool flag = identifier == "true";
if (section) {
section->set(name, flag);
}
} else if (identifier == "inf") {
if (section) {
section->set(name, INFINITY);
}
} else if (identifier == "nan") {
if (section) {
section->set(name, NAN);
}
}
} else if (c == '"' || c == '\'') {
pos++;
string str = parseString(c);
if (section) {
section->set(name, str);
}
} else {
throw error("feature is not supported");
}
expectNewLine();
}
}
-68
View File
@@ -1,68 +0,0 @@
#ifndef CODERS_TOML_H_
#define CODERS_TOML_H_
#include <string>
#include <vector>
#include <unordered_map>
#include "commons.h"
namespace toml {
enum class fieldtype {
ftbool,
ftint,
ftuint,
ftfloat,
ftstring,
};
struct Field {
fieldtype type;
void* ptr;
};
class Section {
std::unordered_map<std::string, Field> fields;
std::vector<std::string> keyOrder;
std::string name;
void add(std::string name, Field field);
public:
Section(std::string name);
void add(std::string name, bool* ptr);
void add(std::string name, int* ptr);
void add(std::string name, uint* ptr);
void add(std::string name, float* ptr);
void add(std::string name, std::string* ptr);
const Field* field(std::string name) const;
void set(std::string name, double value);
void set(std::string name, bool value);
void set(std::string name, std::string value);
std::string getName() const;
const std::vector<std::string>& keys() const;
};
class Wrapper {
std::unordered_map<std::string, Section*> sections;
std::vector<std::string> keyOrder;
public:
~Wrapper();
Section& add(std::string section);
Section* section(std::string name);
std::string write() const;
};
class Reader : public BasicParser {
Wrapper* wrapper;
void skipWhitespace() override;
void readSection(Section* section);
public:
Reader(Wrapper* wrapper, std::string file, std::string source);
void read();
};
}
#endif // CODERS_TOML_H_
+20
View File
@@ -0,0 +1,20 @@
#ifndef CODERS_TOML_HPP_
#define CODERS_TOML_HPP_
#include "commons.hpp"
#include <string>
class SettingsHandler;
namespace toml {
std::string stringify(SettingsHandler& handler);
void parse(
SettingsHandler& handler,
const std::string& file,
const std::string& source
);
}
#endif // CODERS_TOML_HPP_
+3 -3
View File
@@ -1,4 +1,6 @@
#include "wav.h" #include "wav.hpp"
#include "../audio/audio.hpp"
#include <vector> #include <vector>
#include <string> #include <string>
@@ -7,8 +9,6 @@
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
#include "../audio/audio.h"
bool is_big_endian() { bool is_big_endian() {
uint32_t ui32_v = 0x01020304; uint32_t ui32_v = 0x01020304;
char bytes[sizeof(uint32_t)]; char bytes[sizeof(uint32_t)];
+3 -3
View File
@@ -1,5 +1,5 @@
#ifndef CODERS_WAV_H_ #ifndef CODERS_WAV_HPP_
#define CODERS_WAV_H_ #define CODERS_WAV_HPP_
#include <filesystem> #include <filesystem>
@@ -13,4 +13,4 @@ namespace wav {
extern audio::PCMStream* create_stream(const std::filesystem::path& file); extern audio::PCMStream* create_stream(const std::filesystem::path& file);
} }
#endif // CODERS_WAV_H_ #endif // CODERS_WAV_HPP_
+19 -13
View File
@@ -1,9 +1,10 @@
#include "xml.h" #include "xml.hpp"
#include "../util/stringutil.hpp"
#include <charconv> #include <charconv>
#include <stdexcept> #include <stdexcept>
#include <sstream> #include <sstream>
#include "../util/stringutil.h"
using namespace xml; using namespace xml;
@@ -36,7 +37,7 @@ bool Attribute::asBool() const {
glm::vec2 Attribute::asVec2() const { glm::vec2 Attribute::asVec2() const {
size_t pos = text.find(','); size_t pos = text.find(',');
if (pos == std::string::npos) { if (pos == std::string::npos) {
throw std::runtime_error("invalid vec2 value "+escape_string(text)); return glm::vec2(util::parse_double(text, 0, text.length()));
} }
return glm::vec2( return glm::vec2(
util::parse_double(text, 0, pos), util::parse_double(text, 0, pos),
@@ -48,11 +49,11 @@ glm::vec2 Attribute::asVec2() const {
glm::vec3 Attribute::asVec3() const { glm::vec3 Attribute::asVec3() const {
size_t pos1 = text.find(','); size_t pos1 = text.find(',');
if (pos1 == std::string::npos) { if (pos1 == std::string::npos) {
throw std::runtime_error("invalid vec3 value "+escape_string(text)); return glm::vec3(util::parse_double(text, 0, text.length()));
} }
size_t pos2 = text.find(',', pos1+1); size_t pos2 = text.find(',', pos1+1);
if (pos2 == std::string::npos) { if (pos2 == std::string::npos) {
throw std::runtime_error("invalid vec3 value "+escape_string(text)); throw std::runtime_error("invalid vec3 value "+util::quote(text));
} }
return glm::vec3( return glm::vec3(
util::parse_double(text, 0, pos1), util::parse_double(text, 0, pos1),
@@ -65,15 +66,15 @@ glm::vec3 Attribute::asVec3() const {
glm::vec4 Attribute::asVec4() const { glm::vec4 Attribute::asVec4() const {
size_t pos1 = text.find(','); size_t pos1 = text.find(',');
if (pos1 == std::string::npos) { if (pos1 == std::string::npos) {
throw std::runtime_error("invalid vec4 value "+escape_string(text)); return glm::vec4(util::parse_double(text, 0, text.length()));
} }
size_t pos2 = text.find(',', pos1+1); size_t pos2 = text.find(',', pos1+1);
if (pos2 == std::string::npos) { if (pos2 == std::string::npos) {
throw std::runtime_error("invalid vec4 value "+escape_string(text)); throw std::runtime_error("invalid vec4 value "+util::quote(text));
} }
size_t pos3 = text.find(',', pos2+1); size_t pos3 = text.find(',', pos2+1);
if (pos3 == std::string::npos) { if (pos3 == std::string::npos) {
throw std::runtime_error("invalid vec4 value "+escape_string(text)); throw std::runtime_error("invalid vec4 value "+util::quote(text));
} }
return glm::vec4( return glm::vec4(
util::parse_double(text, 0, pos1), util::parse_double(text, 0, pos1),
@@ -99,7 +100,7 @@ glm::vec4 Attribute::asColor() const {
} }
return glm::vec4(r / 255.f, g / 255.f, b / 255.f, a / 255.f); return glm::vec4(r / 255.f, g / 255.f, b / 255.f, a / 255.f);
} else { } else {
throw std::runtime_error("hex colors are only supported"); return asVec4() / 255.f;
} }
} }
@@ -176,7 +177,7 @@ const std::string& Document::getEncoding() const {
return encoding; return encoding;
} }
Parser::Parser(std::string filename, std::string source) Parser::Parser(const std::string& filename, const std::string& source)
: BasicParser(filename, source) { : BasicParser(filename, source) {
} }
@@ -196,8 +197,13 @@ xmlelement Parser::parseOpenTag() {
if (peek() == '=') { if (peek() == '=') {
nextChar(); nextChar();
skipWhitespace(); skipWhitespace();
expect('"');
attrtext = parseString('"'); char quote = peek();
if (quote != '\'' && quote != '"') {
throw error("string literal expected");
}
skip(1);
attrtext = parseString(quote);
} }
node->set(attrname, attrtext); node->set(attrname, attrtext);
} }
@@ -377,7 +383,7 @@ static void stringifyElement(
auto attr = entry.second; auto attr = entry.second;
ss << attr.getName(); ss << attr.getName();
if (!attr.getText().empty()) { if (!attr.getText().empty()) {
ss << "=" << escape_string(attr.getText()); ss << "=" << util::escape(attr.getText());
} }
if (count + 1 < int(attrs.size())) { if (count + 1 < int(attrs.size())) {
ss << " "; ss << " ";
+6 -6
View File
@@ -1,5 +1,7 @@
#ifndef CODERS_XML_H_ #ifndef CODERS_XML_HPP_
#define CODERS_XML_H_ #define CODERS_XML_HPP_
#include "commons.hpp"
#include <string> #include <string>
#include <memory> #include <memory>
@@ -7,8 +9,6 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <unordered_map> #include <unordered_map>
#include "commons.h"
namespace xml { namespace xml {
class Node; class Node;
class Attribute; class Attribute;
@@ -118,7 +118,7 @@ namespace xml {
std::string parseText(); std::string parseText();
std::string parseXMLName(); std::string parseXMLName();
public: public:
Parser(std::string filename, std::string source); Parser(const std::string& filename, const std::string& source);
xmldocument parse(); xmldocument parse();
}; };
@@ -141,4 +141,4 @@ namespace xml {
extern xmldocument parse(std::string filename, std::string source); extern xmldocument parse(std::string filename, std::string source);
} }
#endif // CODERS_XML_H_ #endif // CODERS_XML_HPP_
+18 -9
View File
@@ -1,13 +1,20 @@
#ifndef SRC_CONSTANTS_H_ #ifndef CONSTANTS_HPP_
#define SRC_CONSTANTS_H_ #define CONSTANTS_HPP_
#include "typedefs.hpp"
#include <limits> #include <limits>
#include <string> #include <string>
#include "typedefs.h"
inline constexpr int ENGINE_VERSION_MAJOR = 0; inline constexpr int ENGINE_VERSION_MAJOR = 0;
inline constexpr int ENGINE_VERSION_MINOR = 21; inline constexpr int ENGINE_VERSION_MINOR = 21;
inline constexpr bool ENGINE_VERSION_INDEV = true;
#ifdef NDEBUG
inline constexpr bool ENGINE_DEBUG_BUILD = false;
#else
inline constexpr bool ENGINE_DEBUG_BUILD = true;
#endif // NDEBUG
inline const std::string ENGINE_VERSION_STRING = "0.21"; inline const std::string ENGINE_VERSION_STRING = "0.21";
inline constexpr int BLOCK_AIR = 0; inline constexpr int BLOCK_AIR = 0;
@@ -20,19 +27,21 @@ inline constexpr int CHUNK_D = 16;
inline constexpr uint VOXEL_USER_BITS = 8; inline constexpr uint VOXEL_USER_BITS = 8;
inline constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS; inline constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS;
/// @brief pixel size of an item inventory icon
inline constexpr int ITEM_ICON_SIZE = 48; inline constexpr int ITEM_ICON_SIZE = 48;
/* Chunk volume (count of voxels per Chunk) */ /// @brief chunk volume (count of voxels per Chunk)
inline constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D); inline constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D);
/* BLOCK_VOID is block id used to mark non-existing voxel (voxel of missing chunk) */ /// @brief block id used to mark non-existing voxel (voxel of missing chunk)
inline constexpr blockid_t BLOCK_VOID = std::numeric_limits<blockid_t>::max(); inline constexpr blockid_t BLOCK_VOID = std::numeric_limits<blockid_t>::max();
/// @brief item id used to mark non-existing item (error)
inline constexpr itemid_t ITEM_VOID = std::numeric_limits<itemid_t>::max(); inline constexpr itemid_t ITEM_VOID = std::numeric_limits<itemid_t>::max();
/// @brief max number of block definitions possible
inline constexpr blockid_t MAX_BLOCKS = BLOCK_VOID; inline constexpr blockid_t MAX_BLOCKS = BLOCK_VOID;
inline constexpr uint vox_index(uint x, uint y, uint z, uint w=CHUNK_W, uint d=CHUNK_D) { inline constexpr uint vox_index(uint x, uint y, uint z, uint w=CHUNK_W, uint d=CHUNK_D) {
return (y * d + z) * w + x; return (y * d + z) * w + x;
} }
inline const std::string SHADERS_FOLDER = "shaders"; inline const std::string SHADERS_FOLDER = "shaders";
@@ -41,4 +50,4 @@ inline const std::string FONTS_FOLDER = "fonts";
inline const std::string LAYOUTS_FOLDER = "layouts"; inline const std::string LAYOUTS_FOLDER = "layouts";
inline const std::string SOUNDS_FOLDER = "sounds"; inline const std::string SOUNDS_FOLDER = "sounds";
#endif // SRC_CONSTANTS_H_ #endif // CONSTANTS_HPP_
+13 -6
View File
@@ -1,14 +1,14 @@
#include "Content.h" #include "Content.hpp"
#include <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "../voxels/Block.h" #include "../voxels/Block.hpp"
#include "../items/ItemDef.h" #include "../items/ItemDef.hpp"
#include "ContentPack.h" #include "ContentPack.hpp"
#include "../logic/scripting/scripting.h" #include "../logic/scripting/scripting.hpp"
ContentBuilder::~ContentBuilder() {} ContentBuilder::~ContentBuilder() {}
@@ -155,7 +155,14 @@ Content::Content(
drawGroups(std::move(drawGroups)) drawGroups(std::move(drawGroups))
{} {}
Content::~Content() {} Content::~Content() {
for (auto& entry : blockDefs) {
delete entry.second;
}
for (auto& entry : itemDefs) {
delete entry.second;
}
}
Block* Content::findBlock(std::string id) const { Block* Content::findBlock(std::string id) const {
auto found = blockDefs.find(id); auto found = blockDefs.find(id);
@@ -1,5 +1,5 @@
#ifndef CONTENT_CONTENT_H_ #ifndef CONTENT_CONTENT_HPP_
#define CONTENT_CONTENT_H_ #define CONTENT_CONTENT_HPP_
#include <string> #include <string>
#include <vector> #include <vector>
@@ -7,8 +7,8 @@
#include <stdexcept> #include <stdexcept>
#include <unordered_map> #include <unordered_map>
#include <set> #include <set>
#include "../typedefs.h" #include "../typedefs.hpp"
#include "../voxels/Block.h" #include "../voxels/Block.hpp"
using DrawGroups = std::set<ubyte>; using DrawGroups = std::set<ubyte>;
@@ -146,4 +146,4 @@ public:
const std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>>& getPacks() const; const std::unordered_map<std::string, std::unique_ptr<ContentPackRuntime>>& getPacks() const;
}; };
#endif // CONTENT_CONTENT_H_ #endif // CONTENT_CONTENT_HPP_
+9 -10
View File
@@ -1,16 +1,15 @@
#include "ContentLUT.h" #include "ContentLUT.hpp"
#include "Content.hpp"
#include "../constants.hpp"
#include "../files/files.hpp"
#include "../coders/json.hpp"
#include "../voxels/Block.hpp"
#include "../items/ItemDef.hpp"
#include "../data/dynamic.hpp"
#include <memory> #include <memory>
#include "Content.h"
#include "../constants.h"
#include "../files/files.h"
#include "../coders/json.h"
#include "../voxels/Block.h"
#include "../items/ItemDef.h"
#include "../data/dynamic.h"
ContentLUT::ContentLUT(const Content* content, size_t blocksCount, size_t itemsCount) { ContentLUT::ContentLUT(const Content* content, size_t blocksCount, size_t itemsCount) {
auto* indices = content->getIndices(); auto* indices = content->getIndices();
for (size_t i = 0; i < blocksCount; i++) { for (size_t i = 0; i < blocksCount; i++) {
@@ -1,15 +1,15 @@
#ifndef CONTENT_CONTENT_LUT_H_ #ifndef CONTENT_CONTENT_LUT_HPP_
#define CONTENT_CONTENT_LUT_H_ #define CONTENT_CONTENT_LUT_HPP_
#include "Content.hpp"
#include "../typedefs.hpp"
#include "../constants.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
#include <filesystem> #include <filesystem>
#include "../typedefs.h"
#include "../constants.h"
#include "Content.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
struct contententry { struct contententry {
@@ -93,4 +93,4 @@ public:
std::vector<contententry> getMissingContent() const; std::vector<contententry> getMissingContent() const;
}; };
#endif // CONTENT_CONTENT_LUT_H_ #endif // CONTENT_CONTENT_LUT_HPP_
+18 -17
View File
@@ -1,4 +1,17 @@
#include "ContentLoader.h" #include "ContentLoader.hpp"
#include "Content.hpp"
#include "ContentPack.hpp"
#include "../coders/json.hpp"
#include "../core_defs.hpp"
#include "../data/dynamic.hpp"
#include "../debug/Logger.hpp"
#include "../files/files.hpp"
#include "../items/ItemDef.hpp"
#include "../logic/scripting/scripting.hpp"
#include "../typedefs.hpp"
#include "../util/listutil.hpp"
#include "../voxels/Block.hpp"
#include <iostream> #include <iostream>
#include <string> #include <string>
@@ -6,21 +19,10 @@
#include <algorithm> #include <algorithm>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "Content.h"
#include "../items/ItemDef.h"
#include "../util/listutil.h"
#include "../voxels/Block.h"
#include "../files/files.h"
#include "../coders/json.h"
#include "../typedefs.h"
#include "../core_defs.h"
#include "../data/dynamic.h"
#include "ContentPack.h"
#include "../logic/scripting/scripting.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
static debug::Logger logger("content-loader");
ContentLoader::ContentLoader(ContentPack* pack) : pack(pack) { ContentLoader::ContentLoader(ContentPack* pack) : pack(pack) {
} }
@@ -100,7 +102,6 @@ void ContentLoader::fixPackIndices() {
if (modified){ if (modified){
// rewrite modified json // rewrite modified json
std::cout << indexFile << std::endl;
files::write_json(indexFile, root.get()); files::write_json(indexFile, root.get());
} }
} }
@@ -321,11 +322,11 @@ BlockMaterial ContentLoader::loadBlockMaterial(fs::path file, std::string full)
} }
void ContentLoader::load(ContentBuilder& builder) { void ContentLoader::load(ContentBuilder& builder) {
std::cout << "-- loading pack [" << pack->id << "]" << std::endl; logger.info() << "loading pack [" << pack->id << "]";
auto runtime = new ContentPackRuntime(*pack, scripting::create_pack_environment(*pack)); auto runtime = new ContentPackRuntime(*pack, scripting::create_pack_environment(*pack));
builder.add(runtime); builder.add(runtime);
env = runtime->getEnvironment()->getId(); env = runtime->getEnvironment();
ContentPackStats& stats = runtime->getStatsWriteable(); ContentPackStats& stats = runtime->getStatsWriteable();
fixPackIndices(); fixPackIndices();
@@ -1,7 +1,7 @@
#ifndef CONTENT_CONTENT_LOADER_H_ #ifndef CONTENT_CONTENT_LOADER_HPP_
#define CONTENT_CONTENT_LOADER_H_ #define CONTENT_CONTENT_LOADER_HPP_
#include "../voxels/Block.h" #include "../voxels/Block.hpp"
#include <string> #include <string>
#include <filesystem> #include <filesystem>
@@ -18,7 +18,7 @@ namespace dynamic {
class ContentLoader { class ContentLoader {
const ContentPack* pack; const ContentPack* pack;
int env = 0; scriptenv env;
void loadBlock(Block& def, std::string full, std::string name); void loadBlock(Block& def, std::string full, std::string name);
void loadCustomBlockModel(Block& def, dynamic::Map* primitives); void loadCustomBlockModel(Block& def, dynamic::Map* primitives);
@@ -38,4 +38,4 @@ public:
void load(ContentBuilder& builder); void load(ContentBuilder& builder);
}; };
#endif // CONTENT_CONTENT_LOADER_H_ #endif // CONTENT_CONTENT_LOADER_HPP_

Some files were not shown because too many files have changed in this diff Show More