72 Commits

Author SHA1 Message Date
57995a0e00 Remove train station. 2024-11-24 11:18:08 -06:00
53dc496f2f Dawn progress 2024-11-07 18:28:54 -06:00
6a0ffd4a45 about to start work on downtown 2024-10-25 23:02:55 -05:00
ef84c85527 Cleaned a bit of the tile code. Built train station 2024-10-25 10:30:49 -05:00
39d74cc375 Map loading fixes and improvements 2024-10-22 08:00:48 -05:00
ddbef64f43 Started work on using tiled 2024-10-21 20:50:16 -05:00
b2a3ca4411 Example sign with conversation. 2024-10-20 15:31:04 -07:00
a74f285cb2 Memory functions 2024-10-17 09:30:36 -07:00
5fb36aad35 Moved tile interactions over. 2024-10-17 08:44:17 -07:00
258976b76c Made NPCs interactable with the conversation system. 2024-10-17 07:36:33 -07:00
7867076bbe Added language support to main menu and sign 2024-10-17 07:17:36 -07:00
3baafec9cb Adding language 2024-10-16 14:37:34 -07:00
6c062df9bb Added main menu. 2024-10-09 09:47:05 -05:00
825cc88e17 Moving some logic into separate files 2024-10-08 09:36:15 -05:00
9f4cb283c1 UI Menu more or less done perfectly. 2024-10-08 09:17:00 -05:00
86feb7e56a Mid menu coding 2024-10-07 09:49:22 -05:00
a7dc7fdcf8 Remove testmap2 2024-10-07 00:29:59 -05:00
cb3a58e456 Door and map changing 2024-10-07 00:27:20 -05:00
5334f0944e Add direction to the door 2024-10-06 23:21:28 -05:00
a1d4b0a1d7 Door 2024-10-06 23:11:45 -05:00
ecb3b9c5d1 Fixed JSON parsing throwing errors 2024-10-06 22:46:16 -05:00
bf3912bb7f Added sign 2024-10-06 22:23:26 -05:00
b5d7b7e229 Bit more cleanup 2024-10-06 21:01:05 -05:00
b7987401af Map loading basically done for now 2024-10-06 19:03:22 -05:00
ffc46c677c Added triggers to parsing. 2024-10-06 18:57:28 -05:00
7a8ca2fca1 Test loading asset data. 2024-10-06 18:52:52 -05:00
5751f7c83c Add asset loading support. 2024-10-06 18:27:54 -05:00
c69d0ec1cc Adding triggers, prepping for map loading. 2024-10-06 18:03:46 -05:00
e14445680f Add newlines to draw text 2024-10-06 17:30:04 -05:00
5256b32055 Textbox rendering back. 2024-10-06 17:16:24 -05:00
5444b0b8c7 Ensure linux terminal is still working 2024-10-06 16:43:54 -05:00
45b3cf9478 Cleaned old frame code. 2024-10-06 16:34:47 -05:00
0224ddd36b Getting around to cleaning drawing code finally. 2024-10-06 16:28:34 -05:00
40b0395552 idk what I coded 2024-10-06 01:30:45 -05:00
b7829fda5c Add tile interactions. 2024-10-05 10:29:15 -05:00
bdef59bbe1 Make map rendering centered 2024-10-05 10:17:12 -05:00
27ce6526e6 Vastly improve UI 2024-10-05 09:16:41 -05:00
704002e671 Moved TERM files around 2024-10-05 08:35:36 -05:00
cfe4cf6cad Testing mostly 2024-10-04 22:43:33 -05:00
69672cf8a6 Rendering working 2024-10-04 21:51:38 -05:00
c1345218a3 glfw 2024-10-04 16:41:01 -05:00
be27408cf4 Adding back GLFW 2024-10-04 09:37:32 -05:00
4205b919d4 Adding back GLFW 2024-10-04 09:37:24 -05:00
e14083b4b4 t 2024-10-03 22:35:22 -05:00
ad317da97e Reset 2024-10-03 20:09:10 -05:00
2ff1a159bc idk 2024-10-03 20:07:35 -05:00
c770953b2e VN Dummy 2024-09-29 00:47:12 -05:00
2cb1d745b2 Add JSON parser 2024-09-27 21:55:53 -05:00
8ce0e8f9f6 Changed more deps to use FetchContent 2024-09-25 15:11:04 -04:00
5101a856be Remove glm 2024-09-25 15:01:26 -04:00
303d0c0a6f Add camera pixel perfect. 2024-09-16 21:35:04 -05:00
e3a4368d1e Basic tile code ready. 2024-09-16 07:07:01 -05:00
7c34127900 Some more chunk work. 2024-09-16 06:50:47 -05:00
49d90b3362 Working on chunks 2024-09-15 08:41:44 -05:00
935398d45e Minigolf is pog 2024-09-15 08:06:45 -05:00
4065556d4a Switched map loops to weakptrs 2024-09-15 07:50:11 -05:00
fb8f6e3f95 Commit prog 2024-09-14 10:23:31 -05:00
b4c2ce16a0 idk if I like this structure. 2024-09-13 09:26:21 -05:00
b309478922 Trying to tune turning. 2024-09-11 10:07:23 -05:00
ad3974bde5 Testing walking. 2024-09-11 10:04:54 -05:00
e5349cc093 Created basic movement. 2024-09-11 09:21:56 -05:00
01c56477aa Basic movement example 2024-09-11 08:21:26 -05:00
916396e175 Fixed input 2024-09-10 20:17:32 -05:00
0e5b85633c Worked a bit on prefabs of all things 2024-09-10 18:26:14 -05:00
e5f3f69120 Restored UI Label support 2024-09-10 17:36:04 -05:00
ca240bc180 Moved poker code to main dawn code. 2024-09-10 08:46:57 -05:00
a3a891ddb2 Cleanup of poker code done, about to start testing. 2024-09-10 06:51:04 -05:00
5fae94c722 More refactoring 2024-09-10 00:07:15 -05:00
d5b3b6d619 Cleaning poker code pt 1. 2024-09-08 23:12:03 -05:00
b4e261d954 Move over old poker code 2024-09-08 21:54:19 -05:00
856bc306fe More cleanup complete 2024-09-08 15:30:41 -05:00
cffe7f73a2 Cleanup complete 2024-09-08 15:30:32 -05:00
257 changed files with 9167 additions and 4765 deletions

6
.gitignore vendored
View File

@ -65,7 +65,7 @@ CTestTestfile.cmake
_deps
# Custom
build
/build/*
.vscode
assets/testworld/tileset.png
@ -86,6 +86,4 @@ assets/borrowed
._*
*~
archive/*
*~

27
.gitmodules vendored
View File

@ -1,24 +1,3 @@
[submodule "lib/glfw"]
path = lib/glfw
url = https://github.com/glfw/glfw.git
[submodule "lib/glm"]
path = lib/glm
url = https://github.com/g-truc/glm.git
[submodule "lib/SDL"]
path = lib/SDL
url = https://github.com/libsdl-org/SDL.git
[submodule "lib/openal-soft"]
path = lib/openal-soft
url = https://github.com/kcat/openal-soft
[submodule "lib/AudioFile"]
path = lib/AudioFile
url = https://github.com/adamstark/AudioFile.git
[submodule "lib/freetype"]
path = lib/freetype
url = https://gitlab.freedesktop.org/freetype/freetype.git
[submodule "lib/libarchive"]
path = lib/libarchive
url = https://github.com/libarchive/libarchive
[submodule "lib/boxer"]
path = lib/boxer
url = https://github.com/aaronmjacobs/Boxer
[submodule "lib/font8x8"]
path = lib/font8x8
url = https://github.com/dhepper/font8x8

View File

@ -1,106 +1,42 @@
# Copyright (c) 2022 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
set(DAWN_PROJECT_NAME "Dawn")
set(DAWN_PROJECT_VERSION "01.00")
# Variable Caches
set(DAWN_CACHE_TARGET "dawn-target")
# Build target
if(DEFINED ENV{DAWN_BUILD_SYSTEM})
set(DAWN_BUILD_SYSTEM $ENV{DAWN_BUILD_SYSTEM} CACHE INTERNAL ${DAWN_CACHE_TARGET})
else()
set(DAWN_BUILD_SYSTEM "linux" CACHE INTERNAL ${DAWN_CACHE_TARGET})
endif()
# Build tools specifics
if(DAWN_BUILD_SYSTEM STREQUAL "vita")
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
if(DEFINED ENV{VITASDK})
set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
else()
message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
endif()
endif()
include("$ENV{VITASDK}/share/vita.cmake" REQUIRED)
set(DAWN_VITA_APP_NAME "${DAWN_PROJECT_NAME}" CACHE INTERNAL ${DAWN_CACHE_TARGET})
set(DAWN_VITA_TITLEID "YWSH00001" CACHE INTERNAL ${DAWN_CACHE_TARGET})
set(DAWN_VITA_VERSION "${DAWN_PROJECT_VERSION}" CACHE INTERNAL ${DAWN_CACHE_TARGET})
set(VITA_MKSFOEX_FLAGS "${VITA_MKSFOEX_FLAGS} -d PARENTAL_LEVEL=1" CACHE INTERNAL ${DAWN_CACHE_TARGET})
elseif(DAWN_BUILD_SYSTEM STREQUAL "psp")
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
if(DEFINED ENV{PSPDEV})
set(CMAKE_TOOLCHAIN_FILE "$ENV{PSPDEV}/psp/share/pspdev.cmake" CACHE PATH "toolchain file")
else()
message(FATAL_ERROR "Please define PSPDEV to point to your SDK path!")
endif()
endif()
include("$ENV{PSPDEV}/psp/share/pspdev.cmake" REQUIRED)
endif()
# Set Common Build Variables
set(DAWN_ROOT_DIR "${CMAKE_SOURCE_DIR}")
set(DAWN_BUILD_DIR "${CMAKE_BINARY_DIR}")
set(DAWN_SOURCES_DIR "${DAWN_ROOT_DIR}/src")
set(DAWN_TEMP_DIR "${DAWN_BUILD_DIR}/temp")
set(DAWN_TOOLS_DIR "${DAWN_ROOT_DIR}/tools")
set(DAWN_ASSETS_DIR "${DAWN_ROOT_DIR}/assets")
set(DAWN_ASSETS_BUILD_DIR "${DAWN_BUILD_DIR}/assets")
# Variables
set(DAWN_TARGET_NAME "Dawn" CACHE INTERNAL ${DAWN_CACHE_TARGET})
set(DAWN_ASSETS "" CACHE INTERNAL ${DAWN_CACHE_TARGET})
set(DAWN_BUILD_BINARY ${DAWN_BUILD_DIR}/Dawn CACHE INTERNAL ${DAWN_CACHE_TARGET})
# Initialize Project First.
project("${DAWN_PROJECT_NAME}"
VERSION "${DAWN_PROJECT_VERSION}"
LANGUAGES C CXX
)
add_executable(${DAWN_TARGET_NAME})
# Add tools
add_subdirectory(tools)
# Libraries
add_subdirectory(lib)
# Sources
add_subdirectory(src)
# Append assets
add_dependencies(${DAWN_TARGET_NAME} dawnassets)
if(DAWN_BUILD_SYSTEM STREQUAL "vita")
vita_create_self(${DAWN_TARGET_NAME}.self ${DAWN_BUILD_BINARY})
vita_create_vpk(
${DAWN_TARGET_NAME}.vpk
${DAWN_VITA_TITLEID}
${DAWN_TARGET_NAME}.self
VERSION ${DAWN_VITA_VERSION}
NAME ${DAWN_VITA_APP_NAME}
)
elseif(DAWN_BUILD_SYSTEM STREQUAL "psp")
create_pbp_file(
TARGET ${PROJECT_NAME}
ICON_PATH NULL
BACKGROUND_PATH NULL
PREVIEW_PATH NULL
TITLE ${PROJECT_NAME}
VERSION ${DAWN_PROJECT_VERSION}
)
endif()
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Variable Caches
set(DAWN_CACHE_TARGET "dawn-target")
set(DAWN_TARGET_NAME "Dawn")
if(NOT DEFINED DAWN_TARGET)
set(DAWN_TARGET linux-x64-glfw CACHE INTERNAL ${DAWN_CACHE_TARGET})
# set(DAWN_TARGET linux-x64-terminal CACHE INTERNAL ${DAWN_CACHE_TARGET})
endif()
# Set Common Build Variables
set(DAWN_ROOT_DIR "${CMAKE_SOURCE_DIR}")
set(DAWN_BUILD_DIR "${CMAKE_BINARY_DIR}")
set(DAWN_SOURCES_DIR "${DAWN_ROOT_DIR}/src")
set(DAWN_TOOLS_DIR "${DAWN_ROOT_DIR}/tools")
set(DAWN_ASSETS_SOURCE_DIR "${DAWN_ROOT_DIR}/assets")
set(DAWN_ASSETS_BUILD_DIR "${DAWN_BUILD_DIR}/assets")
set(DAWN_GENERATED_DIR "${DAWN_BUILD_DIR}/generated")
set(DAWN_TEMP_DIR "${DAWN_BUILD_DIR}/temp")
# Initialize Project.
project(Dawn
VERSION 1.0.0
LANGUAGES C
)
# Add tools
add_subdirectory(tools)
# Add Libraries
add_subdirectory(lib)
# Add Project Files
add_subdirectory(src)

View File

@ -1,3 +0,0 @@
# Dawn Project
Simple in code, complex in structure game engine for creating small, fast and
reusable games.

42
assets/en.json Normal file
View File

@ -0,0 +1,42 @@
{
"main_menu": {
"new_game": "New Game",
"load_game": "Load Game",
"options": "Options",
"exit": "Exit"
},
"tiles": {
"water": {
"interact": "A refreshing body of water."
},
"lamp": {
"interact": "An electric lamp.\nA real lightbulb idea."
},
"rail": {
"interact": "Train tracks.\n...Better not cross them."
}
},
"entities": {
"sign": {
"name": "Sign"
}
},
"maps": {
"testmap": {
"bob": "Hello, I am Bob.",
"sign": "This is a sign.",
"sign2": {
"1": "This is another sign.",
"2": "It has two lines."
}
},
"train_station": {
"stair_sign": {
"0": "Stairs slippery when wet.\n\n<- West to Town.\n-> East to lakefront."
}
}
},
"battle": {
"start": "Battle Start!"
}
}

46
assets/maps/testmap.tmx Normal file
View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="3" nextobjectid="7">
<tileset firstgid="1" source="../tilemaps/tilemap.tsx"/>
<tileset firstgid="65" source="../tilemaps/entities.tsx"/>
<layer id="1" name="Map" width="30" height="20" locked="1">
<data encoding="csv">
1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,6,6,6,6,6,2,2,2,2,2,2,3,3,3,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,6,6,6,6,6,2,2,2,2,2,3,3,3,3,2,2,2,2,
1,1,1,1,1,2,2,2,2,2,2,2,5,5,5,5,5,2,2,2,2,2,3,3,3,2,2,2,2,2,
1,1,1,1,1,2,2,2,2,2,2,2,5,5,5,5,5,2,2,2,2,2,3,3,3,2,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,5,5,1,5,5,2,2,2,2,3,3,3,3,2,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,2,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,
1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2
</data>
</layer>
<objectgroup id="2" name="Entities">
<object id="4" name="Player" type="player" gid="66" x="87.7275" y="119.497" width="8" height="8"/>
<object id="5" name="Sign" type="sign" gid="68" x="86.8498" y="55.0415" width="8" height="8">
<properties>
<property name="texts_0" value="maps.testmap.sign2.1"/>
<property name="texts_1" value="maps.testmap.sign2.2"/>
</properties>
</object>
<object id="6" name="Door" type="door" gid="69" x="111.791" y="55.7608" width="8" height="8">
<properties>
<property name="direction" type="int" value="2"/>
<property name="map" value="testmap2.map"/>
<property name="x" type="int" value="11"/>
<property name="y" type="int" value="2"/>
</properties>
</object>
</objectgroup>
</map>

17
assets/maps/testmap2.tmx Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="5" height="5" tilewidth="8" tileheight="8" infinite="0" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" source="../tilemaps/tilemap.tsx"/>
<tileset firstgid="67" source="../tilemaps/entities.tsx"/>
<layer id="1" name="Tile Layer 1" width="5" height="5">
<data encoding="csv">
2,2,2,2,2,
2,2,2,3,2,
2,2,3,3,2,
2,2,3,2,2,
2,3,3,2,2
</data>
</layer>
<objectgroup id="2" name="Entities">
<object id="4" name="Player" type="player" gid="68" x="6.54983" y="15.3437" width="8" height="8"/>
</objectgroup>
</map>

View File

@ -0,0 +1,14 @@
{
"automappingRulesFile": "",
"commands": [
],
"compatibilityVersion": 1100,
"extensionsPath": "extensions",
"folders": [
"."
],
"properties": [
],
"propertyTypes": [
]
}

View File

@ -0,0 +1,114 @@
{
"Map/SizeTest": {
"height": 4300,
"width": 2
},
"activeFile": "maps/testmap.tmx",
"expandedProjectPaths": [
".",
"maps"
],
"file.lastUsedOpenFilter": "All Files (*)",
"fileStates": {
"": {
"scaleInDock": 1
},
"entities.tsx": {
"scaleInDock": 1,
"scaleInEditor": 1
},
"maps/downtown.tmx": {
"scale": 4.9072,
"selectedLayer": 0,
"viewCenter": {
"x": 39.94131072709489,
"y": 40.0432018258885
}
},
"maps/testmap.tmx": {
"expandedObjectLayers": [
2
],
"scale": 3.404166666666667,
"selectedLayer": 1,
"viewCenter": {
"x": 95.17747858017135,
"y": 86.80538555691552
}
},
"maps/testmap2.tmx": {
"expandedObjectLayers": [
2
],
"scale": 5.0383,
"selectedLayer": 1,
"viewCenter": {
"x": 19.84796459123116,
"y": 19.947204414187325
}
},
"maps/train_station.tmx": {
"expandedObjectLayers": [
2
],
"scale": 2.7603,
"selectedLayer": 1,
"viewCenter": {
"x": 160.48980183313407,
"y": 120.4579212404449
}
},
"testmap.tmx": {
"scale": 3.23,
"selectedLayer": 1,
"viewCenter": {
"x": 122.60061919504646,
"y": 56.965944272445824
}
},
"testmap2.tmx": {
"scale": 3.281458333333333,
"selectedLayer": 0,
"viewCenter": {
"x": 119.91619579709226,
"y": 80.14729223541363
}
},
"tilemap.tsx": {
"scaleInDock": 1,
"scaleInEditor": 4
},
"tilemaps/entities.tsx": {
"scaleInDock": 2,
"scaleInEditor": 9.7785
},
"tilemaps/tilemap.tsx": {
"scaleInDock": 2
}
},
"last.externalTilesetPath": "/home/yourwishes/htdocs/Dawn/assets",
"last.imagePath": "/home/yourwishes/htdocs/Dawn/assets",
"map.height": 10,
"map.lastUsedFormat": "tmx",
"map.tileHeight": 8,
"map.tileWidth": 8,
"map.width": 10,
"openFiles": [
"maps/testmap.tmx"
],
"project": "tiled_project.tiled-project",
"property.type": "string",
"recentFiles": [
"maps/testmap.tmx",
"maps/downtown.tmx",
"maps/testmap2.tmx",
"maps/train_station.tmx",
"tilemaps/entities.tsx"
],
"tileset.lastUsedFilter": "All Files (*)",
"tileset.lastUsedFormat": "tsx",
"tileset.tileSize": {
"height": 8,
"width": 8
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="entities" tilewidth="8" tileheight="8" tilecount="64" columns="8">
<image source="entities.png" width="64" height="64"/>
<tile id="1" type="player"/>
<tile id="2" type="npc"/>
<tile id="3" type="sign"/>
<tile id="4" type="door"/>
</tileset>

BIN
assets/tilemaps/tilemap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="tilemap" tilewidth="8" tileheight="8" tilecount="64" columns="8">
<image source="tilemap.png" width="64" height="64"/>
</tileset>

View File

@ -1,3 +0,0 @@
FROM debian:latest
RUN apt update && apt upgrade -y && apt install -y git cmake build-essential libx11-dev libgtk-3-dev python3 python3-pip
RUN ln -s /usr/bin/python3 /usr/bin/python

View File

@ -1,18 +0,0 @@
services:
dawn-linux64:
build: .
volumes:
- ./../../:/Dawn
working_dir: /Dawn
command:
- /bin/sh
- -c
- |
ln -s /usr/bin/python3 /usr/bin/python
if [ ! -d ./lib/glfw ]; then
git submodule update --init
fi
mkdir -p ./build/linux-x64
cd ./build/linux-x64
cmake ../.. -DDAWN_BUILD_SYSTEM=linux -DGLFW_BUILD_X11=ON -DGLFW_BUILD_WAYLAND=OFF
make

View File

@ -1,3 +0,0 @@
FROM pspdev/pspdev
RUN apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python
RUN psp-pacman -Sy pspgl glm

View File

@ -1,14 +0,0 @@
services:
dawn-psp:
build: .
volumes:
- ./../../:/Dawn
working_dir: /Dawn
command:
- /bin/bash
- -c
- |
mkdir -p ./build/psp
cd ./build/psp
psp-cmake ../.. -DDAWN_BUILD_SYSTEM=psp -DCMAKE_BUILD_TYPE=Debug
make

View File

@ -1,15 +0,0 @@
services:
dawn-vita:
image: gnuton/vitasdk-docker
volumes:
- ./../../:/Dawn
working_dir: /Dawn
command:
- /bin/bash
- -c
- |
rm -rf ./build/vita
mkdir -p ./build/vita
cd ./build/vita
cmake ../.. -DDAWN_BUILD_SYSTEM=vita -DCMAKE_BUILD_TYPE=Debug
make

View File

@ -1,340 +0,0 @@
# Compiling, Debugging and Running
This document's purpose is to explain how to compile, debug and run the project
on your machine. It is assumed that you have a basic understanding of the
fundamentals of your operating system and how to use a terminal.
## Preamble
The Dawn project is written almost entirely in C and C++. This includes all of
the tooling used to generate the project and assets. The only non-C/C++ code is
used by CMake to generate the output compilation files. This provides the Dawn
project an extremely high level of portability not typically seen in other
projects.
## TLDR; Version
This document is going to go over the installation and configuration of the
following items. If you are already familiar with these tools, you can skip to
the "Downloading the Source Code" section.
- C/C++ Compiler
- CMake
- Git
- IDE
You may also need *python*, since we depend on third-party libraries that may use
python scripts to generate their own build files. This is not required for the
Dawn project itself.
## Pre-Configuration
In order to compile the Dawn project, you are required to have the following
tools installed on your machine.
### 1. A C/C++ Compiler
The exact tool(s) will depend on your specific scenario. The compiler is used to
take the .cpp/.hpp files and generating binaries that execute on the target
machine. Typically you will use your own C/C++ compiler for the machine that you
are currently running, e.g. if you are running Windows, you will use the Visual
Studio compiler. If you are running Linux, you will use GCC or Clang. If you are
running macOS, you will use Clang, and so-on.
If you are intending to compile on a different machine than the one you are
currently running, you will need to use a cross-compiler that is specific for
your use-case. You will also need to refer to the documentation for creating a
new Dawn engine target.
Please follow the instructions for your specific operating system to install the
appropriate C/C++ compiler.
**Windows**
You will need to download and install [Visual Studio](https://visualstudio.microsoft.com/downloads/).
Visual Studio (not to be confused with Visual Studio Code) is a full IDE that
bundles the official Microsoft C/C++ compiler. It is the recommended compiler
for building the Dawn project on Windows.
Advanced used can also use [MinGW](http://www.mingw.org/) or another compiler if
they wish, however this is not officially supported.
After installing Visual Studio, you will need to install the C++ development
tools. This can be done by opening the Visual Studio Installer and selecting
the "Desktop development with C++" workload.
**Linux**
You will need to install the GCC and Clang compilers. The compilers are usually
installed either by default or by installing the necessary packages for your
Linux distribution.
For example, on Ubuntu, you can install the GCC and Clang compilers by running
the following command:
```bash
sudo apt install build-essential clang
```
On Arch Linux, you can install the GCC and Clang compilers by running the
following command:
```bash
sudo pacman -S base-devel clang
```
And on Fedora, you can install the GCC and Clang compilers by running the
following command:
```bash
sudo dnf install @development-tools clang
```
For other distributions, please refer to your distribution's documentation.
**macOS**
You will need to install the Xcode command line tools. This can be done by done
by running the following command in your terminal:
```bash
xcode-select --install
```
Afterwards you will need to install and enable [Brew](https://brew.sh/). This
can be done by running the following command in your terminal:
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
### 2. CMake
CMake is a tool that is used to generate the compilation files for the Dawn
project. In short this is used to create versions of the Dawn project that can
be compiled on all different sets of compilers, so if you are compiling on, for
example, Windows, you can use CMake to generate the compilation files for the
Visual Studio compiler, or if you are compiling on Linux, you can use CMake to
generate the compilation files for the GCC or Clang compilers, and so-on.
To install CMake, please follow the instructions for your specific operating
system. All other operating systems can be found on the [CMake downloads page](https://cmake.org/download/).
**Windows**
You will need to download and install [CMake](https://cmake.org/download/). The
installer will guide you through the installation process and will install the
CMake executable to your system. It is recommended that you add CMake to your
system PATH if requested by the installer.
**Linux**
Like installing the C/C++ compilers, you will need to install CMake using your
specific Linux distribution's package manager, there is also a chance that CMake
can be installed using flatpak or snap. Please refer to your distribution's
documentation for more information.
For Ubuntu and other Debian-based distributions, you can install CMake by using
the following command:
```bash
sudo apt install cmake
```
For Arch Linux, you can install CMake by using the following command:
```bash
sudo pacman -S cmake
```
And for Fedora, you can install CMake by using the following command:
```bash
sudo dnf install cmake
```
**macOS**
You will install CMake using brew. We detailed how to install brew in the C/C++
compiler section. To install CMake, run the following command in your terminal:
```bash
brew install cmake
```
### 3. Git
Git is a version control system that is used to manage the Dawn project's source
code. It is used to download the source code, and to update the source code to
the latest version. It is also used to manage the project's dependencies. Git is
a standard tool in the programming industry and is used to manage complex
projects, especially those that are worked on by multiple people.
Git, like all of the above tools, is installed slightly differently depending on
your operating system. Please follow the instructions for your specific
operating system.
**Windows**
You will need to download and install [Git](https://git-scm.com/downloads). The
installer will guide you through the installation process and will install the
Git executable to your system. It is recommended that you add Git to your system
PATH if requested by the installer. You do not need to add the Context-menu
items to your system.
**Linux**
Like installing the C/C++ compilers, you will need to install Git using your
specific Linux distribution's package manager. It is also likely that git would
have been installed by default. Please refer to your distribution's docs for
more information.
For Ubuntu and other Debian-based distributions, you can install Git by using
the following command:
```bash
sudo apt install git
```
For Arch Linux, you can install Git by using the following command:
```bash
sudo pacman -S git
```
And for Fedora, you can install Git by using the following command:
```bash
sudo dnf install git
```
**macOS**
You will install Git using brew. We detailed how to install brew in the C/C++
compiler section. To install Git, run the following command in your terminal:
```bash
brew install git
```
### 4. An IDE
An IDE (Integrated Development Environment) is a tool that is used to view and
edit code of projects. While it is not required to use an IDE, it is recommended
since it can make the process of editing and running the project much easier.
There are many different IDEs available, and often people chose an IDE that will
suit their preferences and needs, however if you are unsure of which IDE you
should be using, the Dawn project recommends using [Visual Studio Code](https://code.visualstudio.com/),
not to be confused with Visual Studio.
Visual Studio Code is a free and open-source IDE that is widely used in the
industry for its simple, modern and configurable interface. For example you can
configure VSCode to work on Web Projects, Game Projects, and more. It acts like
a text editor with a bunch of extra tools.
In addition to installing the VSCode IDE, we will add several recommended
plugins that will make editing the Dawn project easier and more seamless.
To install VSCode follow the instructions for your specific operating system on
the [VSCode downloads page](https://code.visualstudio.com/download), as it can
vary a lot between operating systems.
After installing VSCode, you will need to install the following plugins, by
clicking on the "Extensions" icon on the left-hand side of the VSCode window,
and searching for the following plugins. You may also be able to click on the
following links to install the plugins directly, but it may not work.
- [C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)
- [CMake](https://marketplace.visualstudio.com/items?itemName=twxs.cmake)
- [CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools)
## Downloading the Source Code
Now that you have all of the necessary tools installed, you can download the
source code of the project and using it to build. The source code contains all
of the code of the project, as well as the assets and the build scripts. This is
confidential information and should not be shared with anyone.
### 1. Cloning the Repository
We previously installed the git tool, which is used to download the source code
of the project, and some third-party libraries. To download the source code, you
will need to open a terminal and navigate to the directory where you want to
download the source code to.
Afterwards, you will need to run the following command:
```bash
git clone https://git.wish.moe/YourWishes/Dawn.git
```
This will download the source code of the project to a new subdirectory called
"Dawn" and put all of the projects' source code within there.
### 2. Installing the Dependencies / Libraries.
I try to keep dependencies on third-party libraries to a minimum, however there
are a few libraries that are required to build the Dawn project. These libraries
are not included in the source code, and must be downloaded separately. This is
done using the git tool.
After you have cloned the above repository, you will need to open a terminal and
navigate to the directory where you downloaded the source code to. Afterwards,
you will need to run the following command:
```bash
git submodule update --init --recursive
```
This will fetch all of the third-party libraries that are required to build the
Dawn project. This may take a while depending on your internet connection.
### 3. Loading the Project
This step is semi-optional. We are aiming to build the project using CMake, and
the easiest way to do this is to use the CMake Tools plugin for VSCode that we
installed earlier. This plugin will automatically detect the CMake files in the
project and will allow us to build the project using the VSCode interface.
If you opted out of using VSCode, you will need to set up your CMake environment
to suit your IDE or needs. This is outside of the scope of this document, and
you will need to refer to your IDE's documentation for more information.
To load the project, you will need to open VSCode and open the Dawn project
directory. Most operating systems will allow you to do this by dragging the
Dawn project directory onto the VSCode window. If this does not work, you can
open VSCode and click on the "File" menu, and click on "Open Folder". You will
then need to navigate to the Dawn project directory and click "Open".
Afterwards you will likely be prompted autometically to configure the CMake
Tools plugin. If you are not, you can click on the "CMake" icon on the left-hand
side of the VSCode window, and click on "Configure". This will configure the
CMake Tools plugin to use the CMake files in the Dawn project directory.
You may also be asked to select a compiler. If you are using Windows, you will
need to select the Visual Studio compiler. If you are using Linux, you will need
to select the GCC or Clang compiler. If you are using macOS, you will need to
select the Clang compiler. If you are using a different compiler, you will need
to select the appropriate compiler.
If prompted to select a build type, select "Debug".
## Compiling the Project
Now that we have the project loaded into our IDE, we can compile the project.
This is done using the CMake Tools plugin for VSCode. If you are not using
VSCode you will need to refer to your IDE's documentation for more information.
Firstly, you will need to create a settings file to configure the project. In
VSCode you can create a new folder called `.vscode` (Including the leading `.`)
in the Dawn project root directory. Afterwards, you will need to create a new
file called `settings.json` in the `.vscode` directory. You will then need to
paste the following into the file:
```json
{
"cmake.configureArgs": [
"-DDAWN_BUILD_TOOLS=true",
"-DDAWN_BUILD_TARGET=target-liminal-win32-glfw",
"-DDAWN_DEBUG_BUILD=true"
]
}
```
And save the file. You may want to alter the values to suit your needs. For
example, if you are compiling on Linux, you will need to change
`target-liminal-win32-glfw` to `target-liminal-linux-glfw`. If you are compiling
on macOS, you will need to change it to `target-liminal-osx-glfw`. The specific
configure arguments are outside of the scope of this document, and you will need
to refer to the specific target documentation for more information.
After you have created the settings file, you will need to configure and build
the project. To perform the build you need to click "Build" button the bottom of
the VSCode window. This will compile the project and will output the resulting
binaries in to a "build" directory within the Dawn project directory.
Upon clicking the "Build" button, you will see an output panel appear at the
bottom of the VSCode window. This will show the process of the build, and will
show any errors that may occur. This is used to debug and fix any issues that
may occur during the build process.
If the build was successful, you will see a "Build finished" message in the
output panel, typically read as;
```bash
[build] Build finished with exit code 0
```
If you do not see this message, or if the exit code is not 0, you will need to
debug the issue. The output panel will show the error message which is helpful
so we can debug the issue. If you are unable to debug the issue, you can ask for
help in the Discord server.
## Running the built project
After the build process succeeds you will be able to run the project. This is
done by clicking on the Run icon, which looks like a play button, on the bottom
of the VSCode window. This will run the project in production mode and will not
show any debug information.
If the program hangs, crashes or does not run, you can click the Debug icon,
which looks like a ladybug, on the bottom of the VSCode window. This will run
the project in debug mode and will show debug information and HALT the program
if there is an error detected. If program HALTS in debug mode you can use this
information to debug the issue. If you are unable to debug the issue, you can
ask for help in the Discord server.

234
gentileset.py Normal file
View File

@ -0,0 +1,234 @@
# font is a 2D array of 8x8 pixel characters where each bit is a pixel on the
# row.
font8x8_basic = [
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0000 (nul)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0001
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0002
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0003
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0004
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0005
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0006
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0007
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0008
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0009
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000A
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000B
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000C
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000D
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000E
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+000F
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0010
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0011
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0012
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0013
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0014
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0015
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0016
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0017
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0018
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0019
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001A
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001B
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001C
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001D
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001E
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+001F
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0020 (space)
[0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00], # U+0021 (!)
[0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0022 (")
[0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00], # U+0023 (#)
[0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00], # U+0024 ($)
[0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00], # U+0025 (%)
[0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00], # U+0026 (&)
[0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0027 (')
[0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00], # U+0028 (()
[0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00], # U+0029 ())
[0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00], # U+002A (*)
[0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00], # U+002B (+)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06], # U+002C (,)
[0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00], # U+002D (-)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00], # U+002E (.)
[0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00], # U+002F (/)
[0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00], # U+0030 (0)
[0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00], # U+0031 (1)
[0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00], # U+0032 (2)
[0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00], # U+0033 (3)
[0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00], # U+0034 (4)
[0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00], # U+0035 (5)
[0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00], # U+0036 (6)
[0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00], # U+0037 (7)
[0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00], # U+0038 (8)
[0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00], # U+0039 (9)
[0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00], # U+003A (:)
[0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06], # U+003B (;)
[0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00], # U+003C (<)
[0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00], # U+003D (=)
[0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00], # U+003E (>)
[0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00], # U+003F (?)
[0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00], # U+0040 (@)
[0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00], # U+0041 (A)
[0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00], # U+0042 (B)
[0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00], # U+0043 (C)
[0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00], # U+0044 (D)
[0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00], # U+0045 (E)
[0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00], # U+0046 (F)
[0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00], # U+0047 (G)
[0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00], # U+0048 (H)
[0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], # U+0049 (I)
[0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00], # U+004A (J)
[0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00], # U+004B (K)
[0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00], # U+004C (L)
[0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00], # U+004D (M)
[0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00], # U+004E (N)
[0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00], # U+004F (O)
[0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00], # U+0050 (P)
[0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00], # U+0051 (Q)
[0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00], # U+0052 (R)
[0x1E, 0x33, 0x07, 0x1E, 0x38, 0x33, 0x1E, 0x00], # U+0053 (S)
[0x3F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x00], # U+0054 (T)
[0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00], # U+0055 (U)
[0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00], # U+0056 (V)
[0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00], # U+0057 (W)
[0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00], # U+0058 (X)
[0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x0C, 0x00], # U+0059 (Y)
[0x3F, 0x33, 0x19, 0x0C, 0x26, 0x33, 0x3F, 0x00], # U+005A (Z)
[0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], # U+005B ([)
[0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00], # U+005C (\)
[0x1E, 0x30, 0x30, 0x30, 0x30, 0x30, 0x1E, 0x00], # U+005D (])
[0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00], # U+005E (^)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF], # U+005F (_)
[0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00], # U+0060 (`)
[0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00], # U+0061 (a)
[0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00], # U+0062 (b)
[0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00], # U+0063 (c)
[0x38, 0x30, 0x30, 0x3E, 0x33, 0x33, 0x6E, 0x00], # U+0064 (d)
[0x00, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00], # U+0065 (e)
[0x1C, 0x36, 0x06, 0x0F, 0x06, 0x06, 0x0F, 0x00], # U+0066 (f)
[0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1E], # U+0067 (g)
[0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00], # U+0068 (h)
[0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], # U+0069 (i)
[0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E], # U+006A (j)
[0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00], # U+006B (k)
[0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], # U+006C (l)
[0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00], # U+006D (m)
[0x00, 0x00, 0x1B, 0x37, 0x33, 0x33, 0x33, 0x00], # U+006E (n)
[0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00], # U+006F (o)
[0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F], # U+0070 (p)
[0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78], # U+0071 (q)
[0x00, 0x00, 0x1B, 0x36, 0x36, 0x06, 0x0F, 0x00], # U+0072 (r)
[0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00], # U+0073 (s)
[0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00], # U+0074 (t)
[0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00], # U+0075 (u)
[0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00], # U+0076 (v)
[0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00], # U+0077 (w)
[0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00], # U+0078 (x)
[0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1E], # U+0079 (y)
[0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00], # U+007A (z)
[0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00], # U+007B ({)
[0x0C, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0x00], # U+007C (|)
[0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00], # U+007D (})
[0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # U+007E (~)
]
# COLOR4F(0.0f, 0.0f, 0.0f, 1.0f), # Black
# COLOR4F(1.0f, 1.0f, 1.0f, 1.0f), # White
# COLOR4F(0.8f, 0.0f, 0.0f, 1.0f), # Red
# COLOR4F(0.0f, 0.5f, 0.0f, 1.0f), # Green
# COLOR4F(0.0f, 0.0f, 0.8f, 1.0f), # Blue
# COLOR4F(0.8f, 0.8f, 0.0f, 1.0f), # Yellow
# COLOR4F(0.8f, 0.0f, 0.8f, 1.0f), # Magenta
# COLOR4F(0.0f, 0.8f, 0.8f, 1.0f), # Cyan
# COLOR4F(0.5f, 0.5f, 0.5f, 1.0f), # Gray
# COLOR4F(0.5f, 0.25f, 0.0f, 1.0f) # Brown
# Tilemap
COLORS = {
"BLACK": [ 0, 0, 0 ],
"WHITE": [ 255, 255, 255 ],
"RED": [ 204, 0, 0 ],
"GREEN": [ 0, 128, 0 ],
"BLUE": [ 0, 0, 204 ],
"YELLOW": [ 204, 204, 0 ],
"MAGENTA": [ 204, 0, 204 ],
"CYAN": [ 0, 204, 204 ],
"GRAY": [ 128, 128, 128 ],
"BROWN": [ 128, 64, 0 ]
}
TILES = {
# NAME: [ id, symbol, color ]
"NULL": [ 0, 'N', COLORS["RED"] ],
"GRASS": [ 1, '#', COLORS["GREEN"] ],
"WATER": [ 2, '\\', COLORS["BLUE"] ],
# "DOOR": [ 3, 'D', COLORS["BROWN"] ],
"BUILDING_WALL": [ 4, '-', COLORS["GRAY"] ],
"ROOF": [ 5, '/', COLORS["BROWN"] ],
"WALKABLE_NULL": [ 6, ' ', COLORS["BLACK"] ],
"COBBLESTONE": [ 7, '#', COLORS["GRAY"] ],
"STAIRS": [ 8, '=', COLORS["GRAY"] ],
"RAILING": [ 9, 'n', COLORS["BROWN"] ],
"COLUMN": [ 10, 'I', COLORS["WHITE"] ],
"RAIL_TRACK": [ 11, '|', COLORS["GRAY"] ],
"RAIL_SLEEPER": [ 12, '-', COLORS["BROWN"] ],
"CARPET": [ 13, '#', COLORS["RED"] ],
"LAMP": [ 14, 'i', COLORS["YELLOW"] ],
}
ENTITIES = {
"NULL": [ 0, 'N', COLORS["RED"] ],
"PLAYER": [ 1, 'v', COLORS["RED"] ],
"NPC": [ 2, 'V', COLORS["RED"] ],
"SIGN": [ 3, '+', COLORS["YELLOW"] ],
"DOOR": [ 4, 'D', COLORS["BROWN"] ],
}
# Create 64 x 64 RGB pixel buffer.
import png
WIDTH = 64
HEIGHT = 64
def genTileset(filename, tileset, background):
# Create 64x64 pixel buffer with black
PIXEL_BUFFER = []
for y in range(HEIGHT):
row = []
for x in range(WIDTH):
row.append(background)
PIXEL_BUFFER.append(row)
# For each TILES
for tile in tileset:
# Get the tile data
tile_data = tileset[tile]
tile_id = tile_data[0]
tile_char = tile_data[1]
tile_color = tile_data[2]
# Get char pixels
char_pixels = font8x8_basic[ord(tile_char)]
tile_color_rgba = [ tile_color[0], tile_color[1], tile_color[2], 255 ]
# Write char pixels to output buffer, using tile_id to determine pixels with
# each row holding 8 characters of 8 pixels
for y in range(8):
row = char_pixels[y]
for x in range(8):
if row & (1 << x):
PIXEL_BUFFER[(tile_id // 8) * 8 + y][(tile_id % 8) * 8 + x] = tile_color_rgba
# Convert from [ [ [ r, g, b ], [ r, g, b] ], [ [ r, g, b ], [ r, g, b ] ] ] to
# [ [R, G, B, A, R, G, B, A] ] (Flatten level 2 and add alpha channel)
FLATTENED_PIXEL_BUFFER = [ [ 0 for i in range(WIDTH * 4) ] for j in range(HEIGHT) ]
for y in range(HEIGHT):
for x in range(WIDTH):
FLATTENED_PIXEL_BUFFER[y][x * 4 + 0] = PIXEL_BUFFER[y][x][0]
FLATTENED_PIXEL_BUFFER[y][x * 4 + 1] = PIXEL_BUFFER[y][x][1]
FLATTENED_PIXEL_BUFFER[y][x * 4 + 2] = PIXEL_BUFFER[y][x][2]
FLATTENED_PIXEL_BUFFER[y][x * 4 + 3] = PIXEL_BUFFER[y][x][3]
# Now write PIXEL_BUFFER to png
png.from_array(FLATTENED_PIXEL_BUFFER, 'RGBA').save(filename)
genTileset("./assets/tilemaps/tilemap.png", TILES, [ 0, 0, 0, 255 ])
genTileset("./assets/tilemaps/entities.png", ENTITIES, [ 0, 0, 0, 100 ])

Submodule lib/AudioFile deleted from 004065d01e

View File

@ -1,31 +1,31 @@
# Copyright (c) 2021 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# GLFW/GLAD
if(DAWN_BUILD_SYSTEM STREQUAL "linux")
add_subdirectory(glad)
add_subdirectory(glfw)
add_subdirectory(libarchive)
add_subdirectory(glm)
set(LIBTYPE "STATIC")
add_subdirectory(openal-soft)
set(BUILD_TESTS OFF CACHE BOOL "Build tests" FORCE)
set(BUILD_EXAMPLES OFF CACHE BOOL "Build examples" FORCE)
add_subdirectory(AudioFile)
add_subdirectory(freetype)
add_subdirectory(boxer)
target_compile_definitions(Boxer PRIVATE UNICODE)
elseif(DAWN_BUILD_SYSTEM STREQUAL "vita")
add_subdirectory(glm)
elseif(DAWN_BUILD_SYSTEM STREQUAL "psp")
add_subdirectory(glm)
endif()
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
include(FetchContent)
add_library(font8x8 INTERFACE)
target_include_directories(font8x8 INTERFACE font8x8)
add_subdirectory(glad)
# GLFW
FetchContent_Declare(glfw URL https://github.com/glfw/glfw/releases/download/3.4/glfw-3.4.zip)
FetchContent_MakeAvailable(glfw)
# GLM
FetchContent_Declare(
cglm
GIT_REPOSITORY https://github.com/recp/cglm
GIT_TAG 1796cc5ce298235b615dc7a4750b8c3ba56a05dd
)
FetchContent_MakeAvailable(cglm)
#LibArchive
FetchContent_Declare(
libarchive
GIT_REPOSITORY https://github.com/libarchive/libarchive
GIT_TAG v3.7.6
)
FetchContent_MakeAvailable(libarchive)

Submodule lib/SDL deleted from fb1497566c

Submodule lib/boxer deleted from 65e79c38f1

1
lib/font8x8 Submodule

Submodule lib/font8x8 added at 8e279d2d86

Submodule lib/freetype deleted from 7ff43d3e9f

Submodule lib/glfw deleted from b35641f4a3

Submodule lib/glm deleted from 45008b225e

Submodule lib/libarchive deleted from 313aa1fa10

Submodule lib/openal-soft deleted from d3875f333f

View File

@ -1,24 +1,22 @@
# Copyright (c) 2022 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
if(DAWN_BUILD_SYSTEM STREQUAL "linux")
add_subdirectory(dawn)
add_subdirectory(dawnglfw)
add_subdirectory(dawnlinux)
add_subdirectory(dawnopengl)
elseif(DAWN_BUILD_SYSTEM STREQUAL "vita")
add_subdirectory(dawn)
add_subdirectory(dawnvita)
add_subdirectory(dawnopengl)
elseif(DAWN_BUILD_SYSTEM STREQUAL "psp")
set(DAWN_OPENGL_SHADERS FALSE CACHE INTERNAL "${DAWN_CACHE_TARGET}")
set(DAWN_OPENGL_FRAMEBUFFERS FALSE CACHE INTERNAL "${DAWN_CACHE_TARGET}")
set(DAWN_OPENGL_MIPMAPS FALSE CACHE INTERNAL "${DAWN_CACHE_TARGET}")
add_subdirectory(dawn)
add_subdirectory(dawnpsp)
else()
message(FATAL_ERROR "Unknown build system: ${DAWN_BUILD_SYSTEM}")
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Build Project
add_executable(${DAWN_TARGET_NAME})
# Add base
add_subdirectory(dawn)
# Compile entries
if(DAWN_TARGET STREQUAL "linux-x64-terminal")
add_subdirectory(dawnlinux)
add_subdirectory(dawntermlinux)
elseif(DAWN_TARGET STREQUAL "linux-x64-glfw")
add_subdirectory(dawnlinux)
add_subdirectory(dawnglfw)
add_subdirectory(dawnopengl)
else()
message(FATAL_ERROR "Unknown target: ${DAWN_TARGET}")
endif()

View File

@ -6,6 +6,7 @@
# Libraries
target_link_libraries(${DAWN_TARGET_NAME}
PUBLIC
archive_static
)
# Includes
@ -14,22 +15,25 @@ target_include_directories(${DAWN_TARGET_NAME}
${CMAKE_CURRENT_LIST_DIR}
)
# Subdirs
add_subdirectory(assert)
add_subdirectory(asset)
add_subdirectory(display)
add_subdirectory(game)
add_subdirectory(rpg)
add_subdirectory(ui)
add_subdirectory(locale)
add_subdirectory(util)
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
input.c
)
# Subdirs
add_subdirectory(error)
add_subdirectory(game)
add_subdirectory(locale)
add_subdirectory(scene)
add_subdirectory(util)
# Assets
tool_map(testmap maps/testmap.tmx)
tool_map(testmap2 maps/testmap2.tmx)
tool_copy(en en.json)
# Textures
# tool_texture(texture_test
# FILE=${DAWN_ASSETS_DIR}/texture_test.png
# FILTER_MIN=NEAREST
# FILTER_MAG=NEAREST
# )
add_dependencies(${DAWN_TARGET_NAME} dawnassets)

View File

@ -1,10 +1,12 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
error.cpp
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Subdirs
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
assert.c
)

37
src/dawn/assert/assert.c Normal file
View File

@ -0,0 +1,37 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assert.h"
#include <stdarg.h>
void assertTrueImplement(
const char *file,
const int32_t line,
const char *func,
const bool_t result,
const char *message,
...
) {
if(result) return;
// Print file info.
fprintf(
stderr,
"Assert failed in %s:%i :: %s\n",
file,
line,
func
);
// Print message.
va_list args;
va_start(args, message);
vfprintf(stderr, message, args);
va_end(args);
fprintf(stderr, "\n");
abort();
}

View File

@ -6,7 +6,7 @@
*/
#pragma once
#include "dawn.hpp"
#include "dawn.h"
/**
* Asserts that a given statement must evaluate to true or the assertion fails
@ -63,7 +63,7 @@ void assertTrueImplement(
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertNotNull(x, ...) assertTrue(x != nullptr, __VA_ARGS__)
#define assertNotNull(x, ...) assertTrue(x != NULL, __VA_ARGS__)
/**
* Asserts that a given pointer is null.
@ -71,18 +71,7 @@ void assertTrueImplement(
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertNull(x, ...) assertTrue(x == nullptr, __VA_ARGS__)
/**
* Asserts that a given map has a specific key.
* @param map Map to check.
* @param key Key to check for.
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertMapHasKey(map, key, ...) assertTrue( \
map.find(key) != map.end(), __VA_ARGS__ \
)
#define assertNull(x, ...) assertTrue(x == NULL, __VA_ARGS__)
/**
* Asserts that a given value has a specific flag turned off.
@ -108,6 +97,19 @@ void assertTrueImplement(
(value & flag) == flag, __VA_ARGS__ \
)
/**
* Asserts that the given string is not null, and has a length that is less
* the maximum buffer size, including the NULL terminator.
*
* @param str String to check.
* @param bufferSize Maximum buffer size.
* @param message Message (sprintf format) to send to the logger.
* @param args Optional TParam args for the sprintf message to accept.
*/
#define assertStringValid(str, bufferSize, ...) assertTrue( \
((str != NULL) && ((strlen(str)+1) < bufferSize)), __VA_ARGS__ \
)
/**
* Asserts that the current code is deprecated and should not be used anymore.
* @deprecated

View File

@ -0,0 +1,14 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https:#opensource.org/licenses/MIT
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
asset.c
assetarchive.c
assetjson.c
assetmap.c
assetlanguage.c
)

159
src/dawn/asset/asset.c Normal file
View File

@ -0,0 +1,159 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset.h"
#include "assetarchive.h"
#include "assert/assert.h"
#include "util/math.h"
void assetInit() {
// TODO: Works on Windows? path sep probs wrong.
// const char_t *assetFilename = "dawn.tar";
// char_t *assetPath = malloc(sizeof(char_t) * (
// strlen(SYSTEM.executableDirectory) + strlen(assetFilename) + 1
// ));
// sprintf(assetPath, "%s/%s", SYSTEM.executableDirectory, assetFilename);
char_t *assetPath = "/home/yourwishes/htdocs/Dawn/build/dawn.tar";
ASSET_FILE = fopen(assetPath, "rb");
// free(assetPath);
assertNotNull(ASSET_FILE, "assetInit: Failed to open asset file!");
ASSET_ARCHIVE = NULL;
ASSET_ENTRY = NULL;
}
size_t assetReadUntil(uint8_t *buffer, const char_t c, const size_t maxLength) {
if(buffer == NULL) {
assertTrue(
maxLength == -1, "If no buffer is provided, maxLength must be -1."
);
uint8_t tBuffer[1];
size_t read = 0;
while(assetRead(tBuffer, 1) == 1 && (char_t)tBuffer[0] != c) read++;
return read;
} else {
size_t read = 0;
while(read < maxLength) {
// TODO: Read more than 1 char at a time.
read += assetRead(buffer + read, 1);
if((char_t)buffer[read-1] == c) return read - 1;
}
return -1;
}
}
void assetOpen(const char_t *path) {
assertNull(ASSET_ARCHIVE, "assetOpenFile: Archive is not NULL!");
assertNull(ASSET_ENTRY, "assetOpenFile: Entry is not NULL!");
assertStringValid(path, 1024, "assetOpenFile: Path is not valid!");
// Store path
strcpy(ASSET_PATH_CURRENT, path);
// Prepare data
ASSET_ARCHIVE = archive_read_new();
assertNotNull(ASSET_ARCHIVE, "assetOpenFile: Failed to create archive!");
// Set up the reader
// archive_read_support_filter_bzip2(ASSET_ARCHIVE);
archive_read_support_format_tar(ASSET_ARCHIVE);
// Open reader
archive_read_set_open_callback(ASSET_ARCHIVE, &assetArchiveOpen);
archive_read_set_read_callback(ASSET_ARCHIVE, &assetArchiveRead);
archive_read_set_seek_callback(ASSET_ARCHIVE, &assetArchiveSeek);
archive_read_set_close_callback(ASSET_ARCHIVE, &assetArchiveOpen);
archive_read_set_callback_data(ASSET_ARCHIVE, ASSET_ARCHIVE_BUFFER);
int32_t ret = archive_read_open1(ASSET_ARCHIVE);
assertTrue(ret == ARCHIVE_OK, "assetOpenFile: Failed to open archive!");
// Iterate over each file.
while(archive_read_next_header(ASSET_ARCHIVE, &ASSET_ENTRY) == ARCHIVE_OK) {
const char_t *headerFile = (char_t*)archive_entry_pathname(ASSET_ENTRY);
if(strcmp(headerFile, ASSET_PATH_CURRENT) == 0) return;
int32_t ret = archive_read_data_skip(ASSET_ARCHIVE);
assertTrue(ret == ARCHIVE_OK, "assetOpenFile: Failed to skip data!");
}
assertUnreachable("assetOpenFile: Failed to find file!");
}
size_t assetGetSize() {
assertNotNull(ASSET_ARCHIVE, "assetGetSize: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetGetSize: Entry is NULL!");
assertTrue(
archive_entry_size_is_set(ASSET_ENTRY),
"assetGetSize: Entry size is not set!"
);
size_t n = archive_entry_size(ASSET_ENTRY);
// Remnant when get size was doing some incorrect stuff.
// char_t path[2048];
// sprintf(
// path, "/home/yourwishes/htdocs/dusk/build/assets/%s", ASSET_PATH_CURRENT
// );
// FILE *temp = fopen(path, "rb");
// assertNotNull(temp, "assetGetSize: Failed to open temp file!");
// fseek(temp, 0, SEEK_END);
// size_t size = ftell(temp);
// assertTrue(size == n, "assetGetSize: Size is not equal!");
// fclose(temp);
return n;
}
size_t assetRead(uint8_t *buffer, size_t bufferSize) {
assertNotNull(ASSET_ARCHIVE, "assetRead: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetRead: Entry is NULL!");
assertNotNull(buffer, "assetRead: Buffer is NULL!");
assertTrue(bufferSize > 0, "assetRead: Buffer size must be greater than 0!");
ssize_t read = archive_read_data(ASSET_ARCHIVE, buffer, bufferSize);
if(read == ARCHIVE_FATAL) {
assertUnreachable(archive_error_string(ASSET_ARCHIVE));
}
assertTrue(read != ARCHIVE_RETRY, "assetRead: Failed to read data (RETRY)!");
assertTrue(read != ARCHIVE_WARN, "assetRead: Failed to read data (WARN)!");
return read;
}
void assetSkip(const size_t length) {
assertNotNull(ASSET_ARCHIVE, "assetSkip: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetSkip: Entry is NULL!");
assertTrue(length > 0, "assetSkip: Length must be greater than 0!");
// Asset archive does not support skipping, so we have to read and discard.
uint8_t buffer[1024];
size_t remaining = length;
do {
size_t toRead = mathMin(remaining, 1024);
size_t read = assetRead(buffer, toRead);
assertTrue(read == toRead, "assetSkip: Failed to skip data! (overskip?)");
remaining -= read;
} while(remaining > 0);
}
void assetClose() {
assertNotNull(ASSET_ARCHIVE, "assetClose: Archive is NULL!");
assertNotNull(ASSET_ENTRY, "assetClose: Entry is NULL!");
int32_t ret = archive_read_free(ASSET_ARCHIVE);
assertTrue(ret == ARCHIVE_OK, "assetClose: Failed to close archive!");
ASSET_ARCHIVE = NULL;
ASSET_ENTRY = NULL;
}
void assetDispose() {
assertNull(ASSET_ARCHIVE, "assetDestroy: Archive is not NULL!");
assertNull(ASSET_ENTRY, "assetDestroy: Entry is not NULL!");
int32_t result = fclose(ASSET_FILE);
assertTrue(result == 0, "assetDestroy: Failed to close asset file!");
}

73
src/dawn/asset/asset.h Normal file
View File

@ -0,0 +1,73 @@
/**
* Copyright (c) 2023 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
/**
* Initializes the asset manager.
*/
void assetInit();
/**
* Opens an asset by its filename (within the asset archive). Asset paths should
* always use the unix forward slash '/' as a path separator.
*
* @param path The path to the asset within the archive.
*/
void assetOpen(const char_t *path);
/**
* Returns the size of the asset.
*
* @return The size of the asset.
*/
size_t assetGetSize();
/**
* Reads the asset into the buffer.
*
* @param buffer The buffer to read the asset into.
* @param bufferSize The size of the buffer.
* @return The amount of data read.
*/
size_t assetRead(uint8_t *buffer, size_t bufferSize);
/**
* Reads ahead in the buffer until either the end of the buffer, or the
* specified character is found. Return value will be -1 if the character was
* not found.
*
* Buffer can be NULL if you just want to skip ahead.
*
* Returned value will be either the amount of data read into the buffer, which
* excludes the extra 1 character that was read from the asset. If the character
* was not found, -1 will be returned.
*
* @param buffer Buffer to read into.
* @param c Character to read until.
* @param maxLength Maximum length to read.
* @return -1 if the character was not found, otherwise the amount of data read.
*/
size_t assetReadUntil(uint8_t *buffer, const char_t c, const size_t maxLength);
/**
* Skips ahead in the buffer by the specified length.
*
* @param length The length to skip ahead by.
*/
void assetSkip(const size_t length);
/**
* Closes the asset.
*/
void assetClose();
/**
* Destroys and cleans up the asset manager.
*/
void assetDispose();

View File

@ -0,0 +1,55 @@
/**
* Copyright (c) 2023 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset/assetarchive.h"
#include "assert/assert.h"
#include "util/math.h"
FILE *ASSET_FILE;
struct archive *ASSET_ARCHIVE;
struct archive_entry *ASSET_ENTRY;
uint8_t ASSET_ARCHIVE_BUFFER[ASSET_BUFFER_SIZE];
char_t ASSET_PATH_CURRENT[ASSET_PATH_MAX];
ssize_t assetArchiveRead(
struct archive *archive,
void *data,
const void **buffer
) {
assertNotNull(archive, "assetArchiveRead: Archive is NULL!");
assertNotNull(data, "assetArchiveRead: Data is NULL!");
assertNotNull(buffer, "assetArchiveRead: Buffer is NULL!");
*buffer = data;
size_t read = fread(data, 1, ASSET_BUFFER_SIZE, ASSET_FILE);
if(ferror(ASSET_FILE)) return ARCHIVE_FATAL;
return read;
}
int64_t assetArchiveSeek(
struct archive *archive,
void *data,
int64_t offset,
int32_t whence
) {
assertNotNull(archive, "assetArchiveSeek: Archive is NULL!");
assertNotNull(data, "assetArchiveSeek: Data is NULL!");
assertTrue(offset > 0, "assetArchiveSeek: Offset must be greater than 0!");
int32_t ret = fseek(ASSET_FILE, offset, whence);
assertTrue(ret == 0, "assetArchiveSeek: Failed to seek!");
return ftell(ASSET_FILE);
}
int32_t assetArchiveOpen(struct archive *a, void *data) {
int32_t ret = fseek(ASSET_FILE, 0, SEEK_SET);
assertTrue(ret == 0, "assetArchiveOpen: Failed to seek to start of file!");
return ARCHIVE_OK;
}
int32_t assetArchiveClose(struct archive *a, void *data) {
return assetArchiveOpen(a, data);
}

View File

@ -0,0 +1,68 @@
/**
* Copyright (c) 2023 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "asset/asset.h"
#include <archive.h>
#include <archive_entry.h>
#define ASSET_BUFFER_SIZE 32768
#define ASSET_PATH_MAX 1024
extern FILE *ASSET_FILE;
extern struct archive *ASSET_ARCHIVE;
extern struct archive_entry *ASSET_ENTRY;
extern uint8_t ASSET_ARCHIVE_BUFFER[ASSET_BUFFER_SIZE];
extern char_t ASSET_PATH_CURRENT[ASSET_PATH_MAX];
/**
* Internal read method provided to libarchive api.
*
* @param archive The archive to read from.
* @param data The data to read into.
* @param buffer The buffer to read from.
* @return The amount of data read.
*/
ssize_t assetArchiveRead(
struct archive *archive,
void *data,
const void **buffer
);
/**
* Internal seek method provided to libarchive api.
*
* @param archive The archive to seek in.
* @param data The data to seek in.
* @param offset Offset bytes to seek.
* @param whence Relative to whence to seek.
* @return The new position.
*/
int64_t assetArchiveSeek(
struct archive *archive,
void *data,
int64_t offset,
int32_t whence
);
/**
* Internal open method provided to libarchive api.
*
* @param archive The archive to open.
* @param data The data to open.
* @return The result of the open.
*/
int32_t assetArchiveOpen(struct archive *a, void *data);
/**
* Internal close method provided to libarchive api.
*
* @param archive The archive to close.
* @param data The data to close.
* @return The result of the close.
*/
int32_t assetArchiveClose(struct archive *a, void *data);

560
src/dawn/asset/assetjson.c Normal file
View File

@ -0,0 +1,560 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assetjson.h"
#include "assert/assert.h"
#include "util/memory.h"
size_t assetJsonParse(const char_t *json, assetjson_t **out) {
size_t offset = assetJsonParseSub(json, out);
// We only expect whitespace or EOF here
char_t c;
size_t len = strlen(json);
while(offset <= len) {
c = json[offset];
if(c == '\0') break;
if(c == ' ' || c == '\t' || c == '\n' || c == '\r') {
offset++;
continue;
}
assertUnreachable("Unexpected character found after JSON data.");
}
assertTrue(c == '\0', "Unexpected character found after JSON data.");
assertTrue(offset == len, "Unexpected character found after JSON data.");
return offset;
}
size_t assetJsonParseSub(
const char_t *json,
assetjson_t **out
) {
size_t offset = 0;
char_t c;
// Skip whitespace
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// Read first character
c = json[offset];
switch(c) {
case '{':
offset += assetJsonParseAsObject(json + offset, out);
break;
case '[':
offset += assetJsonParseAsArray(json + offset, out);
break;
case '"':
offset += assetJsonParseAsString(json + offset, out);
break;
case '-':
case '0' ... '9':
case '.':
offset += assetJsonParseAsNumber(json + offset, out);
break;
case 't':
case 'f':
offset += assetJsonParseAsBoolean(json + offset, out);
break;
case 'n':
offset += assetJsonParseAsNull(json + offset, out);
break;
default:
assertUnreachable("Invalid JSON data type found.");
break;
}
return offset;
}
size_t assetJsonParseAsNull(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = (assetjson_t*)memoryAllocate(sizeof(assetjson_t));
// Read "null"
assertTrue(json[0] == 'n', "Expected NULL data type. (n0)");
assertTrue(json[1] == 'u', "Expected NULL data type. (u0)");
assertTrue(json[2] == 'l', "Expected NULL data type. (l0)");
assertTrue(json[3] == 'l', "Expected NULL data type. (l1)");
obj->type = ASSET_JSON_DATA_TYPE_NULL;
*out = obj;
return 4;
}
size_t assetJsonParseAsBoolean(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = (assetjson_t*)memoryAllocate(sizeof(assetjson_t));
obj->type = ASSET_JSON_DATA_TYPE_BOOLEAN;
*out = obj;
if(json[0] == 't') {
// Read "true"
assertTrue(json[0] == 't', "Expected TRUE data type. (t0)");
assertTrue(json[1] == 'r', "Expected TRUE data type. (r0)");
assertTrue(json[2] == 'u', "Expected TRUE data type. (u0)");
assertTrue(json[3] == 'e', "Expected TRUE data type. (e0)");
obj->boolean = true;
return 4;
} else {
// Read "false"
assertTrue(json[0] == 'f', "Expected FALSE data type. (f0)");
assertTrue(json[1] == 'a', "Expected FALSE data type. (a0)");
assertTrue(json[2] == 'l', "Expected FALSE data type. (l0)");
assertTrue(json[3] == 's', "Expected FALSE data type. (s0)");
assertTrue(json[4] == 'e', "Expected FALSE data type. (e0)");
obj->boolean = false;
return 5;
}
}
size_t assetJsonParseAsString(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = memoryAllocate(sizeof(assetjson_t));
obj->type = ASSET_JSON_DATA_TYPE_STRING;
// For each char
size_t offset = 1;// Skip opening quote
size_t outOffset = 0;
char c;
bool_t inEscape = false;
size_t bufferSize = 2;
char_t *string = (char_t*)memoryAllocate(bufferSize * sizeof(char_t));
while(true) {
c = json[offset];
if(c == '\0') assertUnreachable("Unexpected end of string.");
if(inEscape) {
inEscape = false;
switch(c) {
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
case 'u':
assertUnreachable("Unicode escape sequences are not supported.");
break;
default:
break;
}
if(outOffset >= bufferSize) {
bufferSize *= 2;
string = memoryReallocate(string, bufferSize * sizeof(char_t));
}
string[outOffset] = c;
offset++;
outOffset++;
continue;
}
if(c == '\\') {
inEscape = true;
offset++;
continue;
}
if(c == '"') break;
if(outOffset >= bufferSize) {
bufferSize *= 2;
string = memoryReallocate(string, bufferSize * sizeof(char_t));
}
string[outOffset] = c;
offset++;
outOffset++;
}
string[outOffset] = '\0';
outOffset++;
*out = obj;
obj->string = string;
return offset + 1;// For closing string quote
}
size_t assetJsonParseAsObject(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = memoryAllocate(sizeof(assetjson_t));
obj->type = ASSET_JSON_DATA_TYPE_OBJECT;
size_t bufferSize = 2;
char_t **keys = memoryAllocate(bufferSize * sizeof(char_t*));
assetjson_t **values = memoryAllocate(bufferSize * sizeof(assetjson_t*));
size_t length = 0;
// Skip whitespace
size_t offset = 1;// Skip opening bracket
char_t c;
while(true) {
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// Only expect opening string or closing brace
if(c == '}') break;
assertTrue(c == '"', "Expected opening string for JSON object key.");
char_t *bufferKey;
// Skip "
offset++;
offset += assetJsonReadString(json + offset, &bufferKey);
// Skip whitespace
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// Only expect colon
assertTrue(c == ':', "Expected colon after JSON object key.");
offset++;
// Skip whitespace
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// Parse sub
assetjson_t *value;
offset += assetJsonParseSub(json + offset, &value);
// Need to resize?
if(length >= bufferSize) {
bufferSize *= 2;
keys = memoryReallocate(keys, bufferSize * sizeof(char_t*));
values = memoryReallocate(values, bufferSize * sizeof(assetjson_t*));
}
keys[length] = bufferKey;
values[length] = value;
length++;
// Skip whitespace
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// Expect either comma or closing bracket
assertTrue(
c == ',' || c == '}',
"Expected comma or closing bracket after JSON object value."
);
if(c == '}') break;
offset++;
}
obj->object.keys = keys;
obj->object.values = values;
obj->object.length = length;
*out = obj;
return offset + 1;// Skip closing bracket
}
size_t assetJsonParseAsArray(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = (assetjson_t*)memoryAllocate(sizeof(assetjson_t));
obj->type = ASSET_JSON_DATA_TYPE_ARRAY;
size_t offset = 1;// Skip opening bracket
char_t c;
// Create array
size_t arraySize = 2;
obj->array.value = (assetjson_t**)memoryAllocate(
arraySize * sizeof(assetjson_t*)
);
obj->array.length = 0;
// Until closing bracket
while(true) {
c = json[offset];
if(c == '\0') assertUnreachable("Unexpected end of JSON array.");
if(c == ']') break;
// Skip whitespace ONLY
if(c == ' ' || c == '\t' || c == '\n' || c == '\r') {
offset++;
continue;
}
// Need to expand?
if(obj->array.length >= arraySize) {
arraySize *= 2;
obj->array.value = memoryReallocate(
obj->array.value, arraySize * sizeof(assetjson_t*)
);
}
// Parse sub
offset += assetJsonParseSub(
json + offset,
&obj->array.value[obj->array.length++]
);
// Skip whitespace ONLY
while((c = json[offset]) == ' ' || c == '\t' || c == '\n' || c == '\r') {
if(c == '\0') assertUnreachable("Unexpected end of JSON data.");
offset++;
}
// If comma, continue
if(c == ',') {
offset++;
continue;
}
// If closing bracket, break
if(c == ']') break;
// Else, error
assertUnreachable("Unexpected character found in JSON array.");
}
// End of array
*out = obj;
return offset + 1;// Skip closing bracket
}
size_t assetJsonParseAsNumber(
const char_t *json,
assetjson_t **out
) {
assetjson_t *obj = (assetjson_t*)memoryAllocate(sizeof(assetjson_t));
obj->type = ASSET_JSON_DATA_TYPE_NUMBER;
// For each char
size_t offset = 0;
size_t outOffset = 0;
char_t c;
size_t bufferSize = 2;
char_t *buffer = (char_t*)memoryAllocate(bufferSize * sizeof(char_t));
bool_t hasDecimal = false;
bool_t hasNumber = false;
// Read number
while(true) {
c = json[offset];
if(c == '\0') assertUnreachable("Unexpected end of number.");
if(c == '-') {
// only accepted on first input
assertTrue(outOffset == 0, "Unexpected - after first digit");
} else if(c == '.') {
// only accepted once
assertTrue(!hasDecimal, "Unexpected . after first decimal");
hasDecimal = true;
if(!hasNumber) {
// If no number before decimal, add a 0
if(outOffset >= bufferSize) {
bufferSize *= 2;
buffer = memoryReallocate(buffer, bufferSize * sizeof(char_t));
}
buffer[outOffset] = '0';
outOffset++;
}
} else if(c >= '0' && c <= '9') {
hasNumber = true;
} else {
break;
}
// Need to expand?
if(outOffset >= bufferSize) {
bufferSize *= 2;
buffer = memoryReallocate(buffer, bufferSize * sizeof(char_t));
}
buffer[outOffset] = c;
offset++;
outOffset++;
}
// Seal the buffer, parse and cleanup
buffer[outOffset] = '\0';
obj->number = strtod(buffer, NULL);
memoryFree(buffer);
*out = obj;
return offset;
}
size_t assetJsonReadString(
const char_t *json,
char_t **buffer
) {
size_t offset = 0;
size_t outOffset = 0;
char_t c;
size_t bufferSize = 32;
char_t *string = (char_t*)memoryAllocate(sizeof(char_t) * bufferSize);
bool_t inEscape = false;
// For each char
while(true) {
c = json[offset];
if(c == '\0') assertUnreachable("Unexpected end of string.");
if(inEscape) {
inEscape = false;
switch(c) {
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
case 'u':
assertUnreachable("Unicode escape sequences are not supported.");
break;
default:
break;
}
if(outOffset >= bufferSize) {
bufferSize *= 2;
string = memoryReallocate(string, bufferSize);
}
string[outOffset] = c;
offset++;
outOffset++;
continue;
}
if(c == '\\') {
inEscape = true;
offset++;
continue;
}
if(c == '"') break;
if(outOffset >= bufferSize) {
bufferSize *= 2;
string = memoryReallocate(string, bufferSize);
}
string[outOffset] = c;
offset++;
outOffset++;
}
string[outOffset] = '\0';
outOffset++;
*buffer = string;
return offset + 1;
}
assetjson_t * assetJsonGetObjectValue(assetjson_t *json, const char_t *key) {
assertTrue(json->type == ASSET_JSON_DATA_TYPE_OBJECT, "Expected JSON object.");
for(size_t i = 0; i < json->object.length; i++) {
if(strcmp(json->object.keys[i], key) == 0) {
return json->object.values[i];
}
}
return NULL;
}
void assetJsonDispose(assetjson_t *json) {
switch(json->type) {
case ASSET_JSON_DATA_TYPE_OBJECT:
for(size_t i = 0; i < json->object.length; i++) {
memoryFree(json->object.keys[i]);
assetJsonDispose(json->object.values[i]);
}
memoryFree(json->object.keys);
memoryFree(json->object.values);
break;
case ASSET_JSON_DATA_TYPE_ARRAY:
for(size_t i = 0; i < json->array.length; i++) {
assetJsonDispose(json->array.value[i]);
}
memoryFree(json->array.value);
break;
case ASSET_JSON_DATA_TYPE_STRING:
memoryFree(json->string);
break;
case ASSET_JSON_DATA_TYPE_NUMBER:
break;
case ASSET_JSON_DATA_TYPE_BOOLEAN:
break;
case ASSET_JSON_DATA_TYPE_NULL:
break;
}
memoryFree(json);
}

140
src/dawn/asset/assetjson.h Normal file
View File

@ -0,0 +1,140 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
typedef enum {
ASSET_JSON_DATA_TYPE_OBJECT,
ASSET_JSON_DATA_TYPE_ARRAY,
ASSET_JSON_DATA_TYPE_STRING,
ASSET_JSON_DATA_TYPE_NUMBER,
ASSET_JSON_DATA_TYPE_BOOLEAN,
ASSET_JSON_DATA_TYPE_NULL
} assetjsondatatype_t;
typedef struct _assetjson_t assetjson_t;
typedef struct _assetjson_t {
assetjsondatatype_t type;
union {
struct {
char_t **keys;
assetjson_t **values;
size_t length;
} object;
struct {
assetjson_t **value;
size_t length;
} array;
double_t number;
char_t *string;
bool_t boolean;
};
} assetjson_t;
/**
* Parses a JSON string.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParse(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a sub-object.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseSub(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a NULL value.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsNull(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a boolean value.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsBoolean(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as an object.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsObject(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as an array.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsArray(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a string.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsString(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a number.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonParseAsNumber(const char_t *json, assetjson_t **out);
/**
* Parses a JSON string as a string.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
size_t assetJsonReadString(const char_t *json, char_t **out);
/**
* Parses a JSON string as a number.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
assetjson_t *assetJsonGetObjectValue(assetjson_t *object, const char_t *key);
/**
* Parses a JSON string as a number.
*
* @param json JSON string to parse.
* @param out Pointer to store the parsed JSON object.
* @return The number of characters parsed.
*/
void assetJsonDispose(assetjson_t *json);

View File

@ -0,0 +1,70 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assetlanguage.h"
#include "asset/asset.h"
#include "assert/assert.h"
#include "locale/language.h"
#include "util/memory.h"
void assetLanguageObjectLoad(
const char_t *key,
assetjson_t *json
) {
char_t tKey[LANGUAGE_STRING_KEY_LENGTH_MAX];
size_t keyLength = strlen(key);
strcpy(tKey, key);
if(keyLength > 0) {
tKey[keyLength] = '.';
keyLength++;
}
for(int32_t i = 0; i < json->object.length; i++) {
const char_t *subKey = json->object.keys[i];
assetjson_t *value = json->object.values[i];
strcpy(tKey + keyLength, subKey);
if(json->object.values[i]->type == ASSET_JSON_DATA_TYPE_OBJECT) {
assetLanguageObjectLoad(tKey, value);
continue;
}
if(json->object.values[i]->type == ASSET_JSON_DATA_TYPE_STRING) {
strcpy(LANGUAGE.keys[LANGUAGE.count], tKey);
strcpy(LANGUAGE.strings[LANGUAGE.count], value->string);
LANGUAGE.count++;
continue;
}
assertUnreachable("Language value is not a string or object!");
}
}
void assetLanguageLoad(const char_t *path) {
assertNotNull(path, "Path cannot be NULL.");
assetOpen(path);
size_t length = assetGetSize();
char_t *buffer = memoryAllocate(sizeof(char_t) * (length + 1));
buffer[length] = '\0';
size_t read = assetRead((uint8_t*)buffer, length);
assertTrue(read == length, "Failed to read language file!");
assetClose();
assetjson_t *json;
read = assetJsonParse(buffer, &json);
memoryFree(buffer);
assertTrue(
json->type == ASSET_JSON_DATA_TYPE_OBJECT,
"Language file is not an object!"
);
languageInit();
assetLanguageObjectLoad("", json);
assetJsonDispose(json);
}

View File

@ -0,0 +1,27 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "asset/assetjson.h"
/**
* Loads a JSON object from the asset file.
*
* @param key The key to load.
* @param json The value to load into.
*/
void assetLanguageObjectLoad(
const char_t *key,
assetjson_t *json
);
/**
* Loads the language file from the specified path.
*
* @param path Path to the language file.
*/
void assetLanguageLoad(const char_t *path);

236
src/dawn/asset/assetmap.c Normal file
View File

@ -0,0 +1,236 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assetmap.h"
#include "asset/asset.h"
#include "assert/assert.h"
#include "util/memory.h"
void assetMapLoadEntity(
assetjson_t *jEnt,
map_t *map
) {
int32_t x = (int32_t)assetJsonGetObjectValue(jEnt, "x")->number;
int32_t y = (int32_t)assetJsonGetObjectValue(jEnt, "y")->number;
entitytype_t type = (entitytype_t)assetJsonGetObjectValue(
jEnt, "type"
)->number;
entity_t *ent = mapEntityAdd(map);
entityInit(ent, type, map);
entityPositionSet(ent, x, y);
assetjson_t *val;
switch(type) {
case ENTITY_TYPE_NPC:
val = assetJsonGetObjectValue(jEnt, "name");
if(val != NULL) {
assertTrue(
val->type == ASSET_JSON_DATA_TYPE_STRING,
"assetMapLoad: NPC name is not a string!"
);
npcNameSet(&ent->npc, val->string);
}
val = assetJsonGetObjectValue(jEnt, "text");
if(val != NULL) {
assertTrue(
val->type == ASSET_JSON_DATA_TYPE_STRING,
"assetMapLoad: NPC text is not a string!"
);
npcTextSet(&ent->npc, val->string);
}
break;
case ENTITY_TYPE_SIGN:
val = assetJsonGetObjectValue(jEnt, "text");
if(val != NULL) {
assertTrue(
val->type == ASSET_JSON_DATA_TYPE_STRING,
"assetMapLoad: Sign text is not a string!"
);
signTextAppend(&ent->sign, val->string);
}
val = assetJsonGetObjectValue(jEnt, "texts");
if(val != NULL) {
assertTrue(
val->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Sign texts is not an array!"
);
assertTrue(
val->array.length <= SIGN_TEXT_COUNT_MAX,
"assetMapLoad: Too many sign texts!"
);
for(int32_t i = 0; i < val->array.length; i++) {
assetjson_t *subVal = val->array.value[i];
assertTrue(
subVal->type == ASSET_JSON_DATA_TYPE_STRING,
"assetMapLoad: Sign text is not a string!"
);
signTextAppend(&ent->sign, subVal->string);
}
}
break;
case ENTITY_TYPE_DOOR:
val = assetJsonGetObjectValue(jEnt, "door");
if(val != NULL) {
assetjson_t *door = assetJsonGetObjectValue(val, "x");
x = (int32_t)door->number;
assertTrue(
door->type == ASSET_JSON_DATA_TYPE_NUMBER,
"assetMapLoad: Door x is not a number!"
);
door = assetJsonGetObjectValue(val, "y");
y = (int32_t)door->number;
assertTrue(
door->type == ASSET_JSON_DATA_TYPE_NUMBER,
"assetMapLoad: Door y is not a number!"
);
door = assetJsonGetObjectValue(val, "direction");
entitydirection_t direction = ENTITY_DIRECTION_SOUTH;
if(door != NULL) {
direction = (entitydirection_t)(
assetJsonGetObjectValue(val, "direction")->number
);
}
door = assetJsonGetObjectValue(val, "map");
maplist_t list;
if(door == NULL) {
list = map->list;
} else if(door->type == ASSET_JSON_DATA_TYPE_STRING) {
list = mapListGet(door->string);
} else if(door->type == ASSET_JSON_DATA_TYPE_NUMBER) {
list = (maplist_t)door->number;
} else {
assertUnreachable("assetMapLoad: Door map not string or number!");
}
doorDestinationSet(&ent->door, x, y, direction, list);
}
break;
default:
break;
}
}
void assetMapLoad(
const char_t *path,
map_t *map
) {
assertNotNull(map, "assetMapLoad: Map is NULL!");
// Read in the string data.
assetOpen(path);
size_t length = assetGetSize();
char_t *buffer = memoryAllocate(sizeof(char_t) * (length + 1));
size_t read = assetRead((uint8_t*)buffer, length);
buffer[length] = '\0';
assertTrue(read == length, "assetMapLoad: Failed to read map data!");
assetClose();
// Begin parsing JSON data.
assetjson_t *json;
read = assetJsonParse(buffer, &json);
memoryFree(buffer);
assertTrue(
json->type == ASSET_JSON_DATA_TYPE_OBJECT,
"assetMapLoad: Map data is not an object!"
);
int32_t width = (int32_t)assetJsonGetObjectValue(json, "width")->number;
int32_t height = (int32_t)assetJsonGetObjectValue(json, "height")->number;
assetjson_t *layers = assetJsonGetObjectValue(json, "layers");
assertTrue(
layers->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Layers is not an array!"
);
int32_t layerCount = layers->array.length;
assertTrue(layerCount == MAP_LAYERS_MAX, "assetMapLoad: No layers found!");
mapInit(map, mapListGet(path), width, height, layerCount);
// Load tile data.
for(int32_t i = 0; i < layerCount; i++) {
assetjson_t *layer = layers->array.value[i];
assertTrue(
layer->type == ASSET_JSON_DATA_TYPE_OBJECT,
"assetMapLoad: Layer is not an object!"
);
assetjson_t *tiles = assetJsonGetObjectValue(layer, "tiles");
assertTrue(
tiles->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Tiles is not an array!"
);
assertTrue(
tiles->array.length == width * height,
"assetMapLoad: Tile count does not match map size!"
);
for(int32_t j = 0; j < width * height; j++) {
map->tiles[j] = (tile_t)tiles->array.value[j]->number;
}
}
// Load entity data
assetjson_t *entities = assetJsonGetObjectValue(json, "entities");
if(entities != NULL) {
assertTrue(
entities->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Entities is not an array!"
);
for(int32_t i = 0; i < entities->array.length; i++) {
assetjson_t *jEnt = entities->array.value[i];
assertTrue(
jEnt->type == ASSET_JSON_DATA_TYPE_OBJECT,
"assetMapLoad: Entity is not an object!"
);
assetMapLoadEntity(jEnt, map);
}
}
// Load trigger data
assetjson_t *triggers = assetJsonGetObjectValue(json, "triggers");
if(triggers != NULL) {
assertTrue(
triggers->type == ASSET_JSON_DATA_TYPE_ARRAY,
"assetMapLoad: Triggers is not an array!"
);
for(int32_t i = 0; i < triggers->array.length; i++) {
assetjson_t *jTrig = triggers->array.value[i];
assertTrue(
jTrig->type == ASSET_JSON_DATA_TYPE_OBJECT,
"assetMapLoad: Trigger is not an object!"
);
int32_t x = (int32_t)assetJsonGetObjectValue(jTrig, "x")->number;
int32_t y = (int32_t)assetJsonGetObjectValue(jTrig, "y")->number;
int32_t width = (int32_t)assetJsonGetObjectValue(jTrig, "width")->number;
int32_t height = (int32_t)assetJsonGetObjectValue(
jTrig, "height"
)->number;
triggertype_t type = (triggertype_t)assetJsonGetObjectValue(
jTrig, "type"
)->number;
trigger_t *trigger = mapTriggerAdd(map);
triggerInit(trigger, type, x, y, width, height);
}
}
assetJsonDispose(json);
}

32
src/dawn/asset/assetmap.h Normal file
View File

@ -0,0 +1,32 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "rpg/world/map.h"
#include "asset/assetjson.h"
/**
* Loads an entity from the specified JSON object.
*
* @param jEnt JSON object to load the entity from.
* @param map Map to load the entity into.
*/
void assetMapLoadEntity(
assetjson_t *jEnt,
map_t *map
);
/**
* Loads a map from the specified path.
*
* @param path Path to the map file.
* @param map Map to load the data into.
*/
void assetMapLoad(
const char_t *path,
map_t *map
);

22
src/dawn/dawn.h Normal file
View File

@ -0,0 +1,22 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <float.h>
#include <errno.h>
typedef bool bool_t;
typedef char char_t;
typedef unsigned char uchar_t;
typedef uint_fast32_t flag_t;

View File

@ -1,37 +0,0 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#define DAWN_GAME_NAME "Dawn"
#define DAWN_GAME_NAME_U8 u8"Dawn"
#include <vector>
#include <iostream>
#include <thread>
#include <map>
#include <array>
#include <memory>
#include <algorithm>
#include <sstream>
#include <string>
#include <functional>
#include <cstdarg>
#include <cstdint>
#include <cstring>
#include <float.h>
// #define GLM_ENABLE_EXPERIMENTAL
// #include <glm/glm.hpp>
// #include <glm/gtc/type_ptr.hpp>
// #include <glm/gtx/matrix_decompose.hpp>
typedef char char_t;
typedef char8_t u8char_t;
typedef float float_t;
typedef double double_t;
typedef bool bool_t;

View File

@ -1,11 +1,15 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
assertgl.cpp
erroropengl.cpp
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Subdirs
add_subdirectory(draw)
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
color.c
frame.c
symbol.c
)

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "animationitem.h"
#define ANIMATION_ITEM_COUNT_MAX 64
typedef struct _animation_t {
float_t time;
bool_t loop;
float_t duration;
animationitem_t items[ANIMATION_ITEM_COUNT_MAX];
uint8_t itemCount;
} animation_t;
/**
* Initializes an animation.
* @param anim The animation to initialize.
*/
void animationInit(animation_t *anim);
/**
* Updates an animation.
* @param anim The animation to update.
* @param delta The time since the last update.
*/
void animationUpdate(animation_t *anim, const float_t delta);
/**
* Returns the total duration of the animation.
*
* @param anim The animation to get the duration of.
* @return The total duration of the animation.
*/
float_t animationDurationGet(const animation_t *anim);

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
typedef struct _animation_t animation_t;
typedef struct _animationitem_t {
float_t time;
float_t duration;
void *user;
void (*start)(animation_t *anim, animationitem_t *item);
void (*update)(animation_t *anim,animationitem_t *item,const float_t rDelta);
} animationitem_t;

26
src/dawn/display/color.c Normal file
View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2023 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "color.h"
#include "assert/assert.h"
const color4f_t COLOR4F_COLOR_MAP[COLOR_COUNT] = {
COLOR4F_BLACK,
COLOR4F_WHITE,
COLOR4F(0.8f, 0.0f, 0.0f, 1.0f),
COLOR4F(0.0f, 0.5f, 0.0f, 1.0f),
COLOR4F(0.0f, 0.0f, 0.8f, 1.0f),
COLOR4F(0.8f, 0.8f, 0.0f, 1.0f),
COLOR4F(0.8f, 0.0f, 0.8f, 1.0f),
COLOR4F(0.0f, 0.8f, 0.8f, 1.0f),
COLOR4F(0.5f, 0.5f, 0.5f, 1.0f),
COLOR4F(0.5f, 0.25f, 0.0f, 1.0f)
};
void color4fCopy(const color4f_t src, color4f_t dest) {
memcpy(dest, src, sizeof(color4f_t));
}

81
src/dawn/display/color.h Normal file
View File

@ -0,0 +1,81 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
typedef float_t color3f_t[3];
typedef float_t color4f_t[4];
// Simple colors, used by the frame system.
#define COLOR_BLACK 0x00
#define COLOR_WHITE 0x01
#define COLOR_RED 0x02
#define COLOR_GREEN 0x03
#define COLOR_BLUE 0x04
#define COLOR_YELLOW 0x05
#define COLOR_MAGENTA 0x06
#define COLOR_CYAN 0x07
#define COLOR_GRAY 0x08
#define COLOR_BROWN 0x09
#define COLOR_COUNT COLOR_BROWN+1
#define COLOR3F(r,g,b) ((color3f_t){ r, g, b })
#define COLOR3F_RED COLOR3F(1, 0, 0)
#define COLOR3F_GREEN COLOR3F(0, 1, 0)
#define COLOR3F_BLUE COLOR3F(0, 0, 1)
#define COLOR3F_BLACK COLOR3F(0, 0, 0)
#define COLOR3F_WHITE COLOR3F(1, 1, 1)
#define COLOR3F_MAGENTA COLOR3F(1, 0, 1)
#define COLOR3F_YELLOW COLOR3F(1, 1, 0)
#define COLOR3F_CYAN COLOR3F(0, 1, 1)
#define COLOR3F_GRAY COLOR3F(0.5f, 0.5f, 0.5f)
#define COLOR3F_DARKGRAY COLOR3F(0.25f, 0.25f, 0.25f)
#define COLOR3F_LIGHTGRAY COLOR3F(0.75f, 0.75f, 0.75f)
#define COLOR3F_ORANGE COLOR3F(1, 0.5f, 0)
#define COLOR3F_PURPLE COLOR3F(0.5f, 0, 1)
#define COLOR3F_PINK COLOR3F(1, 0, 0.5f)
#define COLOR3F_BROWN COLOR3F(0.5f, 0.25f, 0)
#define COLOR3F_GOLD COLOR3F(1, 0.75f, 0)
#define COLOR3F_SILVER COLOR3F(0.75f, 0.75f, 0.75f)
#define COLOR3F_BRONZE COLOR3F(0.75f, 0.5f, 0.25f)
#define COLOR3F_CORNFLOWERBLUE COLOR3F(0.4f, 0.6f, 0.9f)
#define COLOR4F(r,g,b,a) ((color4f_t){ r, g, b, a })
#define COLOR4F_RED COLOR4F(1, 0, 0, 1)
#define COLOR4F_GREEN COLOR4F(0, 1, 0, 1)
#define COLOR4F_BLUE COLOR4F(0, 0, 1, 1)
#define COLOR4F_BLACK COLOR4F(0, 0, 0, 1)
#define COLOR4F_WHITE COLOR4F(1, 1, 1, 1)
#define COLOR4F_MAGENTA COLOR4F(1, 0, 1, 1)
#define COLOR4F_YELLOW COLOR4F(1, 1, 0, 1)
#define COLOR4F_CYAN COLOR4F(0, 1, 1, 1)
#define COLOR4F_GRAY COLOR4F(0.5f, 0.5f, 0.5f, 1)
#define COLOR4F_DARKGRAY COLOR4F(0.25f, 0.25f, 0.25f, 1)
#define COLOR4F_LIGHTGRAY COLOR4F(0.75f, 0.75f, 0.75f, 1)
#define COLOR4F_ORANGE COLOR4F(1, 0.5f, 0, 1)
#define COLOR4F_PURPLE COLOR4F(0.5f, 0, 1, 1)
#define COLOR4F_PINK COLOR4F(1, 0, 0.5f, 1)
#define COLOR4F_BROWN COLOR4F(0.5f, 0.25f, 0, 1)
#define COLOR4F_GOLD COLOR4F(1, 0.75f, 0, 1)
#define COLOR4F_SILVER COLOR4F(0.75f, 0.75f, 0.75f, 1)
#define COLOR4F_BRONZE COLOR4F(0.75f, 0.5f, 0.25f, 1)
#define COLOR4F_CORNFLOWERBLUE COLOR4F(0.4f, 0.6f, 0.9f, 1)
#define COLOR4F_TRANSPARENT_BLACK COLOR4F(0, 0, 0, 0)
#define COLOR4F_TRANSPARENT_WHITE COLOR4F(1, 1, 1, 0)
#define COLOR4F_TRANSPARENT COLOR4F_TRANSPARENT_BLACK
extern const color4f_t COLOR4F_COLOR_MAP[COLOR_COUNT];
/**
* Copies a color.
*
* @param src Source color.
* @param dest Destination color.
*/
void color4fCopy(const color4f_t src, color4f_t dest);

View File

@ -0,0 +1,25 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
/**
* Initializes the display subsystem.
*/
void displayInit();
/**
* Updates the display subsystem, this is basically asking the display renderer
* to perform a render.
*/
void displayUpdate();
/**
* Cleans up the display subsystem.
*/
void displayDispose();

View File

@ -0,0 +1,18 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Subdirs
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
drawbattle.c
drawstatemainmenu.c
drawstateoverworld.c
drawmap.c
drawtext.c
drawshape.c
drawui.c
)

View File

@ -0,0 +1,17 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "drawbattle.h"
#include "display/draw/drawshape.h"
#include "display/draw/drawui.h"
void drawBattle() {
drawClear(' ', COLOR_WHITE);
// Draw UI
drawUITextbox();
}

View File

@ -0,0 +1,13 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
/**
* Draws the battle state.
*/
void drawBattle();

View File

@ -0,0 +1,91 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "drawmap.h"
#include "assert/assert.h"
#include "display/symbol.h"
void drawMap(
const map_t *map,
const uint16_t cameraX,
const uint16_t cameraY,
const uint16_t drawX,
const uint16_t drawY,
const uint16_t drawWidth,
const uint16_t drawHeight
) {
assertNotNull(map, "Map cannot be NULL.");
assertTrue(drawX < FRAME_WIDTH, "Map is too far right.");
assertTrue(drawY < FRAME_HEIGHT, "Map is too far down.");
assertTrue(drawWidth > 0, "Map is too narrow.");
assertTrue(drawHeight > 0, "Map is too short.");
assertTrue(drawX + drawWidth <= FRAME_WIDTH, "Map is too wide.");
assertTrue(drawY + drawHeight <= FRAME_HEIGHT, "Map is too tall.");
entity_t *ent;
tile_t tile;
uint32_t i;
char_t *bufferDest;
uint8_t *colorDest;
// If the size of the map's smaller than the frame, center it, otherwise use
// the cameraPosition as the center point.
int16_t offsetX = 0, offsetY = 0;
if(map->width < drawWidth) {
offsetX = (drawWidth - map->width) / 2;
} else {
// Clamp to map bounds
if(cameraX < drawWidth / 2) {
offsetX = 0;
} else if(cameraX >= map->width - (drawWidth / 2)) {
offsetX = -(map->width - drawWidth);
} else {
offsetX = -(cameraX - (drawWidth / 2));
}
}
if(map->height < drawHeight) {
offsetY = (drawHeight - map->height) / 2;
} else {
// Clamp to map bounds
if(cameraY < drawHeight / 2) {
offsetY = 0;
} else if(cameraY >= map->height - (drawHeight / 2)) {
offsetY = -(map->height - drawHeight);
} else {
offsetY = -(cameraY - (drawHeight / 2));
}
}
// Draw the map
i = 0;
for(uint16_t y = 0; y < drawHeight; y++) {
bufferDest = &FRAME_BUFFER[(drawY + y) * FRAME_WIDTH + drawX];
colorDest = &FRAME_COLOR[(drawY + y) * FRAME_WIDTH + drawX];
for(uint16_t x = 0; x < drawWidth; x++) {
if(x < offsetX || y < offsetY || x >= map->width + offsetX || y >= map->height + offsetY) {
colorDest[x] = COLOR_BLACK;
bufferDest[x] = ' ';
continue;
}
// Entity?
ent = mapEntityGetByPosition(map, x - offsetX, y - offsetY);
if(ent != NULL) {
colorDest[x] = symbolGetColorByEntity(ent);
bufferDest[x] = symbolGetCharByEntity(ent);
continue;
}
// Tile?
tile = mapTileGetByPosition(map, x - offsetX, y - offsetY, 0);
colorDest[x] = tileColorGet(tile);
bufferDest[x] = tileSymbolGet(tile);
}
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/frame.h"
#include "rpg/world/map.h"
/**
* Draws a map to a region of the screen.
*
* @param map Map to draw.
* @param cameraX X position of the camera.
* @param cameraY Y position of the camera.
* @param drawX X position to draw the map.
* @param drawY Y position to draw the map.
* @param drawWidth Width of the map to draw.
* @param drawHeight Height of the map to draw.
*/
void drawMap(
const map_t *map,
const uint16_t cameraX,
const uint16_t cameraY,
const uint16_t drawX,
const uint16_t drawY,
const uint16_t drawWidth,
const uint16_t drawHeight
);

View File

@ -0,0 +1,44 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "drawshape.h"
#include "assert/assert.h"
#include "util/memory.h"
void drawClear(
const char_t c,
const uint8_t color
) {
memorySet(FRAME_BUFFER, c, FRAME_HEIGHT * FRAME_WIDTH);
memorySet(FRAME_COLOR, color, FRAME_HEIGHT * FRAME_WIDTH);
}
void drawBox(
const uint16_t x,
const uint16_t y,
const uint16_t width,
const uint16_t height,
const char_t c,
const uint8_t color
) {
assertTrue(x < FRAME_WIDTH, "Box is too far right.");
assertTrue(y < FRAME_HEIGHT, "Box is too far down.");
if(width == 0 || height == 0) return;
assertTrue(x + width <= FRAME_WIDTH, "Box is too wide.");
assertTrue(y + height <= FRAME_HEIGHT, "Box is too tall.");
if(width == FRAME_WIDTH) {
memorySet(&FRAME_BUFFER[y * FRAME_WIDTH + x], c, height * width);
memorySet(&FRAME_COLOR[y * FRAME_WIDTH + x], color, height * width);
return;
}
for(uint16_t iy = 0; iy < height; iy++) {
memorySet(&FRAME_BUFFER[(y + iy) * FRAME_WIDTH + x], c, width);
memorySet(&FRAME_COLOR[(y + iy) * FRAME_WIDTH + x], color, width);
}
}

View File

@ -0,0 +1,39 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/frame.h"
/**
* Clears the frame buffer with a character and color.
*
* @param c Character to clear the frame buffer with.
* @param color Color to clear the frame buffer with.
*/
void drawClear(
const char_t c,
const uint8_t color
);
/**
* Draws a box to the frame buffer.
*
* @param x The x position to draw the box.
* @param y The y position to draw the box.
* @param width The width of the box.
* @param height The height of the box.
* @param c The character to draw the box with.
* @param color The color to draw the box.
*/
void drawBox(
const uint16_t x,
const uint16_t y,
const uint16_t width,
const uint16_t height,
const char_t c,
const uint8_t color
);

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "drawstatemainmenu.h"
#include "display/draw/drawtext.h"
#include "display/draw/drawui.h"
#include "ui/mainmenu.h"
void drawStateMainMenu() {
// Draw the logo
drawText("Dawn", 4, 0, 0, COLOR_WHITE);
// Draw the menu
uint16_t width = menuGetLongestStringLength(&MAIN_MENU) + 3;
uint16_t height = MAIN_MENU.rows + 2;
drawUIMenuBox(
&MAIN_MENU,
(FRAME_WIDTH - width) / 2, FRAME_HEIGHT - height - 4,
width, height,
COLOR_WHITE, COLOR_WHITE, COLOR_WHITE
);
}

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/frame.h"
/**
* Draws the main menu state.
*/
void drawStateMainMenu();

View File

@ -0,0 +1,39 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "drawstateoverworld.h"
#include "ui/textbox.h"
#include "rpg/world/map.h"
#include "game/game.h"
#include "display/draw/drawmap.h"
#include "display/draw/drawui.h"
void drawStateOverworld() {
map_t *map = GAME.currentMap;
if(map == NULL) return;
// Draw the map, based on player position
entity_t *player = mapEntityGetByType(map, ENTITY_TYPE_PLAYER);
uint16_t cameraPositionX, cameraPositionY;
if(player == NULL) {
cameraPositionX = 0;
cameraPositionY = 0;
} else {
cameraPositionX = player->x;
cameraPositionY = player->y;
}
drawMap(
GAME.currentMap,
cameraPositionX, cameraPositionY,
0, 0,
FRAME_WIDTH, FRAME_HEIGHT
);
// Draw UI
drawUITextbox();
}

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/frame.h"
/**
* Draws the overworld state.
*/
void drawStateOverworld();

View File

@ -0,0 +1,44 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "drawtext.h"
#include "assert/assert.h"
#include "util/math.h"
void drawText(
const char_t *text,
const size_t len,
const uint16_t x,
const uint16_t y,
const uint8_t color
) {
if(len == 0) return;
size_t rLen = mathMin(len, strlen(text));
if(rLen == 0) return;
assertTrue(x < FRAME_WIDTH, "Text is too far right.");
assertTrue(y < FRAME_HEIGHT, "Text is too low.");
char_t c;
uint16_t xPos = x;
uint16_t yPos = y * FRAME_WIDTH;
size_t i = 0;
do {
c = text[i++];
if(c == '\n') {
yPos += FRAME_WIDTH;
xPos = x;
continue;
}
assertTrue(xPos < FRAME_WIDTH, "Text overflows right.");
FRAME_BUFFER[yPos + xPos] = c;
FRAME_COLOR[yPos + xPos] = color;
xPos++;
} while(i < rLen);
}

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/frame.h"
/**
* Draws some text to the frame buffer.
*
* @param text The text to draw.
* @param len The length of the text to draw.
* @param x The x position to draw the text.
* @param y The y position to draw the text.
* @param color The color to draw the text.
*/
void drawText(
const char_t *text,
const size_t len,
const uint16_t x,
const uint16_t y,
const uint8_t color
);

View File

@ -0,0 +1,229 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "drawui.h"
#include "drawshape.h"
#include "assert/assert.h"
#include "game/time.h"
#include "display/draw/drawtext.h"
#include "ui/textbox.h"
#include "ui/testmenu.h"
#include "util/math.h"
#include "util/memory.h"
void drawUIBox(
const uint16_t x,
const uint16_t y,
const uint16_t width,
const uint16_t height,
const uint8_t color,
const bool_t fill
) {
assertTrue(x < FRAME_WIDTH, "Box is too far right.");
assertTrue(y < FRAME_HEIGHT, "Box is too far down.");
assertTrue(width > 2, "Box is too narrow.");
assertTrue(height > 2, "Box is too short.");
assertTrue(x + width <= FRAME_WIDTH, "Box is too wide.");
assertTrue(y + height <= FRAME_HEIGHT, "Box is too tall.");
// Draw the top and bottom borders
for(uint16_t i = 0; i < width; i++) {
FRAME_BUFFER[y * FRAME_WIDTH + x + i] = '-';
FRAME_BUFFER[(y + height - 1) * FRAME_WIDTH + x + i] = '-';
FRAME_COLOR[y * FRAME_WIDTH + x + i] = color;
FRAME_COLOR[(y + height - 1) * FRAME_WIDTH + x + i] = color;
}
// Draw the left and right borders
for(uint16_t i = 0; i < height; i++) {
FRAME_BUFFER[(y + i) * FRAME_WIDTH + x] = '|';
FRAME_BUFFER[(y + i) * FRAME_WIDTH + x + width - 1] = '|';
FRAME_COLOR[(y + i) * FRAME_WIDTH + x] = color;
FRAME_COLOR[(y + i) * FRAME_WIDTH + x + width - 1] = color;
}
// Draw the corners
FRAME_BUFFER[y * FRAME_WIDTH + x] = '+';
FRAME_BUFFER[y * FRAME_WIDTH + x + width - 1] = '+';
FRAME_BUFFER[(y + height - 1) * FRAME_WIDTH + x] = '+';
FRAME_BUFFER[(y + height - 1) * FRAME_WIDTH + x + width - 1] = '+';
FRAME_COLOR[y * FRAME_WIDTH + x] = color;
FRAME_COLOR[y * FRAME_WIDTH + x + width - 1] = color;
FRAME_COLOR[(y + height - 1) * FRAME_WIDTH + x] = color;
FRAME_COLOR[(y + height - 1) * FRAME_WIDTH + x + width - 1] = color;
// Fill the inside
if(!fill) return;
drawBox(x + 1, y + 1, width - 2, height - 2, ' ', COLOR_BLACK);
}
void drawUIMenu(
menu_t *menu,
const uint16_t x,
const uint16_t y,
const uint16_t width,
const uint16_t height,
const uint8_t cursorColor,
const uint8_t textColor
) {
assertTrue(menu, "Menu cannot be NULL.");
assertTrue(menu->rows > 0, "Rows must be greater than 0.");
assertTrue(menu->columns > 0, "Columns must be greater than 0.");
assertTrue(width*2 > menu->columns, "Width must be greater than columns.");
uint16_t colWidth;
uint16_t startingCol;
uint16_t startingRow;
uint16_t rowCount;
uint16_t colCount;
char_t *str;
size_t i;
// Determine the width of each column. This must include space for the cursor
// and the text.
if(menu->columns == 1 || rowCount == 0) {
colWidth = width;
colCount = 1;
} else {
size_t longestString = 0;
i = 0;
while(true) {
str = menu->strings[i++];
if(str == NULL) break;
size_t len = strlen(str);
if(len > longestString) longestString = len;
// If we overrun the size of the box, we can stop looking.
if((len+1) > width) {
longestString = width;
break;
}
}
// How many columns can we fit?
uint16_t possibleColumnsAtThisWidth = width / (longestString + 1);
if(possibleColumnsAtThisWidth < menu->columns) {
// We need to take a subset of the columns
colWidth = width / possibleColumnsAtThisWidth;
colCount = possibleColumnsAtThisWidth;
} else {
// We can fit all columns in
colWidth = width / menu->columns;
colCount = menu->columns;
}
assertTrue(longestString != 0, "Longest string has length 0?");
}
// Determine count of rows to render
if(rowCount == 1) {
rowCount = 1;
} else {
rowCount = mathMin(rowCount, height);
}
// Where are we rendering from?
startingCol = menu->renderOffsetX;
if(menu->x >= startingCol + colCount) {
startingCol = (menu->x + 1) - colCount;
} else if(menu->x < startingCol) {
startingCol = menu->x;
}
startingRow = menu->renderOffsetY;
if(menu->y >= startingRow + rowCount) {
startingRow = (menu->y + 1) - rowCount;
} else if(menu->y < startingRow) {
startingRow = menu->y;
}
// Update back to the menu
menu->renderOffsetX = startingCol;
menu->renderOffsetY = startingRow;
for(uint16_t col = startingCol; col < startingCol+colCount; col++) {
for(uint16_t row = startingRow; row < startingRow+rowCount; row++) {
uint16_t index = (row * menu->columns) + col;
if(menu->strings[index] == NULL) continue;
drawText(
menu->strings[index],
colWidth,
x + (colWidth * (col - startingCol)) + 1,
y + (row - startingRow),
textColor
);
}
}
// Draw the cursor
i = (
x + ((menu->x - startingCol) * colWidth)
) + (
(y + (menu->y - startingRow)) * FRAME_WIDTH
);
FRAME_BUFFER[i] = '>';
FRAME_COLOR[i] = cursorColor;
}
void drawUIMenuBox(
menu_t *menu,
const uint16_t x,
const uint16_t y,
const uint16_t width,
const uint16_t height,
const uint8_t cursorColor,
const uint8_t textColor,
const uint8_t boxColor
) {
drawUIBox(x, y, width, height, boxColor, true);
drawUIMenu(
menu,
x + 1, y + 1,
width - 2, height - 2,
cursorColor, textColor
);
}
void drawUITextbox() {
if(!textboxIsOpen()) return;
// Border
drawUIBox(
0, FRAME_HEIGHT - DRAW_UI_TEXTBOX_HEIGHT,
DRAW_UI_TEXTBOX_WIDTH, DRAW_UI_TEXTBOX_HEIGHT,
COLOR_MAGENTA, true
);
// Title
drawText(
TEXTBOX.title,
-1,
2, FRAME_HEIGHT - DRAW_UI_TEXTBOX_HEIGHT,
COLOR_WHITE
);
// Text
drawText(
TEXTBOX.text,
TEXTBOX.textIndex,
1, FRAME_HEIGHT - DRAW_UI_TEXTBOX_HEIGHT + 1,
COLOR_WHITE
);
// Blinking cursor
memorySet(&FRAME_BUFFER[DRAW_UI_TEXTBOX_CURSOR_POS], ' ', 3);
memorySet(&FRAME_COLOR[DRAW_UI_TEXTBOX_CURSOR_POS], COLOR_WHITE, 3);
if(TEXTBOX.textIndex < TEXTBOX.textLength) return;
int32_t blink = (int32_t)(TIME.time * DRAW_UI_TEXTBOX_BLINKS_PER_SECOND) % 2;
FRAME_BUFFER[DRAW_UI_TEXTBOX_CURSOR_POS + 1] = blink ? '>' : ' ';
FRAME_BUFFER[DRAW_UI_TEXTBOX_CURSOR_POS + 2] = blink ? ' ' : '>';
}

View File

@ -0,0 +1,83 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/frame.h"
#include "ui/menu.h"
#define DRAW_UI_TEXTBOX_WIDTH FRAME_WIDTH
#define DRAW_UI_TEXTBOX_HEIGHT 8
#define DRAW_UI_TEXTBOX_CURSOR_POS ((FRAME_HEIGHT * FRAME_WIDTH) - 4)
#define DRAW_UI_TEXTBOX_BLINKS_PER_SECOND 2
/**
* Draws a UI box to the frame buffer.
*
* @param x The x position to draw the border.
* @param y The y position to draw the border.
* @param width The width of the border.
* @param height The height of the border.
* @param color The color to draw the border.
* @param fill Whether or not to fill the inside of the border.
*/
void drawUIBox(
const uint16_t x,
const uint16_t y,
const uint16_t width,
const uint16_t height,
const uint8_t color,
const bool_t fill
);
/**
* Draws a UI menu to the frame buffer.
*
* @param menu The menu to draw.
* @param x The x position to draw the menu.
* @param y The y position to draw the menu.
* @param width The width of the menu.
* @param height The height of the menu.
* @param cursorColor The color of the cursor.
* @param textColor The color of the text.
*/
void drawUIMenu(
menu_t *menu,
const uint16_t x,
const uint16_t y,
const uint16_t width,
const uint16_t height,
const uint8_t cursorColor,
const uint8_t textColor
);
/**
* Draws a UI menu box to the frame buffer.
*
* @param menu The menu to draw.
* @param x The x position to draw the menu.
* @param y The y position to draw the menu.
* @param width The width of the menu.
* @param height The height of the menu.
* @param cursorColor The color of the cursor.
* @param textColor The color of the text.
* @param boxColor The color of the box.
*/
void drawUIMenuBox(
menu_t *menu,
const uint16_t x,
const uint16_t y,
const uint16_t width,
const uint16_t height,
const uint8_t cursorColor,
const uint8_t textColor,
const uint8_t boxColor
);
/**
* Draws the UI textbox to the frame buffer.
*/
void drawUITextbox();

54
src/dawn/display/frame.c Normal file
View File

@ -0,0 +1,54 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "frame.h"
#include "game/game.h"
#include "display/draw/drawshape.h"
#include "display/draw/drawtext.h"
#include "display/draw/drawstateoverworld.h"
#include "display/draw/drawstatemainmenu.h"
#include "display/draw/drawbattle.h"
char_t FRAME_BUFFER[FRAME_HEIGHT * FRAME_WIDTH];
uint8_t FRAME_COLOR[FRAME_HEIGHT * FRAME_WIDTH];
void frameInit() {
drawClear(' ', COLOR_BLACK);
}
void frameUpdate() {
switch(GAME.state) {
case GAME_STATE_PAUSED:
const char_t *str = "PAUSED";
size_t len = strlen(str);
drawText(
str,
-1,
(FRAME_WIDTH - len) / 2,
(FRAME_HEIGHT - 1) / 2,
COLOR_WHITE
);
break;
case GAME_STATE_OVERWORLD:
drawStateOverworld();
break;
case GAME_STATE_MAIN_MENU:
drawStateMainMenu();
break;
case GAME_STATE_BATTLE:
drawBattle();
break;
default:
printf("Rendering unknown game state: %d\n", GAME.state);
break;
}
}

33
src/dawn/display/frame.h Normal file
View File

@ -0,0 +1,33 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/color.h"
#define FRAME_CHAR_SIZE 8
#define FRAME_PIXEL_WIDTH 320
#define FRAME_PIXEL_HEIGHT 240
#define FRAME_WIDTH FRAME_PIXEL_WIDTH/FRAME_CHAR_SIZE
#define FRAME_HEIGHT FRAME_PIXEL_HEIGHT/FRAME_CHAR_SIZE
extern char_t FRAME_BUFFER[FRAME_HEIGHT * FRAME_WIDTH];
extern uint8_t FRAME_COLOR[FRAME_HEIGHT * FRAME_WIDTH];
/**
* Initializes the frame buffer.
*/
void frameInit();
/**
* Updates the terminal frame.
*/
void frameUpdate();
/**
* Clears the frame buffer.
*/
void frameClear();

55
src/dawn/display/symbol.c Normal file
View File

@ -0,0 +1,55 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assert/assert.h"
#include "rpg/entity/entitydirection.h"
#include "symbol.h"
#include "game/time.h"
char_t symbolGetCharByEntity(const entity_t *ent) {
assertNotNull(ent, "Entity cannot be NULL.");
switch(ent->type) {
case ENTITY_TYPE_SIGN:
return '+';
case ENTITY_TYPE_DOOR:
return 'D';
default:
break;
}
switch(ent->direction) {
case ENTITY_DIRECTION_EAST: return '>';
case ENTITY_DIRECTION_WEST: return '<';
case ENTITY_DIRECTION_NORTH: return '^';
case ENTITY_DIRECTION_SOUTH: return 'v';
default:
assertUnreachable("Invalid entity direction.");
}
}
uint8_t symbolGetColorByEntity(const entity_t *ent) {
assertNotNull(ent, "Entity cannot be NULL.");
switch(ent->type) {
case ENTITY_TYPE_PLAYER:
return COLOR_RED;
case ENTITY_TYPE_NPC:
return COLOR_MAGENTA;
case ENTITY_TYPE_SIGN:
return COLOR_YELLOW;
case ENTITY_TYPE_DOOR:
return COLOR_BROWN;
default:
assertUnreachable("Invalid entity type.");
}
}

26
src/dawn/display/symbol.h Normal file
View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "rpg/entity/entity.h"
#include "display/color.h"
/**
* Returns the symbol for the given entity.
*
* @param ent Entity to get the symbol for.
* @return The symbol for the entity.
*/
char_t symbolGetCharByEntity(const entity_t *ent);
/**
* Returns the color for the given entity.
*
* @param ent Entity to get the color for.
* @return The color for the entity.
*/
uint8_t symbolGetColorByEntity(const entity_t *ent);

View File

@ -1,25 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "assert.hpp"
void assertTrueImplement(
const char *file,
const int32_t line,
const char *func,
const bool_t result,
const char *message,
...
) {
if(!result) {
va_list args;
va_start(args, message);
fprintf(stderr, "Assertion failed in %s:%d (%s): ", file, line, func);
vfprintf(stderr, message, args);
fprintf(stderr, "\n");
va_end(args);
exit(1);
}
}

View File

@ -1,22 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
/**
* Shows an error message box on the host device. This method should be blocking
* and should not return until the user has acknowledged the error.
*
* @param message Message to display.
*/
void errorMessageBox(const std::u8string &message);
/**
* Logs an error message to the host device.
*
* @param message Message to log.
*/
void errorLog(const std::string &message);

View File

@ -1,141 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnlibs.hpp"
namespace Dawn {
enum class CustomEventResult {
NOTHING,
REMOVE,
INVOKE,
INVOKE_AND_REMOVE
};
template<
typename InternalData,
typename InternalListenerData,
typename ListenerArgument,
typename ...InvokeArgs
>
class CustomEvent {
private:
int32_t nextId = 0;
std::unordered_map<
int32_t,
std::pair<InternalListenerData, std::function<void(InvokeArgs...)>>
> listeners;
protected:
InternalData internalData;
/**
* Custom event filter. Decides whether or not the event should be emitted
* to the listener.
*
* @param listenerData Data for this listener.
* @param args The arguments to pass to the listeners.
* @return The result of the filter.
*/
virtual enum CustomEventResult shouldEmit(
const InternalListenerData &listenerData,
const InvokeArgs... args
) = 0;
/**
* Transform the arguments for listener data when the listener is first
* subscribed.
*
* @param argument The argument to transform.
* @return The transformed argument into an internal data format.
*/
virtual InternalListenerData transformData(
const ListenerArgument &argument
) = 0;
/**
* Transform the data for listener data after the event has been emitted.
*
* @param internalData The internal data to transform.
* @return Updated/Transformed internal data.
*/
virtual InternalListenerData transformDataAfterEmit(
const InternalListenerData &internalData
) {
return internalData;
}
public:
/**
* Emits the event.
* @param args The arguments to pass to the listeners.
*/
void emit(InvokeArgs... args) {
auto copy = listeners;
for(auto &pair : copy) {
// Check emit test.
auto result = this->shouldEmit(
pair.second.first,
args...
);
if(
result == CustomEventResult::INVOKE ||
result == CustomEventResult::INVOKE_AND_REMOVE
) {
pair.second.second(args...);
}
if(
result == CustomEventResult::REMOVE ||
result == CustomEventResult::INVOKE_AND_REMOVE
) {
listeners.erase(pair.first);
continue;
}
if(
result == CustomEventResult::INVOKE ||
result == CustomEventResult::INVOKE_AND_REMOVE
) {
// Update the internal data.
listeners[pair.first].first = transformDataAfterEmit(
pair.second.first
);
}
}
}
/**
* Listens to the event.
*
* @param data Listener data to use.
* @param listener The listener to add.
* @returns A function that can be called to remove the listener.
*/
std::function<void()> listen(
const ListenerArgument &data,
const std::function<void(InvokeArgs...)> listener
) {
int32_t id = nextId++;
auto pair = std::make_pair(
transformData(data),
listener
);
listeners[id] = pair;
return [this, id]() {
listeners.erase(id);
};
}
/**
* Destroys the custom event.
*/
virtual ~CustomEvent() {
listeners.clear();
}
};
}

View File

@ -1,57 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
template<typename ...A>
class Event {
private:
int32_t nextId = 0;
std::map<int32_t, std::function<void(A...)>> listeners;
public:
/**
* Constructs a new Event.
*/
Event() {
}
/**
* Emits the event.
* @param args The arguments to pass to the listeners.
*/
void emit(A ...args) {
auto copy = listeners;
for(auto &pair : copy) {
pair.second(args...);
}
}
/**
* Listens to the event.
* @param listener The listener to add.
* @returns A function that can be called to remove the listener.
*/
std::function<void()> listen(
const std::function<void(A...)> listener
) {
int32_t id = nextId++;
listeners[id] = listener;
return [this, id]() {
listeners.erase(id);
};
}
/**
* Destroys the event.
*/
virtual ~Event() {
listeners.clear();
}
};
}

View File

@ -3,7 +3,12 @@
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Subdirs
add_subdirectory(state)
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
Game.cpp
time.c
game.c
)

View File

@ -1,45 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Game.hpp"
#include "scene/Scene.hpp"
#include "scene/item/SceneItem2D.hpp"
using namespace Dawn;
Game::Game() {
}
void Game::init() {
currentScene = std::make_shared<Scene>(weak_from_this());
auto myItem = currentScene->addSceneItem<SceneItem2D>("myItem");
}
void Game::update() {
}
std::shared_ptr<Scene> Game::getCurrentScene() {
return currentScene;
}
void Game::setActiveScene(std::shared_ptr<Scene> scene) {
auto previousCurrent = currentScene;
if(previousCurrent != nullptr) {
previousCurrent->inactive();
}
currentScene = scene;
if(currentScene != nullptr) {
currentScene->active();
}
}
Game::~Game() {
}

View File

@ -1,53 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
class Scene;
class Game : public std::enable_shared_from_this<Game> {
private:
std::shared_ptr<Scene> currentScene;
public:
/**
* Constructs a new instance of Game, the class majorily responsible for
* handling all internal dawn functions outside of platform-centric things
* like windowing and graphics.
*/
Game();
/**
* Initializes the game and all sub managers used by game.
*/
void init();
/**
* Updates the game and all sub managers used by game.
*/
void update();
/**
* Returns the current active scene.
*
* @return The current active scene.
*/
std::shared_ptr<Scene> getCurrentScene();
/**
* Sets the active scene for the game.
*
* @param scene The scene to set as active.
*/
void setActiveScene(std::shared_ptr<Scene> scene);
/**
* Deloads game and all sub managers used by game.
*/
~Game();
};
}

94
src/dawn/game/game.c Normal file
View File

@ -0,0 +1,94 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "game/game.h"
#include "game/time.h"
#include "input.h"
#include "display/display.h"
#include "asset/asset.h"
#include "ui/textbox.h"
#include "ui/testmenu.h"
#include "ui/mainmenu.h"
#include "game/state/mainmenu.h"
#include "game/state/mapchange.h"
#include "game/state/overworld.h"
#include "game/state/battle.h"
#include "rpg/conversation/conversation.h"
#include "asset/assetlanguage.h"
#include "util/memory.h"
game_t GAME;
void gameInit() {
memoryInit();
memorySet(&GAME, 0, sizeof(game_t));
timeInit();
inputInit();
displayInit();
assetInit();
assetLanguageLoad("en.json");
textboxInit();
testMenuInit();
mainMenuInit();
conversationInit();
GAME.state = GAME_STATE_INITIAL;
}
gameupdateresult_t gameUpdate(const float_t delta) {
timeUpdate(delta);
inputUpdate();
switch(GAME.state) {
case GAME_STATE_INITIAL:
GAME.state = GAME_STATE_MAIN_MENU;
break;
case GAME_STATE_OVERWORLD:
gameStateOverworldUpdate();
break;
case GAME_STATE_PAUSED:
if(inputWasPressed(INPUT_BIND_PAUSE)) GAME.state = GAME_STATE_OVERWORLD;
break;
case GAME_STATE_MAP_CHANGE:
gameStateMapChangeUpdate();
break;
case GAME_STATE_MAIN_MENU:
gameStateMainMenuUpdate();
break;
case GAME_STATE_BATTLE:
gameStateBattleUpdate();
break;
default:
printf("Updating unknown state %d\n", GAME.state);
}
if(inputWasPressed(INPUT_BIND_FORCE_QUIT)) GAME.shouldExit = true;
// Perform render.
displayUpdate();
if(GAME.shouldExit) return GAME_UPDATE_RESULT_EXIT;
return GAME_UPDATE_RESULT_CONTINUE;
}
void gameDispose() {
assetDispose();
displayDispose();
memoryTestZero();
}

50
src/dawn/game/game.h Normal file
View File

@ -0,0 +1,50 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "rpg/world/map.h"
typedef enum {
GAME_UPDATE_RESULT_CONTINUE = 0,
GAME_UPDATE_RESULT_EXIT = 1
} gameupdateresult_t;
typedef enum {
GAME_STATE_INITIAL = 0,
GAME_STATE_OVERWORLD = 1,
GAME_STATE_PAUSED = 2,
GAME_STATE_MAP_CHANGE = 3,
GAME_STATE_MAIN_MENU = 4,
GAME_STATE_BATTLE = 5
} gamestate_t;
typedef struct {
map_t *currentMap;
gamestate_t state;
bool_t shouldExit;
maplist_t mapNext;
} game_t;
extern game_t GAME;
/**
* Initializes the game state.
*/
void gameInit();
/**
* Updates the game state.
*
* @param delta Time since last update.
* @return Game update result, 0 for continue, 1 for exit, else for failure.
*/
gameupdateresult_t gameUpdate(const float_t delta);
/**
* Cleans up the game state.
*/
void gameDispose();

View File

@ -0,0 +1,15 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Subdirs
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
battle.c
mainmenu.c
mapchange.c
overworld.c
)

View File

@ -0,0 +1,17 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "battle.h"
#include "game/game.h"
#include "ui/textbox.h"
#include "rpg/battle/battle.h"
void gameStateBattleUpdate() {
battleUpdate();
textboxUpdate();
}

View File

@ -0,0 +1,13 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
/**
* Updates the battle state.
*/
void gameStateBattleUpdate();

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "mainmenu.h"
#include "ui/mainmenu.h"
void gameStateMainMenuUpdate() {
// Update the main menu
mainMenuUpdate();
}

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
/**
* Updates the main menu state.
*/
void gameStateMainMenuUpdate();

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "mapchange.h"
#include "asset/assetmap.h"
#include "game/game.h"
#include "util/memory.h"
void gameStateMapChangeUpdate() {
// First try and find the player object
entity_t *player = NULL;
player_t oldPlayerData;
entitydirection_t dir = ENTITY_DIRECTION_SOUTH;
if(GAME.currentMap != NULL) {
player = mapEntityGetByType(GAME.currentMap, ENTITY_TYPE_PLAYER);
dir = player->direction;
oldPlayerData = player->player;
}
assetMapLoad(MAP_LIST_PATHS[GAME.mapNext], &MAP_MAIN);
GAME.state = GAME_STATE_OVERWORLD;
GAME.currentMap = &MAP_MAIN;
// Do not reference player since its invalid, just check if it DID exist
if(GAME.currentMap != NULL && player != NULL) {
player = mapEntityGetByType(GAME.currentMap, ENTITY_TYPE_PLAYER);
if(player == NULL) return;
player->player = oldPlayerData;
player->direction = dir;
}
}

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
/**
* Updates the map change game state.
*/
void gameStateMapChangeUpdate();

View File

@ -0,0 +1,22 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "overworld.h"
#include "game/game.h"
#include "input.h"
#include "ui/textbox.h"
#include "ui/testmenu.h"
#include "rpg/conversation/conversation.h"
void gameStateOverworldUpdate() {
textboxUpdate();
testMenuUpdate();
conversationUpdate();
if(GAME.currentMap) mapUpdate(GAME.currentMap);
if(inputWasPressed(INPUT_BIND_PAUSE)) GAME.state = GAME_STATE_PAUSED;
}

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
/**
* Updates the overworld game state.
*/
void gameStateOverworldUpdate();

23
src/dawn/game/time.c Normal file
View File

@ -0,0 +1,23 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "game/time.h"
#include "assert/assert.h"
dawntime_t TIME;
void timeInit() {
TIME.delta = 0.0f;
TIME.time = 0.0f;
}
void timeUpdate(const float_t delta) {
assertTrue(delta > 0, "time delta must be greater than 0.");
TIME.delta = delta;
TIME.time += delta;
}

28
src/dawn/game/time.h Normal file
View File

@ -0,0 +1,28 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
typedef struct {
float_t delta;
float_t time;
} dawntime_t;
extern dawntime_t TIME;
/**
* Initializes the time system.
*/
void timeInit();
/**
* Updates the time system.
*
* @param delta Time since last update.
*/
void timeUpdate(const float_t delta);

41
src/dawn/input.c Normal file
View File

@ -0,0 +1,41 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "input.h"
#include "util/memory.h"
input_t INPUT;
void inputInit() {
memorySet(&INPUT, 0, sizeof(input_t));
}
void inputUpdate() {
// Update the previous state
memoryCopy(
INPUT.previousState,
INPUT.currentState,
sizeof(INPUT.previousState)
);
// Get the new state
for(inputbind_t i = 0; i < INPUT_BIND_COUNT; i++) {
INPUT.currentState[i] = inputGetState(i);
}
}
inputstate_t inputIsDown(const inputbind_t bind) {
return INPUT.currentState[bind];
}
inputstate_t inputWasPressed(const inputbind_t bind) {
return INPUT.currentState[bind] && !INPUT.previousState[bind];
}
inputstate_t inputWasReleased(const inputbind_t bind) {
return !INPUT.currentState[bind] && INPUT.previousState[bind];
}

68
src/dawn/input.h Normal file
View File

@ -0,0 +1,68 @@
/**
* Copyright (c) 2023 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
typedef uint8_t inputbind_t;
typedef bool_t inputstate_t;
#define INPUT_BIND_UP 0x00
#define INPUT_BIND_DOWN 0x01
#define INPUT_BIND_LEFT 0x02
#define INPUT_BIND_RIGHT 0x03
#define INPUT_BIND_ACCEPT 0x04
#define INPUT_BIND_CANCEL 0x05
#define INPUT_BIND_PAUSE 0x06
#define INPUT_BIND_FORCE_QUIT 0x07
#define INPUT_BIND_COUNT (INPUT_BIND_FORCE_QUIT + 1)
typedef struct {
inputstate_t currentState[INPUT_BIND_COUNT];
inputstate_t previousState[INPUT_BIND_COUNT];
} input_t;
extern input_t INPUT;
/**
* Initializes the input system.
*/
void inputInit();
/**
* Updates the input system.
*/
void inputUpdate();
/**
* Returns whether or not the given input is down.
*
* @param bind The input to check.
*/
inputstate_t inputIsDown(const inputbind_t bind);
/**
* Returns whether or not the given input was pressed this update tick.
*
* @param bind The input to check.
*/
inputstate_t inputWasPressed(const inputbind_t bind);
/**
* Returns whether or not the given input was released this update tick.
*
* @param bind The input to check.
*/
inputstate_t inputWasReleased(const inputbind_t bind);
/**
* Returns the current state of the given input. Overridden per platform.
*
* @param bind The input to check.
*/
inputstate_t inputGetState(const inputbind_t bind);

View File

@ -1,10 +1,12 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
Language.cpp
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Subdirs
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
language.c
)

View File

@ -1,15 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Language.hpp"
using namespace Dawn;
std::u8string Language::get(
const char_t key[],
const std::pair<std::string, std::u8string> &args
) {
return u8"Some language string 👍";
}

View File

@ -1,24 +0,0 @@
// Copyright (c) 2024 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawn.hpp"
namespace Dawn {
class Language {
public:
/**
* Gets a language string from the language definition set.
*
* @param key The key to look up in the language file.
* @param args A pair of strings to replace in the language string.
* @return The language string.
*/
static std::u8string get(
const char_t key[],
const std::pair<std::string, std::u8string> &args = std::make_pair("", u8"")
);
};
}

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "language.h"
#include "assert/assert.h"
#include "util/memory.h"
language_t LANGUAGE;
void languageInit() {
memorySet(&LANGUAGE, 0, sizeof(language_t));
}
const char_t * languageGetPointer(const char_t *key) {
assertNotNull(key, "Key cannot be NULL.");
language_t *lang = &LANGUAGE;
lang->count;
int32_t i = 0;
while(i < LANGUAGE.count) {
if(strcmp(key, LANGUAGE.keys[i]) != 0) {
i++;
continue;
}
return LANGUAGE.strings[i];
}
return NULL;
}
int32_t languageGet(char_t *buffer, const char_t *key) {
const char_t *str = languageGetPointer(key);
if(str == NULL) return -1;
if(buffer == NULL) return strlen(str);
strcpy(buffer, str);
return strlen(str);
}

View File

@ -0,0 +1,44 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
#define LANGUAGE_STRING_COUNT_MAX 128
#define LANGUAGE_STRING_KEY_LENGTH_MAX 64
#define LANGUAGE_STRING_LENGTH_MAX 1024
typedef struct {
const char_t keys[LANGUAGE_STRING_COUNT_MAX][LANGUAGE_STRING_KEY_LENGTH_MAX];
const char_t strings[LANGUAGE_STRING_COUNT_MAX][LANGUAGE_STRING_LENGTH_MAX];
int32_t count;
} language_t;
extern language_t LANGUAGE;
/**
* Initializes the language system.
*/
void languageInit();
/**
* Gets the pointer to the language string for the given key. Pointer should not
* be modified or freed.
*
* @param key The key to get the string for.
* @return The pointer to the string.
*/
const char_t * languageGetPointer(const char_t *key);
/**
* Returns the language string for the given key.
*
* @param buffer The buffer to write the string to, or NULL to get length.
* @param key The key to get the string for.
* @return The length of the string.
*/
int32_t languageGet(char_t *buffer, const char_t *key);

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