Compare commits
13 Commits
5cea284906
...
097c8c00f9
| Author | SHA1 | Date | |
|---|---|---|---|
| 097c8c00f9 | |||
| aa5b41fe31 | |||
| 0d56859d94 | |||
| 1af5f238e4 | |||
| dd697d5650 | |||
| 5cf299a1c7 | |||
| 67bf825cc9 | |||
| 56e1696cd4 | |||
| d955fb6430 | |||
| dd910a31aa | |||
| 708c4d0ec3 | |||
| ad13d6c6a1 | |||
| 1c32158142 |
5
.ci/dolphin/Dockerfile
Normal file
5
.ci/dolphin/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM devkitpro/devkitppc
|
||||
|
||||
RUN apt update && \
|
||||
apt install -y python3 python3-pip python3-polib python3-pil python3-dotenv python3-pyqt5 python3-opengl && \
|
||||
dkp-pacman -S --needed --noconfirm gamecube-sdl2 ppc-liblzma ppc-libzip
|
||||
12
.ci/dolphin/build-gamecube.sh
Executable file
12
.ci/dolphin/build-gamecube.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
docker build -t myapp:latest -f .ci/dolphin/Dockerfile .
|
||||
docker run -it -v ./:/workdir myapp:latest /bin/bash -c ' \
|
||||
export PATH="$DEVKITPPC/bin:$PATH" && \
|
||||
cd /workdir && \
|
||||
rm -rf build-gamecube && \
|
||||
mkdir -p build-gamecube && \
|
||||
cmake -S. -Bbuild-gamecube -DDUSK_TARGET_SYSTEM=gamecube -DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/GameCube.cmake" && \
|
||||
cd build-gamecube && \
|
||||
make VERBOSE=1
|
||||
'
|
||||
# docker run -it -v ./:/workdir myapp:latest /bin/bash
|
||||
13
.ci/dolphin/build-wii.sh
Executable file
13
.ci/dolphin/build-wii.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
docker build -t myapp:latest -f .ci/dolphin/Dockerfile .
|
||||
docker run -it -v ./:/workdir myapp:latest /bin/bash -c ' \
|
||||
export PATH="$DEVKITPPC/bin:$PATH" && \
|
||||
cd /workdir && \
|
||||
rm -rf build-wii && \
|
||||
mkdir -p build-wii && \
|
||||
cmake -S. -Bbuild-wii -DDUSK_TARGET_SYSTEM=wii -DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/Wii.cmake" && \
|
||||
cd build-wii && \
|
||||
make VERBOSE=1 && \
|
||||
mv ./Dusk.dol ./boot.dol
|
||||
'
|
||||
# docker run -it -v ./:/workdir myapp:latest /bin/bash
|
||||
@@ -71,4 +71,17 @@ jobs:
|
||||
with:
|
||||
name: dusk-psp
|
||||
path: build/gitea/
|
||||
if-no-files-found: error
|
||||
if-no-files-found: error
|
||||
|
||||
build-dolphin:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y docker.io
|
||||
- name: Docker test
|
||||
run: |
|
||||
./.ci/dolphin/build-gamecube.sh
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -101,4 +101,7 @@ yarn-error.log
|
||||
yarn.lock
|
||||
|
||||
.editor
|
||||
.venv
|
||||
.venv
|
||||
|
||||
/build2
|
||||
/build*
|
||||
107
CMakeLists.txt
107
CMakeLists.txt
@@ -4,18 +4,13 @@
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Setup
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
||||
|
||||
option(ENABLE_TESTS "Enable tests" ON)
|
||||
|
||||
# Set target system
|
||||
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
||||
set(DUSK_TARGET_SYSTEM "linux")
|
||||
# set(DUSK_TARGET_SYSTEM "psp")
|
||||
endif()
|
||||
option(ENABLE_TESTS "Enable tests" OFF)
|
||||
|
||||
# Prep cache
|
||||
set(DUSK_CACHE_TARGET "dusk-target")
|
||||
@@ -42,28 +37,48 @@ file(MAKE_DIRECTORY ${DUSK_GENERATED_HEADERS_DIR})
|
||||
# Find packages
|
||||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||||
|
||||
# Set target system
|
||||
# message(FATAL_ERROR "DISABLED FOR NOW2 ${DUSK_TARGET_SYSTEM}")
|
||||
|
||||
if(NOT DEFINED DUSK_TARGET_SYSTEM)
|
||||
set(DUSK_TARGET_SYSTEM "linux")
|
||||
# set(DUSK_TARGET_SYSTEM "psp")
|
||||
endif()
|
||||
|
||||
# Toolchains
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
find_package(pspsdk REQUIRED)
|
||||
endif()
|
||||
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||
# Override to make library and binary be the same.
|
||||
set(DUSK_LIBRARY_TARGET_NAME "${DUSK_LIBRARY_TARGET_NAME}.elf" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
endif()
|
||||
|
||||
# Init Project.
|
||||
project(${DUSK_LIBRARY_TARGET_NAME}
|
||||
VERSION 1.0.0
|
||||
LANGUAGES C
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
# MainLibrary
|
||||
add_library(${DUSK_LIBRARY_TARGET_NAME})
|
||||
# Either, create library and binary separately (used for tests), or make them
|
||||
# one in the same so all code is in the binary.
|
||||
if(ENABLE_TESTS)
|
||||
# MainLibrary
|
||||
add_library(${DUSK_LIBRARY_TARGET_NAME} STATIC)
|
||||
|
||||
# Binary Executable
|
||||
add_executable(${DUSK_BINARY_TARGET_NAME})
|
||||
# Binary Executable
|
||||
add_executable(${DUSK_BINARY_TARGET_NAME} ${DUSK_SOURCES_DIR}/null.c)
|
||||
|
||||
# Link library to binary and test
|
||||
target_link_libraries(${DUSK_BINARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
${DUSK_LIBRARY_TARGET_NAME}
|
||||
)
|
||||
# Link library to binary
|
||||
target_link_libraries(${DUSK_BINARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
${DUSK_LIBRARY_TARGET_NAME}
|
||||
)
|
||||
else()
|
||||
set(DUSK_BINARY_TARGET_NAME "${DUSK_LIBRARY_TARGET_NAME}" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||
add_executable(${DUSK_BINARY_TARGET_NAME} ${DUSK_SOURCES_DIR}/null.c)
|
||||
endif()
|
||||
|
||||
# Add tools
|
||||
add_subdirectory(tools)
|
||||
@@ -77,8 +92,10 @@ if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
||||
find_package(OpenGL REQUIRED)
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
SDL2
|
||||
pthread
|
||||
OpenGL::GL
|
||||
GL
|
||||
m
|
||||
)
|
||||
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
@@ -87,6 +104,7 @@ elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
${SDL2_LIBRARIES}
|
||||
SDL2
|
||||
pthread
|
||||
OpenGL::GL
|
||||
zip
|
||||
bz2
|
||||
@@ -94,18 +112,61 @@ elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
mbedtls
|
||||
mbedcrypto
|
||||
lzma
|
||||
m
|
||||
)
|
||||
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||
${SDL2_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
|
||||
configure_file(opengl.pc.in opengl.pc @ONLY)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(zip IMPORTED_TARGET libzip)
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DOLPHIN
|
||||
)
|
||||
|
||||
# Custom flags for cglm
|
||||
set(CGLM_SHARED OFF CACHE BOOL "Build cglm shared" FORCE)
|
||||
set(CGLM_STATIC ON CACHE BOOL "Build cglm static" FORCE)
|
||||
find_package(cglm REQUIRED)
|
||||
|
||||
# Compile lua
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
liblua
|
||||
URL https://www.lua.org/ftp/lua-5.5.0.tar.gz
|
||||
)
|
||||
FetchContent_MakeAvailable(liblua)
|
||||
set(LUA_SRC_DIR "${liblua_SOURCE_DIR}/src")
|
||||
set(LUA_C_FILES
|
||||
lapi.c lauxlib.c lbaselib.c lcode.c lcorolib.c lctype.c ldblib.c ldebug.c
|
||||
ldo.c ldump.c lfunc.c lgc.c linit.c liolib.c llex.c lmathlib.c lmem.c
|
||||
loadlib.c lobject.c lopcodes.c loslib.c lparser.c lstate.c lstring.c
|
||||
lstrlib.c ltable.c ltablib.c ltm.c lundump.c lutf8lib.c lvm.c lzio.c
|
||||
)
|
||||
list(TRANSFORM LUA_C_FILES PREPEND "${LUA_SRC_DIR}/")
|
||||
add_library(liblua STATIC ${LUA_C_FILES})
|
||||
target_include_directories(liblua PUBLIC "${LUA_SRC_DIR}")
|
||||
target_compile_definitions(liblua PRIVATE LUA_USE_C89)
|
||||
add_library(lua::lua ALIAS liblua)
|
||||
set(Lua_FOUND TRUE CACHE BOOL "Lua found" FORCE)
|
||||
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||
cglm
|
||||
liblua
|
||||
m
|
||||
fat
|
||||
PkgConfig::zip
|
||||
)
|
||||
endif()
|
||||
|
||||
# Force turn tests off for now
|
||||
set(ENABLE_TESTS OFF CACHE BOOL "Enable tests" FORCE)
|
||||
|
||||
# Add code
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(${DUSK_SOURCES_DIR})
|
||||
|
||||
# Handle tests
|
||||
if(ENABLE_TESTS)
|
||||
@@ -141,4 +202,12 @@ if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
PSAR_PATH ${DUSK_BUILD_DIR}/dusk.dsk
|
||||
VERSION 01.00
|
||||
)
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||
set(DUSK_BINARY_TARGET_NAME_DOL "${DUSK_BUILD_DIR}/Dusk.dol")
|
||||
add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD
|
||||
COMMAND elf2dol
|
||||
"$<TARGET_FILE:${DUSK_BINARY_TARGET_NAME}>"
|
||||
"${DUSK_BINARY_TARGET_NAME_DOL}"
|
||||
COMMENT "Generating ${DUSK_BINARY_TARGET_NAME_DOL} from ${DUSK_BINARY_TARGET_NAME}"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "uiframe.h"
|
||||
#include "display/spritebatch.h"
|
||||
#include "assert/assert.h"
|
||||
#include <math.h>
|
||||
#include "util/math.h"
|
||||
|
||||
void uiFrameDraw(
|
||||
const float_t x,
|
||||
|
||||
@@ -16,6 +16,21 @@ if PLATFORM == "psp" then
|
||||
inputBind("lstick_down", INPUT_ACTION_DOWN)
|
||||
inputBind("lstick_left", INPUT_ACTION_LEFT)
|
||||
inputBind("lstick_right", INPUT_ACTION_RIGHT)
|
||||
|
||||
elseif PLATFORM == "gamecube" then
|
||||
-- inputBind("start", INPUT_ACTION_RAGEQUIT)
|
||||
-- inputBind("dpad_up", INPUT_ACTION_UP)
|
||||
-- inputBind("dpad_down", INPUT_ACTION_DOWN)
|
||||
-- inputBind("dpad_left", INPUT_ACTION_LEFT)
|
||||
-- inputBind("dpad_right", INPUT_ACTION_RIGHT)
|
||||
-- inputBind("button_b", INPUT_ACTION_CANCEL)
|
||||
-- inputBind("button_a", INPUT_ACTION_ACCEPT)
|
||||
-- inputBind("button_start", INPUT_ACTION_RAGEQUIT)
|
||||
-- inputBind("lstick_up", INPUT_ACTION_UP)
|
||||
-- inputBind("lstick_down", INPUT_ACTION_DOWN)
|
||||
-- inputBind("lstick_left", INPUT_ACTION_LEFT)
|
||||
-- inputBind("lstick_right", INPUT_ACTION_RIGHT)
|
||||
|
||||
else
|
||||
if INPUT_KEYBOARD then
|
||||
inputBind("w", INPUT_ACTION_UP)
|
||||
@@ -37,5 +52,5 @@ else
|
||||
end
|
||||
end
|
||||
|
||||
localeSet(DUSK_LOCALE_EN_US)
|
||||
-- localeSet(DUSK_LOCALE_EN_US)
|
||||
sceneSet('scene/initial.dsf')
|
||||
@@ -8,37 +8,59 @@ module('time')
|
||||
module('map')
|
||||
module('glm')
|
||||
|
||||
screenSetBackground(colorBlack())
|
||||
mapLoad('map/testmap/testmap.dmf')
|
||||
camera = cameraCreate(CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC)
|
||||
screenSetBackground(colorLime())
|
||||
mapCamera = cameraCreate()
|
||||
text = "Hello, Dusk!"
|
||||
|
||||
text = "Hello World"
|
||||
x = -35
|
||||
y = 0
|
||||
|
||||
function sceneDispose()
|
||||
end
|
||||
|
||||
function sceneUpdate()
|
||||
end
|
||||
|
||||
function sceneRender()
|
||||
-- Map Test
|
||||
mapCamera.position = vec3(50, 50, 50)
|
||||
cameraPushMatrix(mapCamera)
|
||||
mapCamera.position = vec3(300, 300, 300)
|
||||
mapRender()
|
||||
|
||||
textDraw(x, y, text, colorBlue())
|
||||
|
||||
spriteBatchFlush()
|
||||
cameraPopMatrix()
|
||||
end
|
||||
|
||||
-- UI Test
|
||||
cameraPushMatrix(camera)
|
||||
camera.bottom = screenGetHeight()
|
||||
camera.right = screenGetWidth()
|
||||
|
||||
width, height = textMeasure(text)
|
||||
x = (screenGetWidth() - width)
|
||||
x = math.sin(TIME.time * 2) * (x / 2) + (x / 2)
|
||||
y = (screenGetHeight() - height) / 2
|
||||
y = math.cos(TIME.time * 3) * (y) + (y)
|
||||
textDraw(x, y, text, colorMagenta())
|
||||
-- screenSetBackground(colorBlack())
|
||||
-- mapLoad('map/testmap/testmap.dmf')
|
||||
-- camera = cameraCreate(CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC)
|
||||
-- mapCamera = cameraCreate()
|
||||
|
||||
cameraPopMatrix()
|
||||
end
|
||||
-- text = "Hello World"
|
||||
|
||||
-- function sceneDispose()
|
||||
-- end
|
||||
|
||||
-- function sceneUpdate()
|
||||
-- end
|
||||
|
||||
-- function sceneRender()
|
||||
-- -- Map Test
|
||||
-- mapCamera.position = vec3(300, 300, 300)
|
||||
-- cameraPushMatrix(mapCamera)
|
||||
-- mapRender()
|
||||
-- cameraPopMatrix()
|
||||
|
||||
-- -- UI Test
|
||||
-- cameraPushMatrix(camera)
|
||||
-- camera.bottom = screenGetHeight()
|
||||
-- camera.right = screenGetWidth()
|
||||
|
||||
-- width, height = textMeasure(text)
|
||||
-- x = (screenGetWidth() - width)
|
||||
-- x = math.sin(TIME.time * 2) * (x / 2) + (x / 2)
|
||||
-- y = (screenGetHeight() - height) / 2
|
||||
-- y = math.cos(TIME.time * 3) * (y) + (y)
|
||||
-- textDraw(x, y, text, colorMagenta())
|
||||
|
||||
-- cameraPopMatrix()
|
||||
-- end
|
||||
@@ -3,4 +3,5 @@
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_asset(TILESET minogram.png type=PALETTIZED tileWidth=6 tileHeight=10 columns=16 rows=6)# Fixes PSP rendering
|
||||
add_asset(TILESET minogram.png type=ALPHA tileWidth=6 tileHeight=10 columns=16 rows=6)# Fixes PSP rendering
|
||||
# add_asset(TILESET minogram.png type=PALETTIZED tileWidth=6 tileHeight=10 columns=16 rows=6)# Fixes PSP rendering
|
||||
@@ -4,6 +4,7 @@
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
cglm
|
||||
GIT_REPOSITORY https://github.com/recp/cglm.git
|
||||
|
||||
10
opengl.pc.in
Normal file
10
opengl.pc.in
Normal file
@@ -0,0 +1,10 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: OpenGL
|
||||
Description: OpenGL (without GLX) library and headers.
|
||||
Version: @PROJECT_VERSION@
|
||||
Libs.private: -lstdc++ -logc -lm
|
||||
Libs: -L${libdir} -lopengx
|
||||
Cflags: -I${includedir}
|
||||
@@ -3,29 +3,31 @@
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
find_package(cglm REQUIRED)
|
||||
find_package(libzip REQUIRED)
|
||||
find_package(Lua REQUIRED)
|
||||
if(NOT cglm_FOUND)
|
||||
find_package(cglm REQUIRED)
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC cglm)
|
||||
endif()
|
||||
|
||||
if(Lua_FOUND AND NOT TARGET Lua::Lua)
|
||||
add_library(Lua::Lua INTERFACE IMPORTED)
|
||||
set_target_properties(
|
||||
Lua::Lua
|
||||
PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${LUA_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "${LUA_LIBRARIES}"
|
||||
)
|
||||
if(NOT libzip_FOUND)
|
||||
find_package(libzip REQUIRED)
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC zip)
|
||||
endif()
|
||||
|
||||
if(NOT Lua_FOUND)
|
||||
find_package(Lua REQUIRED)
|
||||
if(Lua_FOUND AND NOT TARGET Lua::Lua)
|
||||
add_library(Lua::Lua INTERFACE IMPORTED)
|
||||
set_target_properties(
|
||||
Lua::Lua
|
||||
PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${LUA_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "${LUA_LIBRARIES}"
|
||||
)
|
||||
endif()
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC Lua::Lua)
|
||||
endif()
|
||||
|
||||
# Libs
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
m
|
||||
cglm
|
||||
zip
|
||||
pthread
|
||||
Lua::Lua
|
||||
)
|
||||
|
||||
# Includes
|
||||
target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
|
||||
@@ -63,7 +65,10 @@ add_subdirectory(map)
|
||||
add_subdirectory(scene)
|
||||
add_subdirectory(script)
|
||||
add_subdirectory(story)
|
||||
add_subdirectory(thread)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(ui)
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(util)
|
||||
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux" OR DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
add_subdirectory(thread)
|
||||
endif()
|
||||
@@ -37,6 +37,7 @@
|
||||
line,
|
||||
message
|
||||
);
|
||||
debugFlush();
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -12,10 +12,66 @@
|
||||
#include "asset/assettype.h"
|
||||
#include "engine/engine.h"
|
||||
#include "debug/debug.h"
|
||||
#include "util/string.h"
|
||||
|
||||
errorret_t assetInit(void) {
|
||||
memoryZero(&ASSET, sizeof(asset_t));
|
||||
|
||||
|
||||
#if DOLPHIN
|
||||
// Init FAT driver.
|
||||
if(!fatInitDefault()) errorThrow("Failed to initialize FAT filesystem.");
|
||||
|
||||
char_t **dolphinSearchPath = (char_t **)ASSET_DOLPHIN_PATHS;
|
||||
char_t foundPath[FILENAME_MAX];
|
||||
foundPath[0] = '\0';
|
||||
do {
|
||||
// Try open dir
|
||||
DIR *pdir = opendir(*dolphinSearchPath);
|
||||
if(pdir == NULL) continue;
|
||||
|
||||
|
||||
// Scan if file is present
|
||||
while(true) {
|
||||
struct dirent* pent = readdir(pdir);
|
||||
if(pent == NULL) break;
|
||||
|
||||
if(stringCompareInsensitive(pent->d_name, ASSET_FILE) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Copy out filename
|
||||
snprintf(
|
||||
foundPath,
|
||||
FILENAME_MAX,
|
||||
"%s/%s",
|
||||
*dolphinSearchPath,
|
||||
ASSET_FILE
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
// Close dir.
|
||||
closedir(pdir);
|
||||
|
||||
// Did we find the file here?
|
||||
if(foundPath[0] != '\0') break;
|
||||
} while(*(++dolphinSearchPath) != NULL);
|
||||
|
||||
if(foundPath[0] != '\0') {
|
||||
}
|
||||
|
||||
// Did we find the asset file?
|
||||
if(foundPath[0] == '\0') {
|
||||
errorThrow("Failed to find asset file on FAT filesystem.");
|
||||
}
|
||||
|
||||
ASSET.zip = zip_open(foundPath, ZIP_RDONLY, NULL);
|
||||
if(ASSET.zip == NULL) {
|
||||
errorThrow("Failed to open asset file on FAT filesystem.");
|
||||
}
|
||||
errorOk();
|
||||
#endif
|
||||
|
||||
// Engine may have been provided the launch path
|
||||
if(ENGINE.argc > 0) {
|
||||
// Get the directory of the executable
|
||||
@@ -177,20 +233,42 @@ errorret_t assetLoad(const char_t *filename, void *output) {
|
||||
assertStrLenMax(filename, FILENAME_MAX, "Filename too long.");
|
||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||
|
||||
// Get file size of the asset.
|
||||
zip_stat_t st;
|
||||
zip_stat_init(&st);
|
||||
if(!zip_stat(ASSET.zip, filename, 0, &st) == 0) {
|
||||
errorThrow("Failed to stat asset file: %s", filename);
|
||||
}
|
||||
|
||||
// Minimum file size.
|
||||
zip_int64_t fileSize = (zip_int64_t)st.size;
|
||||
if(fileSize < sizeof(assetheader_t)) {
|
||||
errorThrow("Asset file too small to contain header: %s", filename);
|
||||
}
|
||||
|
||||
// Try to open the file
|
||||
zip_file_t *file = zip_fopen(ASSET.zip, filename, 0);
|
||||
if(file == NULL) {
|
||||
errorThrow("Failed to open asset file: %s", filename);
|
||||
}
|
||||
|
||||
|
||||
// Read the header.
|
||||
zip_int64_t bytesRemaining = fileSize;
|
||||
assetheader_t header;
|
||||
memoryZero(&header, sizeof(assetheader_t));
|
||||
zip_int64_t bytesRead = zip_fread(file, &header, sizeof(assetheader_t));
|
||||
if(bytesRead != sizeof(assetheader_t)) {
|
||||
zip_int64_t bytesRead = zip_fread(
|
||||
file,
|
||||
&header,
|
||||
(zip_uint64_t)sizeof(assetheader_t)
|
||||
);
|
||||
if((size_t)bytesRead != sizeof(assetheader_t)) {
|
||||
zip_fclose(file);
|
||||
errorThrow("Failed to read asset header for: %s", filename);
|
||||
}
|
||||
bytesRemaining -= (zip_uint64_t)bytesRead;
|
||||
|
||||
assertTrue(sizeof(assetheader_t) == ASSET_HEADER_SIZE, "Asset header size mismatch.");
|
||||
assertTrue(bytesRead == ASSET_HEADER_SIZE, "Asset header read size mismatch.");
|
||||
|
||||
// Find the asset type based on the header
|
||||
const assettypedef_t *def = NULL;
|
||||
@@ -220,20 +298,44 @@ errorret_t assetLoad(const char_t *filename, void *output) {
|
||||
switch(def->loadStrategy) {
|
||||
case ASSET_LOAD_STRAT_ENTIRE:
|
||||
assertNotNull(def->entire, "Asset load function cannot be NULL.");
|
||||
void *data = memoryAllocate(def->dataSize);
|
||||
bytesRead = zip_fread(file, data, def->dataSize);
|
||||
if(bytesRead == 0 || bytesRead > def->dataSize) {
|
||||
|
||||
// Must have more to read
|
||||
if(bytesRemaining <= 0) {
|
||||
zip_fclose(file);
|
||||
errorThrow("No data remaining to read for asset: %s", filename);
|
||||
}
|
||||
|
||||
if(bytesRemaining > def->dataSize) {
|
||||
zip_fclose(file);
|
||||
errorThrow(
|
||||
"Asset file has too much data remaining after header: %s",
|
||||
filename
|
||||
);
|
||||
}
|
||||
|
||||
// Create space to read the entire asset data
|
||||
void *data = memoryAllocate(bytesRemaining);
|
||||
if(!data) {
|
||||
zip_fclose(file);
|
||||
errorThrow("Failed to allocate memory for asset data of file: %s", filename);
|
||||
}
|
||||
|
||||
// Read in the asset data.
|
||||
bytesRead = zip_fread(file, data, bytesRemaining);
|
||||
if(bytesRead == 0 || bytesRead > bytesRemaining) {
|
||||
memoryFree(data);
|
||||
zip_fclose(file);
|
||||
errorThrow("Failed to read asset data for file: %s", filename);
|
||||
}
|
||||
|
||||
bytesRemaining -= bytesRead;
|
||||
|
||||
// Close the file now we have the data
|
||||
zip_fclose(file);
|
||||
|
||||
// Pass to the asset type loader
|
||||
errorret_t ret = def->entire(data, output);
|
||||
memoryFree(data);
|
||||
|
||||
errorChain(ret);
|
||||
break;
|
||||
|
||||
|
||||
@@ -9,27 +9,54 @@
|
||||
#include "error/error.h"
|
||||
#include "assettype.h"
|
||||
|
||||
#if ASSET_TYPE == wad
|
||||
#if PSP
|
||||
#define ASSET_PBP_READ_PBP_FROM_HOST 0
|
||||
#define ASSET_PBP_SIGNATURE_SIZE 4
|
||||
#define ASSET_PBP_SIGNATURE "\0PBP"
|
||||
#if PSP
|
||||
#define ASSET_PBP_READ_PBP_FROM_HOST 0
|
||||
#define ASSET_PBP_SIGNATURE_SIZE 4
|
||||
#define ASSET_PBP_SIGNATURE "\0PBP"
|
||||
|
||||
typedef struct {
|
||||
char_t signature[ASSET_PBP_SIGNATURE_SIZE];
|
||||
uint32_t version;
|
||||
uint32_t sfoOffset;
|
||||
uint32_t icon0Offset;
|
||||
uint32_t icon1Offset;
|
||||
uint32_t pic0Offset;
|
||||
uint32_t pic1Offset;
|
||||
uint32_t snd0Offset;
|
||||
uint32_t pspOffset;
|
||||
uint32_t psarOffset;
|
||||
} assetpbp_t;
|
||||
#endif
|
||||
#else
|
||||
#error "Unsupported ASSET_TYPE"
|
||||
typedef struct {
|
||||
char_t signature[ASSET_PBP_SIGNATURE_SIZE];
|
||||
uint32_t version;
|
||||
uint32_t sfoOffset;
|
||||
uint32_t icon0Offset;
|
||||
uint32_t icon1Offset;
|
||||
uint32_t pic0Offset;
|
||||
uint32_t pic1Offset;
|
||||
uint32_t snd0Offset;
|
||||
uint32_t pspOffset;
|
||||
uint32_t psarOffset;
|
||||
} assetpbp_t;
|
||||
|
||||
#elif DOLPHIN
|
||||
#include <fat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char_t *ASSET_DOLPHIN_PATHS[] = {
|
||||
"/",
|
||||
"/Dusk",
|
||||
"/dusk",
|
||||
"/DUSK",
|
||||
"/apps",
|
||||
"/apps/Dusk",
|
||||
"/apps/dusk",
|
||||
"/apps/DUSK",
|
||||
".",
|
||||
"./",
|
||||
"./Dusk",
|
||||
"./dusk",
|
||||
"./DUSK",
|
||||
"./apps",
|
||||
"./apps/Dusk",
|
||||
"./apps/dusk",
|
||||
"./apps/DUSK",
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
#define ASSET_FILE "dusk.dsk"
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "assert/assert.h"
|
||||
#include "display/texture.h"
|
||||
|
||||
#include "debug/debug.h"
|
||||
|
||||
errorret_t assetAlphaImageLoad(void *data, void *output) {
|
||||
assertNotNull(data, "Data pointer cannot be NULL.");
|
||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||
@@ -16,6 +18,10 @@ errorret_t assetAlphaImageLoad(void *data, void *output) {
|
||||
assetalphaimage_t *dataPtr = (assetalphaimage_t *)data;
|
||||
texture_t *outputPtr = (texture_t *)output;
|
||||
|
||||
// Fix endian
|
||||
dataPtr->width = le32toh(dataPtr->width);
|
||||
dataPtr->height = le32toh(dataPtr->height);
|
||||
|
||||
textureInit(
|
||||
outputPtr,
|
||||
dataPtr->width,
|
||||
|
||||
@@ -43,6 +43,13 @@ errorret_t assetLanguageInit(
|
||||
errorThrow("Failed to read language asset header.");
|
||||
}
|
||||
|
||||
// Fix the endianness of the header data.
|
||||
for(uint32_t i = 0; i < LANG_KEY_COUNT; i++) {
|
||||
lang->header.strings[i].chunk = le32toh(lang->header.strings[i].chunk);
|
||||
lang->header.strings[i].offset = le32toh(lang->header.strings[i].offset);
|
||||
lang->header.strings[i].length = le32toh(lang->header.strings[i].length);
|
||||
}
|
||||
|
||||
lang->chunksOffset = zip_ftell(lang->zip);
|
||||
if(lang->chunksOffset <= 0) {
|
||||
zip_fclose(lang->zip);
|
||||
|
||||
@@ -55,6 +55,9 @@ errorret_t assetMapChunkHandler(assetcustom_t custom) {
|
||||
errorThrow("Failed to read chunk asset header.");
|
||||
}
|
||||
|
||||
// Fix endianess if necessary
|
||||
header.tileCount = le32toh(header.tileCount);
|
||||
|
||||
if(header.tileCount != CHUNK_TILE_COUNT) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow(
|
||||
@@ -107,6 +110,9 @@ errorret_t assetMapChunkHandler(assetcustom_t custom) {
|
||||
errorThrow("Failed to read chunk model header.");
|
||||
}
|
||||
|
||||
// Fix endianess if necessary
|
||||
modelHeader.vertexCount = le32toh(modelHeader.vertexCount);
|
||||
|
||||
if(
|
||||
vertexIndex + modelHeader.vertexCount >
|
||||
CHUNK_VERTEX_COUNT_MAX
|
||||
|
||||
@@ -15,6 +15,10 @@ errorret_t assetPaletteImageLoad(void *data, void *output) {
|
||||
|
||||
assetpaletteimage_t *assetData = (assetpaletteimage_t *)data;
|
||||
texture_t *texture = (texture_t *)output;
|
||||
|
||||
// Fix endian
|
||||
assetData->width = le32toh(assetData->width);
|
||||
assetData->height = le32toh(assetData->height);
|
||||
|
||||
textureInit(
|
||||
texture,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "error/error.h"
|
||||
#include "duskdefs.h"
|
||||
#include <zip.h>
|
||||
#include <lua.h>
|
||||
#include "script/scriptcontext.h"
|
||||
|
||||
#define ASSET_SCRIPT_BUFFER_SIZE 1024
|
||||
|
||||
|
||||
@@ -6,13 +6,17 @@
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
#if DOLPHIN
|
||||
#include "display/display.h"
|
||||
|
||||
static char_t DEBUG_ERROR_BUFFER[16*1024] = {0};
|
||||
#endif
|
||||
|
||||
void debugPrint(const char_t *message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
vprintf(message, args);
|
||||
va_end(args);
|
||||
fflush(stdout);
|
||||
|
||||
#if PSP
|
||||
FILE *file = fopen("ms0:/PSP/GAME/Dusk/debug.log", "a");
|
||||
@@ -22,5 +26,70 @@ void debugPrint(const char_t *message, ...) {
|
||||
va_end(args);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
#elif DOLPHIN
|
||||
// append to error buffer
|
||||
size_t start = strlen(DEBUG_ERROR_BUFFER);
|
||||
va_start(args, message);
|
||||
vsnprintf(
|
||||
DEBUG_ERROR_BUFFER + start,
|
||||
sizeof(DEBUG_ERROR_BUFFER) - start,
|
||||
message,
|
||||
args
|
||||
);
|
||||
va_end(args);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void debugFlush() {
|
||||
#if PSP
|
||||
// No buffering, so nothing to flush
|
||||
#elif DOLPHIN
|
||||
// Either create graphics, or hijack the displays' graphics.
|
||||
void *xfb = NULL;
|
||||
GXRModeObj *rmode = NULL;
|
||||
void *framebuffer;
|
||||
|
||||
if(DISPLAY.frameBuffer[0]) {
|
||||
console_init(
|
||||
DISPLAY.frameBuffer[0],
|
||||
20,
|
||||
20,
|
||||
DISPLAY.screenMode->fbWidth,
|
||||
DISPLAY.screenMode->xfbHeight,
|
||||
DISPLAY.screenMode->fbWidth * VI_DISPLAY_PIX_SZ
|
||||
);
|
||||
} else {
|
||||
VIDEO_Init();
|
||||
rmode = VIDEO_GetPreferredMode(NULL);
|
||||
framebuffer = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
|
||||
console_init(
|
||||
framebuffer,
|
||||
20,
|
||||
20,
|
||||
rmode->fbWidth,
|
||||
rmode->xfbHeight,
|
||||
rmode->fbWidth*VI_DISPLAY_PIX_SZ
|
||||
);
|
||||
VIDEO_Configure(rmode);
|
||||
VIDEO_SetNextFramebuffer(framebuffer);
|
||||
VIDEO_SetBlack(FALSE);
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
|
||||
}
|
||||
|
||||
// Printf
|
||||
printf("SOB\n");
|
||||
printf(DEBUG_ERROR_BUFFER);
|
||||
printf("\nEOB.");
|
||||
|
||||
while(SYS_MainLoop()) {
|
||||
VIDEO_WaitVSync();
|
||||
}
|
||||
#else
|
||||
fflush(stdout);
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -14,4 +14,9 @@
|
||||
* @param message The message format string.
|
||||
* @param ... Additional arguments for the format string.
|
||||
*/
|
||||
void debugPrint(const char_t *message, ...);
|
||||
void debugPrint(const char_t *message, ...);
|
||||
|
||||
/**
|
||||
* Flushes the debug output buffer.
|
||||
*/
|
||||
void debugFlush();
|
||||
@@ -38,6 +38,15 @@ elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
DISPLAY_HEIGHT=272
|
||||
DISPLAY_SIZE_DYNAMIC=0
|
||||
)
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
DISPLAY_WINDOW_WIDTH_DEFAULT=640
|
||||
DISPLAY_WINDOW_HEIGHT_DEFAULT=480
|
||||
DISPLAY_WIDTH=640
|
||||
DISPLAY_HEIGHT=480
|
||||
DISPLAY_SIZE_DYNAMIC=0
|
||||
)
|
||||
endif()
|
||||
|
||||
dusk_run_python(
|
||||
|
||||
@@ -48,6 +48,97 @@ void cameraInitOrthographic(camera_t *camera) {
|
||||
void cameraPushMatrix(camera_t *camera) {
|
||||
assertNotNull(camera, "Not a camera component");
|
||||
|
||||
#if DOLPHIN
|
||||
Mtx44 guProjection;
|
||||
Mtx guView;
|
||||
Mtx modelView;
|
||||
|
||||
switch(camera->projType) {
|
||||
case CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC:
|
||||
guOrtho(
|
||||
guProjection,
|
||||
camera->orthographic.left,
|
||||
camera->orthographic.right,
|
||||
camera->orthographic.bottom,
|
||||
camera->orthographic.top,
|
||||
camera->nearClip,
|
||||
camera->farClip
|
||||
);
|
||||
break;
|
||||
|
||||
case CAMERA_PROJECTION_TYPE_PERSPECTIVE:
|
||||
guPerspective(
|
||||
guProjection,
|
||||
// FOV is in degrees.
|
||||
camera->perspective.fov * (180.0f / GLM_PIf),
|
||||
(float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND) /
|
||||
(float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND),
|
||||
camera->nearClip,
|
||||
camera->farClip
|
||||
);
|
||||
break;
|
||||
|
||||
case CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED:
|
||||
assertUnreachable("Flipped perspective not implemented on Dolphin");
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Invalid camera projection type");
|
||||
}
|
||||
|
||||
switch(camera->viewType) {
|
||||
case CAMERA_VIEW_TYPE_LOOKAT:
|
||||
guVector eye = {
|
||||
camera->lookat.position[0],
|
||||
camera->lookat.position[1],
|
||||
camera->lookat.position[2]
|
||||
};
|
||||
guVector up = {
|
||||
camera->lookat.up[0],
|
||||
camera->lookat.up[1],
|
||||
camera->lookat.up[2]
|
||||
};
|
||||
guVector look = {
|
||||
camera->lookat.target[0],
|
||||
camera->lookat.target[1],
|
||||
camera->lookat.target[2]
|
||||
};
|
||||
guLookAt(guView, &eye, &up, &look);
|
||||
break;
|
||||
|
||||
case CAMERA_VIEW_TYPE_MATRIX:
|
||||
assertUnreachable("Matrix camera not implemented");
|
||||
break;
|
||||
|
||||
case CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT:
|
||||
assertUnreachable("Pixel perfect camera not implemented");
|
||||
break;
|
||||
|
||||
case CAMERA_VIEW_TYPE_2D:
|
||||
assertUnreachable("2D camera not implemented");
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Invalid camera view type");
|
||||
}
|
||||
|
||||
// Set Projection Matrix
|
||||
GX_LoadProjectionMtx(
|
||||
guProjection,
|
||||
camera->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC ?
|
||||
GX_ORTHOGRAPHIC :
|
||||
GX_PERSPECTIVE
|
||||
);
|
||||
|
||||
// Set view and model matrix. Dunno how I'll handle models but whatever.
|
||||
guMtxIdentity(modelView);
|
||||
guMtxTransApply(modelView, modelView, 0.0F, 0.0F, 0.0F);
|
||||
guMtxConcat(guView,modelView,modelView);
|
||||
GX_LoadPosMtxImm(modelView, GX_PNMTX0);
|
||||
|
||||
return;
|
||||
#endif
|
||||
|
||||
mat4 projection;
|
||||
mat4 view;
|
||||
|
||||
|
||||
@@ -15,10 +15,19 @@
|
||||
#include "ui/ui.h"
|
||||
#include "debug/debug.h"
|
||||
#include "display/text.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
display_t DISPLAY;
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
|
||||
display_t DISPLAY = { 0 };
|
||||
|
||||
errorret_t displayInit(void) {
|
||||
memoryZero(&DISPLAY, sizeof(DISPLAY));
|
||||
|
||||
#if DISPLAY_SDL2
|
||||
uint32_t flags = SDL_INIT_VIDEO;
|
||||
#if INPUT_GAMEPAD == 1
|
||||
@@ -69,6 +78,68 @@ errorret_t displayInit(void) {
|
||||
glEnableClientState(GL_COLOR_ARRAY);// To confirm: every frame on PSP?
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
#elif DOLPHIN
|
||||
VIDEO_Init();
|
||||
DISPLAY.screenMode = VIDEO_GetPreferredMode(NULL);
|
||||
DISPLAY.frameBuffer[0] = MEM_K0_TO_K1(
|
||||
SYS_AllocateFramebuffer(DISPLAY.screenMode)
|
||||
);
|
||||
DISPLAY.frameBuffer[1] = MEM_K0_TO_K1(
|
||||
SYS_AllocateFramebuffer(DISPLAY.screenMode)
|
||||
);
|
||||
VIDEO_Configure(DISPLAY.screenMode);
|
||||
|
||||
VIDEO_SetNextFramebuffer(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer]);
|
||||
// VIDEO_SetPostRetraceCallback(copy_buffers);
|
||||
VIDEO_SetBlack(FALSE);
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
if(DISPLAY.screenMode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
|
||||
|
||||
DISPLAY.fifoBuffer = memalign(32, DISPLAY_FIFO_SIZE);
|
||||
memoryZero(DISPLAY.fifoBuffer, DISPLAY_FIFO_SIZE);
|
||||
|
||||
GX_Init(DISPLAY.fifoBuffer, DISPLAY_FIFO_SIZE);
|
||||
|
||||
// This seems to be mostly related to interlacing vs progressive
|
||||
GX_SetViewport(
|
||||
0, 0,
|
||||
DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight,
|
||||
0, 1
|
||||
);
|
||||
float_t yscale = GX_GetYScaleFactor(
|
||||
DISPLAY.screenMode->efbHeight, DISPLAY.screenMode->xfbHeight
|
||||
);
|
||||
uint32_t xfbHeight = GX_SetDispCopyYScale(yscale);
|
||||
GX_SetScissor(
|
||||
0, 0,
|
||||
DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight
|
||||
);
|
||||
GX_SetDispCopySrc(
|
||||
0, 0,
|
||||
DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight
|
||||
);
|
||||
GX_SetDispCopyDst(DISPLAY.screenMode->fbWidth, xfbHeight);
|
||||
GX_SetCopyFilter(
|
||||
DISPLAY.screenMode->aa,
|
||||
DISPLAY.screenMode->sample_pattern,
|
||||
GX_TRUE,
|
||||
DISPLAY.screenMode->vfilter
|
||||
);
|
||||
GX_SetFieldMode(
|
||||
DISPLAY.screenMode->field_rendering,
|
||||
(
|
||||
(DISPLAY.screenMode->viHeight == 2 * DISPLAY.screenMode->xfbHeight) ?
|
||||
GX_ENABLE :
|
||||
GX_DISABLE
|
||||
)
|
||||
);
|
||||
|
||||
// Setup cull modes
|
||||
GX_SetCullMode(GX_CULL_NONE);
|
||||
GX_CopyDisp(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer], GX_TRUE);
|
||||
GX_SetDispCopyGamma(GX_GM_1_0);
|
||||
#endif
|
||||
|
||||
quadInit();
|
||||
@@ -110,6 +181,10 @@ errorret_t displayUpdate(void) {
|
||||
}
|
||||
|
||||
SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext);
|
||||
|
||||
#elif DOLPHIN
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
// Reset state
|
||||
@@ -125,7 +200,7 @@ errorret_t displayUpdate(void) {
|
||||
errorChain(sceneRender());
|
||||
|
||||
// Render UI
|
||||
uiRender();
|
||||
// uiRender();
|
||||
|
||||
// Finish up
|
||||
screenUnbind();
|
||||
@@ -133,12 +208,22 @@ errorret_t displayUpdate(void) {
|
||||
|
||||
#if DISPLAY_SDL2
|
||||
SDL_GL_SwapWindow(DISPLAY.window);
|
||||
#endif
|
||||
|
||||
GLenum err;
|
||||
while((err = glGetError()) != GL_NO_ERROR) {
|
||||
debugPrint("GL Error: %d\n", err);
|
||||
}
|
||||
GLenum err;
|
||||
while((err = glGetError()) != GL_NO_ERROR) {
|
||||
debugPrint("GL Error: %d\n", err);
|
||||
}
|
||||
#elif DOLPHIN
|
||||
GX_DrawDone();
|
||||
|
||||
DISPLAY.whichFrameBuffer ^= 1;
|
||||
GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
|
||||
GX_SetColorUpdate(GX_TRUE);
|
||||
GX_CopyDisp(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer], GX_TRUE);
|
||||
VIDEO_SetNextFramebuffer(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer]);
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
#endif
|
||||
|
||||
// For now, we just return an OK error.
|
||||
errorOk();
|
||||
|
||||
@@ -15,6 +15,13 @@ typedef struct {
|
||||
#if DISPLAY_SDL2
|
||||
SDL_Window *window;
|
||||
SDL_GLContext glContext;
|
||||
|
||||
#elif DOLPHIN
|
||||
void *frameBuffer[2];// Double-Bufferred
|
||||
int whichFrameBuffer;
|
||||
GXRModeObj *screenMode;
|
||||
void *fifoBuffer;
|
||||
|
||||
#endif
|
||||
} display_t;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
#if DISPLAY_SDL2
|
||||
#include <SDL2/SDL.h>
|
||||
@@ -17,6 +18,9 @@
|
||||
#ifndef DISPLAY_SIZE_DYNAMIC
|
||||
#define DISPLAY_SIZE_DYNAMIC 1
|
||||
#endif
|
||||
#elif DOLPHIN
|
||||
// Dolphin.
|
||||
#define DISPLAY_FIFO_SIZE (256*1024)
|
||||
#else
|
||||
#error "Need to specify display backend."
|
||||
#endif
|
||||
|
||||
@@ -68,6 +68,13 @@ int32_t frameBufferGetWidth(const framebuffer_t *framebuffer) {
|
||||
}
|
||||
|
||||
return framebuffer->texture.width;
|
||||
|
||||
#elif DOLPHIN
|
||||
return DISPLAY.screenMode->fbWidth;
|
||||
|
||||
#else
|
||||
#error "Unsupported DISPLAY_TYPE."
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -84,15 +91,19 @@ int32_t frameBufferGetHeight(const framebuffer_t *framebuffer) {
|
||||
}
|
||||
|
||||
return framebuffer->texture.height;
|
||||
|
||||
#elif DOLPHIN
|
||||
return DISPLAY.screenMode->efbHeight;
|
||||
|
||||
#else
|
||||
#error "Unsupported DISPLAY_TYPE."
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void frameBufferBind(const framebuffer_t *framebuffer) {
|
||||
if(framebuffer == NULL) {
|
||||
#if DISPLAY_SDL2
|
||||
frameBufferBind(&FRAMEBUFFER_BACKBUFFER);
|
||||
#endif
|
||||
|
||||
frameBufferBind(&FRAMEBUFFER_BACKBUFFER);
|
||||
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
|
||||
return;
|
||||
}
|
||||
@@ -117,6 +128,18 @@ void frameBufferBind(const framebuffer_t *framebuffer) {
|
||||
0, 0,
|
||||
frameBufferGetWidth(framebuffer), frameBufferGetHeight(framebuffer)
|
||||
);
|
||||
|
||||
#elif DOLPHIN
|
||||
GX_InvVtxCache();
|
||||
GX_InvalidateTexAll();
|
||||
|
||||
GX_SetViewport(
|
||||
0, 0,
|
||||
frameBufferGetWidth(framebuffer),
|
||||
frameBufferGetHeight(framebuffer),
|
||||
0, 1
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
FRAMEBUFFER_BOUND = framebuffer;
|
||||
@@ -141,6 +164,12 @@ void frameBufferClear(uint8_t flags, color_t color) {
|
||||
}
|
||||
|
||||
glClear(glFlags);
|
||||
#elif DOLPHIN
|
||||
GX_SetCopyClear(
|
||||
(GXColor){ color.r, color.g, color.b, color.a },
|
||||
GX_MAX_Z24
|
||||
);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ typedef struct {
|
||||
// OpenGL Framebuffer Object ID
|
||||
GLuint id;
|
||||
texture_t texture;
|
||||
#elif DOLPHIN
|
||||
// --- IGNORE ---
|
||||
uint8_t id;
|
||||
#else
|
||||
#error "Framebuffers not implemented on this platform."
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
#if DOLPHIN
|
||||
#include "display/texture.h"
|
||||
#endif
|
||||
|
||||
void meshInit(
|
||||
mesh_t *mesh,
|
||||
const meshprimitivetype_t primitiveType,
|
||||
@@ -69,6 +73,37 @@ void meshDraw(
|
||||
0,
|
||||
count
|
||||
);
|
||||
|
||||
#elif DOLPHIN
|
||||
// Prepare Vertex descriptor
|
||||
DCFlushRange(
|
||||
(void*)&mesh->vertices[offset],
|
||||
sizeof(meshvertex_t) * count
|
||||
);
|
||||
GX_ClearVtxDesc();// Just clears so may be un-needed?
|
||||
|
||||
GX_SetVtxDesc(GX_VA_POS, GX_INDEX16);
|
||||
GX_SetVtxDesc(GX_VA_CLR0, GX_INDEX16);
|
||||
GX_SetVtxDesc(GX_VA_TEX0, GX_INDEX16);
|
||||
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
|
||||
|
||||
const u8 stride = (u8)sizeof(meshvertex_t);
|
||||
GX_SetArray(GX_VA_POS, &mesh->vertices[offset].pos[0], stride);
|
||||
GX_SetArray(GX_VA_CLR0, &mesh->vertices[offset].color, stride);
|
||||
GX_SetArray(GX_VA_TEX0, &mesh->vertices[offset].uv[0], stride);
|
||||
|
||||
textureDolphinUploadTEV();
|
||||
|
||||
GX_Begin(mesh->primitiveType, GX_VTXFMT0, (uint16_t)count);
|
||||
for(u16 i = 0; i < (u16)count; ++i) {
|
||||
GX_Position1x16(i);
|
||||
GX_Color1x16(i);
|
||||
GX_TexCoord1x16(i);
|
||||
}
|
||||
GX_End();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ typedef enum {
|
||||
MESH_PRIMITIVE_TRIANGLES = GL_TRIANGLES,
|
||||
MESH_PRIMITIVE_LINES = GL_LINES,
|
||||
MESH_PRIMITIVE_POINTS = GL_POINTS,
|
||||
#elif DOLPHIN
|
||||
MESH_PRIMITIVE_TRIANGLES = GX_TRIANGLES,
|
||||
MESH_PRIMITIVE_LINES = GX_LINES,
|
||||
MESH_PRIMITIVE_POINTS = GX_POINTS,
|
||||
#endif
|
||||
} meshprimitivetype_t;
|
||||
|
||||
@@ -19,11 +23,9 @@ typedef enum {
|
||||
#define MESH_VERTEX_POS_SIZE 3
|
||||
|
||||
typedef struct {
|
||||
#if DISPLAY_SDL2
|
||||
color4b_t color;
|
||||
GLfloat uv[MESH_VERTEX_UV_SIZE];
|
||||
GLfloat pos[MESH_VERTEX_POS_SIZE];
|
||||
#endif
|
||||
color_t color;
|
||||
float uv[MESH_VERTEX_UV_SIZE];
|
||||
float pos[MESH_VERTEX_POS_SIZE];
|
||||
} meshvertex_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
|
||||
mesh_t QUAD_MESH_SIMPLE;
|
||||
meshvertex_t QUAD_MESH_SIMPLE_VERTICES[QUAD_VERTEX_COUNT] = {
|
||||
{ COLOR_WHITE_4B, { 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
|
||||
{ COLOR_WHITE_4B, { 1.0f, 0.0f }, { 1.0f, 0.0f, 0.0f } },
|
||||
{ COLOR_WHITE_4B, { 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f } },
|
||||
|
||||
{ COLOR_WHITE_4B, { 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } },
|
||||
{ COLOR_WHITE_4B, { 1.0f, 1.0f }, { 1.0f, 1.0f, 0.0f } },
|
||||
{ COLOR_WHITE_4B, { 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f } }
|
||||
{ .color = COLOR_WHITE_4B, .uv = { 0.0f, 0.0f }, .pos = { 0.0f, 0.0f, 0.0f } },
|
||||
{ .color = COLOR_WHITE_4B, .uv = { 1.0f, 0.0f }, .pos = { 1.0f, 0.0f, 0.0f } },
|
||||
{ .color = COLOR_WHITE_4B, .uv = { 1.0f, 1.0f }, .pos = { 1.0f, 1.0f, 0.0f } },
|
||||
|
||||
{ .color = COLOR_WHITE_4B, .uv = { 0.0f, 0.0f }, .pos = { 0.0f, 0.0f, 0.0f } },
|
||||
{ .color = COLOR_WHITE_4B, .uv = { 1.0f, 1.0f }, .pos = { 1.0f, 1.0f, 0.0f } },
|
||||
{ .color = COLOR_WHITE_4B, .uv = { 0.0f, 1.0f }, .pos = { 0.0f, 1.0f, 0.0f } }
|
||||
};
|
||||
|
||||
void quadInit() {
|
||||
@@ -44,38 +44,48 @@ void quadBuffer(
|
||||
assertNotNull(vertices, "Vertices cannot be NULL");
|
||||
|
||||
// First triangle
|
||||
vertices[0] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ u0, v0 }, // UV
|
||||
{ minX, minY, z } // Position
|
||||
};
|
||||
vertices[1] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ u1, v0 }, // UV
|
||||
{ maxX, minY, z } // Position
|
||||
};
|
||||
vertices[2] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ u1, v1 }, // UV
|
||||
{ maxX, maxY, z } // Position
|
||||
};
|
||||
vertices[0].color = color;
|
||||
vertices[0].uv[0] = u0;
|
||||
vertices[0].uv[1] = v1;
|
||||
vertices[0].pos[0] = minX;
|
||||
vertices[0].pos[1] = maxY;
|
||||
vertices[0].pos[2] = z;
|
||||
|
||||
vertices[2].color = color;
|
||||
vertices[2].uv[0] = u0;
|
||||
vertices[2].uv[1] = v0;
|
||||
vertices[2].pos[0] = minX;
|
||||
vertices[2].pos[1] = minY;
|
||||
vertices[2].pos[2] = z;
|
||||
|
||||
vertices[1].color = color;
|
||||
vertices[1].uv[0] = u1;
|
||||
vertices[1].uv[1] = v0;
|
||||
vertices[1].pos[0] = maxX;
|
||||
vertices[1].pos[1] = minY;
|
||||
vertices[1].pos[2] = z;
|
||||
|
||||
// Second triangle
|
||||
vertices[3] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ u0, v0 }, // UV
|
||||
{ minX, minY, z } // Position
|
||||
};
|
||||
vertices[4] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ u1, v1 }, // UV
|
||||
{ maxX, maxY, z } // Position
|
||||
};
|
||||
vertices[5] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ u0, v1 }, // UV
|
||||
{ minX, maxY, z } // Position
|
||||
};
|
||||
vertices[3].color = color;
|
||||
vertices[3].uv[0] = u0;
|
||||
vertices[3].uv[1] = v1;
|
||||
vertices[3].pos[0] = minX;
|
||||
vertices[3].pos[1] = maxY;
|
||||
vertices[3].pos[2] = z;
|
||||
|
||||
vertices[5].color = color;
|
||||
vertices[5].uv[0] = u1;
|
||||
vertices[5].uv[1] = v0;
|
||||
vertices[5].pos[0] = maxX;
|
||||
vertices[5].pos[1] = minY;
|
||||
vertices[5].pos[2] = z;
|
||||
|
||||
vertices[4].color = color;
|
||||
vertices[4].uv[0] = u1;
|
||||
vertices[4].uv[1] = v1;
|
||||
vertices[4].pos[0] = maxX;
|
||||
vertices[4].pos[1] = maxY;
|
||||
vertices[4].pos[2] = z;
|
||||
}
|
||||
|
||||
void quadBuffer3D(
|
||||
@@ -93,36 +103,46 @@ void quadBuffer3D(
|
||||
assertNotNull(uvMax, "UV Max vector cannot be NULL");
|
||||
|
||||
// First triangle
|
||||
vertices[0] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ uvMin[0], uvMin[1] }, // UV
|
||||
{ min[0], min[1], min[2] } // Position
|
||||
};
|
||||
vertices[1] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ uvMax[0], uvMin[1] }, // UV
|
||||
{ max[0], min[1], min[2] } // Position
|
||||
};
|
||||
vertices[2] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ uvMax[0], uvMax[1] }, // UV
|
||||
{ max[0], max[1], min[2] } // Position
|
||||
};
|
||||
vertices[0].color = color;
|
||||
vertices[0].uv[0] = uvMin[0];
|
||||
vertices[0].uv[1] = uvMin[1];
|
||||
vertices[0].pos[0] = min[0];
|
||||
vertices[0].pos[1] = min[1];
|
||||
vertices[0].pos[2] = min[2];
|
||||
|
||||
vertices[1].color = color;
|
||||
vertices[1].uv[0] = uvMax[0];
|
||||
vertices[1].uv[1] = uvMin[1];
|
||||
vertices[1].pos[0] = max[0];
|
||||
vertices[1].pos[1] = min[1];
|
||||
vertices[1].pos[2] = min[2];
|
||||
|
||||
vertices[2].color = color;
|
||||
vertices[2].uv[0] = uvMax[0];
|
||||
vertices[2].uv[1] = uvMax[1];
|
||||
vertices[2].pos[0] = max[0];
|
||||
vertices[2].pos[1] = max[1];
|
||||
vertices[2].pos[2] = min[2];
|
||||
|
||||
// Second triangle
|
||||
vertices[3] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ uvMin[0], uvMin[1] }, // UV
|
||||
{ min[0], min[1], min[2] } // Position
|
||||
};
|
||||
vertices[4] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ uvMax[0], uvMax[1] }, // UV
|
||||
{ max[0], max[1], min[2] } // Position
|
||||
};
|
||||
vertices[5] = (meshvertex_t) {
|
||||
{ color.r, color.g, color.b, color.a }, // Color
|
||||
{ uvMin[0], uvMax[1] }, // UV
|
||||
{ min[0], max[1], min[2] } // Position
|
||||
};
|
||||
vertices[3].color = color;
|
||||
vertices[3].uv[0] = uvMin[0];
|
||||
vertices[3].uv[1] = uvMin[1];
|
||||
vertices[3].pos[0] = min[0];
|
||||
vertices[3].pos[1] = min[1];
|
||||
vertices[3].pos[2] = min[2];
|
||||
|
||||
vertices[4].color = color;
|
||||
vertices[4].uv[0] = uvMax[0];
|
||||
vertices[4].uv[1] = uvMax[1];
|
||||
vertices[4].pos[0] = max[0];
|
||||
vertices[4].pos[1] = max[1];
|
||||
vertices[4].pos[2] = min[2];
|
||||
|
||||
vertices[5].color = color;
|
||||
vertices[5].uv[0] = uvMin[0];
|
||||
vertices[5].uv[1] = uvMax[1];
|
||||
vertices[5].pos[0] = min[0];
|
||||
vertices[5].pos[1] = max[1];
|
||||
vertices[5].pos[2] = min[2];
|
||||
}
|
||||
@@ -9,9 +9,12 @@
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
meshvertex_t SPRITEBATCH_VERTICES[SPRITEBATCH_VERTEX_COUNT];
|
||||
spritebatch_t SPRITEBATCH;
|
||||
|
||||
void spriteBatchInit() {
|
||||
memoryZero(&SPRITEBATCH, sizeof(spritebatch_t));
|
||||
|
||||
SPRITEBATCH.spriteCount = 0;
|
||||
SPRITEBATCH.currentTexture = NULL;
|
||||
|
||||
@@ -19,7 +22,7 @@ void spriteBatchInit() {
|
||||
&SPRITEBATCH.mesh,
|
||||
MESH_PRIMITIVE_TRIANGLES,
|
||||
SPRITEBATCH_VERTEX_COUNT,
|
||||
&SPRITEBATCH.vertices[0]
|
||||
&SPRITEBATCH_VERTICES[0]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,7 +48,7 @@ void spriteBatchPush(
|
||||
}
|
||||
|
||||
quadBuffer(
|
||||
&SPRITEBATCH.vertices[SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT],
|
||||
&SPRITEBATCH_VERTICES[SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT],
|
||||
minX, minY, maxX, maxY,
|
||||
color,
|
||||
u0, v0, u1, v1
|
||||
@@ -72,7 +75,7 @@ void spriteBatchPush3D(
|
||||
}
|
||||
|
||||
quadBuffer3D(
|
||||
&SPRITEBATCH.vertices[SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT],
|
||||
&SPRITEBATCH_VERTICES[SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT],
|
||||
min, max, color, uv0, uv1
|
||||
);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "display/mesh/quad.h"
|
||||
#include "display/texture.h"
|
||||
|
||||
#define SPRITEBATCH_SPRITES_MAX 1
|
||||
#define SPRITEBATCH_SPRITES_MAX 32
|
||||
#define SPRITEBATCH_VERTEX_COUNT (SPRITEBATCH_SPRITES_MAX * QUAD_VERTEX_COUNT)
|
||||
|
||||
|
||||
@@ -17,9 +17,11 @@ typedef struct {
|
||||
mesh_t mesh;
|
||||
int32_t spriteCount;
|
||||
texture_t *currentTexture;
|
||||
meshvertex_t vertices[SPRITEBATCH_VERTEX_COUNT];
|
||||
} spritebatch_t;
|
||||
|
||||
// Have to define these seperately because of alignment in certain platforms.
|
||||
// (Looking at you Dolphin)/
|
||||
extern meshvertex_t SPRITEBATCH_VERTICES[SPRITEBATCH_VERTEX_COUNT];
|
||||
extern spritebatch_t SPRITEBATCH;
|
||||
|
||||
/**
|
||||
|
||||
@@ -144,10 +144,148 @@ void textureInit(
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
texture->ready = true;
|
||||
|
||||
#elif DOLPHIN
|
||||
texture->format = format;
|
||||
|
||||
switch(format) {
|
||||
case TEXTURE_FORMAT_RGBA:
|
||||
assertTrue(
|
||||
(width % 4) == 0 && (height % 4) == 0,
|
||||
"RGB5A3 requires w/h multiple of 4 (or pad)"
|
||||
);
|
||||
|
||||
// Convert to RGB5A3 format
|
||||
size_t rgbaSize = width * height * sizeof(u16);
|
||||
texture->rgba = (u16*)memalign(32, rgbaSize);
|
||||
assertNotNull(texture->rgba, "Failed to allocate texture RGBA data");
|
||||
|
||||
for(uint32_t y = 0; y < height; ++y) {
|
||||
for(uint32_t x = 0; x < width; ++x) {
|
||||
const int src = y * width + x;
|
||||
|
||||
const int tileX = x >> 2;
|
||||
const int tileY = y >> 2;
|
||||
const int tilesPerRow = width >> 2;
|
||||
const int tileIndex = tileY * tilesPerRow + tileX;
|
||||
const int tileBaseWords = tileIndex * 16;
|
||||
const int inTile = ((y & 3) << 2) + (x & 3);
|
||||
const int dest = tileBaseWords + inTile;
|
||||
|
||||
color4b_t col = data.rgba.colors[src];
|
||||
|
||||
u16 outCol;
|
||||
if(col.a < 255) {
|
||||
// 0AAA RRRR GGGG BBBB
|
||||
outCol = (
|
||||
(0u << 15) |
|
||||
((u16)(col.a >> 5) << 12) |
|
||||
((u16)(col.r >> 4) << 8) |
|
||||
((u16)(col.g >> 4) << 4) |
|
||||
((u16)(col.b >> 4) << 0)
|
||||
);
|
||||
} else {
|
||||
// 1RRRR RRGG GGGB BBBB
|
||||
outCol = (
|
||||
(1u << 15) |
|
||||
((u16)(col.r >> 3) << 10) |
|
||||
((u16)(col.g >> 3) << 5) |
|
||||
((u16)(col.b >> 3) << 0)
|
||||
);
|
||||
}
|
||||
texture->rgba[dest] = outCol;
|
||||
}
|
||||
}
|
||||
|
||||
DCFlushRange(texture->rgba, rgbaSize);
|
||||
GX_InitTexObj(
|
||||
&texture->texObj,
|
||||
texture->rgba,
|
||||
width, height,
|
||||
GX_TF_RGB5A3,
|
||||
GX_CLAMP, GX_CLAMP,
|
||||
GX_FALSE
|
||||
);
|
||||
|
||||
DCFlushRange(texture->rgba, rgbaSize);
|
||||
GX_InvalidateTexAll();
|
||||
|
||||
GX_InitTexObjLOD(
|
||||
&texture->texObj,
|
||||
GX_NEAR, GX_NEAR,
|
||||
0.0f, 0.0f, 0.0f,
|
||||
GX_FALSE,
|
||||
GX_FALSE,
|
||||
GX_ANISO_1
|
||||
);
|
||||
break;
|
||||
|
||||
case TEXTURE_FORMAT_ALPHA:
|
||||
assertTrue(
|
||||
(width % 4) == 0 && (height % 4) == 0,
|
||||
"GX_TF_I8 requires w/h multiple of 4 (or pad)"
|
||||
);
|
||||
|
||||
// 1 byte per pixel (I8), GX expects 4x4 tiled layout
|
||||
const size_t alphaSize = (size_t)width * (size_t)height;
|
||||
|
||||
texture->alpha = (u8*)memalign(32, alphaSize);
|
||||
assertNotNull(texture->alpha, "Failed to allocate alpha texture data");
|
||||
|
||||
const u32 tilesPerRow = ((u32)width) >> 3; // /8
|
||||
|
||||
for (u32 y = 0; y < (u32)height; ++y) {
|
||||
const u32 tileY = y >> 2; // /4
|
||||
const u32 inTileY = (y & 3) << 3; // (y%4)*8
|
||||
|
||||
for (u32 x = 0; x < (u32)width; ++x) {
|
||||
const u32 srcI = y * (u32)width + x;
|
||||
const u8 srcA = data.alpha.data[srcI]; // linear input
|
||||
|
||||
const u32 tileX = x >> 3; // /8
|
||||
const u32 tileIndex = tileY * tilesPerRow + tileX;
|
||||
|
||||
const u32 tileBase = tileIndex * 32; // 8*4*1 = 32 bytes per tile
|
||||
const u32 inTile = inTileY + (x & 7); // (y%4)*8 + (x%8)
|
||||
|
||||
texture->alpha[tileBase + inTile] = 0xFF - srcA;// Fixes inverted alpha.
|
||||
}
|
||||
}
|
||||
|
||||
// Flush CPU cache so GX sees the swizzled I8 texture data
|
||||
DCFlushRange(texture->alpha, alphaSize);
|
||||
|
||||
// Initialize GX texture object with swizzled data
|
||||
GX_InitTexObj(
|
||||
&texture->texObj,
|
||||
texture->alpha,
|
||||
width, height,
|
||||
GX_TF_I8,
|
||||
GX_CLAMP, GX_CLAMP,
|
||||
GX_FALSE
|
||||
);
|
||||
|
||||
GX_InitTexObjLOD(
|
||||
&texture->texObj,
|
||||
GX_NEAR, GX_NEAR,
|
||||
0.0f, 0.0f, 0.0f,
|
||||
GX_FALSE,
|
||||
GX_FALSE,
|
||||
GX_ANISO_1
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Unsupported texture format for Dolphin");
|
||||
break;
|
||||
}
|
||||
|
||||
texture->ready = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void textureBind(const texture_t *texture) {
|
||||
void textureBind(texture_t *texture) {
|
||||
if(TEXTURE_BOUND == texture) return;
|
||||
|
||||
if(texture == NULL) {
|
||||
@@ -158,10 +296,7 @@ void textureBind(const texture_t *texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
assertTrue(
|
||||
texture->id != 0,
|
||||
"Texture ID must not be 0"
|
||||
);
|
||||
assertTrue(texture->ready, "Texture ID must be ready");
|
||||
assertTrue(
|
||||
texture->width > 0 && texture->height > 0,
|
||||
"Texture width and height must be greater than 0"
|
||||
@@ -171,15 +306,143 @@ void textureBind(const texture_t *texture) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
#elif DOLPHIN
|
||||
GX_LoadTexObj(&texture->texObj, GX_TEXMAP0);
|
||||
#endif
|
||||
TEXTURE_BOUND = texture;
|
||||
}
|
||||
|
||||
void textureDispose(texture_t *texture) {
|
||||
assertNotNull(texture, "Texture cannot be NULL");
|
||||
assertTrue(texture->id != 0, "Texture ID must not be 0");
|
||||
assertTrue(texture->ready, "Texture ID must be ready");
|
||||
|
||||
if(TEXTURE_BOUND == texture) {
|
||||
textureBind(NULL);
|
||||
}
|
||||
|
||||
#if DISPLAY_SDL2
|
||||
glDeleteTextures(1, &texture->id);
|
||||
#elif DOLPHIN
|
||||
switch(texture->format) {
|
||||
case TEXTURE_FORMAT_RGBA:
|
||||
free(texture->rgba);
|
||||
break;
|
||||
|
||||
case TEXTURE_FORMAT_ALPHA:
|
||||
free(texture->alpha);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
memoryZero(texture, sizeof(texture_t));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if DOLPHIN
|
||||
void textureDolphinUploadTEV() {
|
||||
// Add channel for vertex color
|
||||
GX_SetNumChans(1);
|
||||
GX_SetChanCtrl(
|
||||
GX_COLOR0A0,// Store in color channel 0
|
||||
GX_DISABLE,// Lighting disabled
|
||||
GX_SRC_REG,// Ambient color?
|
||||
GX_SRC_VTX,// Material color?
|
||||
GX_LIGHTNULL,// Light Mask
|
||||
GX_DF_NONE,// Diffuse function
|
||||
GX_AF_NONE// Attenuation function
|
||||
);
|
||||
|
||||
if(!TEXTURE_BOUND) {
|
||||
GX_SetNumTexGens(0);
|
||||
GX_SetNumTevStages(1);
|
||||
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
|
||||
return;
|
||||
}
|
||||
|
||||
// One set of UVs
|
||||
GX_SetNumTexGens(1);
|
||||
GX_SetTexCoordGen(
|
||||
GX_TEXCOORD0,
|
||||
GX_TG_MTX2x4,
|
||||
GX_TG_TEX0,
|
||||
GX_IDENTITY
|
||||
);
|
||||
|
||||
// Basically the shader setup
|
||||
switch(TEXTURE_BOUND->format) {
|
||||
case TEXTURE_FORMAT_RGBA:
|
||||
// One TEV stage: vertex color * texture color
|
||||
GX_SetNumTevStages(1);
|
||||
GX_SetTevOrder(
|
||||
GX_TEVSTAGE0,
|
||||
GX_TEXCOORD0,
|
||||
GX_TEXMAP0,
|
||||
GX_COLOR0A0
|
||||
);
|
||||
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
|
||||
break;
|
||||
|
||||
case TEXTURE_FORMAT_ALPHA:
|
||||
// One TEV stage: vertex color * texture color
|
||||
GX_SetNumTevStages(1);
|
||||
GX_SetTevOrder(
|
||||
GX_TEVSTAGE0,
|
||||
GX_TEXCOORD0,
|
||||
GX_TEXMAP0,
|
||||
GX_COLOR0A0
|
||||
);
|
||||
|
||||
// Color = vertex color
|
||||
GX_SetTevColorIn(
|
||||
GX_TEVSTAGE0,
|
||||
GX_CC_RASC,
|
||||
GX_CC_ZERO,
|
||||
GX_CC_ZERO,
|
||||
GX_CC_ZERO
|
||||
);
|
||||
GX_SetTevColorOp(
|
||||
GX_TEVSTAGE0,
|
||||
GX_TEV_ADD,
|
||||
GX_TB_ZERO,
|
||||
GX_CS_SCALE_1,
|
||||
GX_TRUE,
|
||||
GX_TEVPREV
|
||||
);
|
||||
|
||||
// Alpha = vertex alpha * I8 intensity
|
||||
GX_SetTevAlphaIn(
|
||||
GX_TEVSTAGE0,
|
||||
GX_CA_RASA,
|
||||
GX_CA_ZERO,
|
||||
GX_CA_TEXA,
|
||||
GX_CA_ZERO
|
||||
);
|
||||
GX_SetTevAlphaOp(
|
||||
GX_TEVSTAGE0,
|
||||
GX_TEV_ADD,
|
||||
GX_TB_ZERO,
|
||||
GX_CS_SCALE_1,
|
||||
GX_TRUE,
|
||||
GX_TEVPREV
|
||||
);
|
||||
|
||||
GX_SetBlendMode(
|
||||
GX_BM_BLEND,
|
||||
GX_BL_SRCALPHA,
|
||||
GX_BL_INVSRCALPHA,
|
||||
GX_LO_CLEAR
|
||||
);
|
||||
|
||||
GX_SetColorUpdate(GX_TRUE);
|
||||
GX_SetAlphaUpdate(GX_TRUE);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Unknown texture format in meshDraw");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -14,14 +14,26 @@ typedef enum {
|
||||
TEXTURE_FORMAT_RGBA = GL_RGBA,
|
||||
TEXTURE_FORMAT_ALPHA = GL_ALPHA,
|
||||
TEXTURE_FORMAT_PALETTE = GL_COLOR_INDEX8_EXT,
|
||||
#elif DOLPHIN
|
||||
TEXTURE_FORMAT_RGBA = GX_TF_RGBA8,
|
||||
TEXTURE_FORMAT_ALPHA = GX_TF_A8,
|
||||
TEXTURE_FORMAT_PALETTE = GX_TF_CI8,
|
||||
#endif
|
||||
} textureformat_t;
|
||||
|
||||
typedef struct {
|
||||
#if DISPLAY_SDL2
|
||||
GLuint id;
|
||||
#elif DOLPHIN
|
||||
GXTexObj texObj;
|
||||
textureformat_t format;
|
||||
union {
|
||||
u16 *rgba;
|
||||
u8 *alpha;
|
||||
};
|
||||
#endif
|
||||
|
||||
bool_t ready;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
} texture_t;
|
||||
@@ -65,11 +77,18 @@ void textureInit(
|
||||
*
|
||||
* @param texture The texture to bind.
|
||||
*/
|
||||
void textureBind(const texture_t *texture);
|
||||
void textureBind(texture_t *texture);
|
||||
|
||||
/**
|
||||
* Disposes a texture.
|
||||
*
|
||||
* @param texture The texture to dispose.
|
||||
*/
|
||||
void textureDispose(texture_t *texture);
|
||||
void textureDispose(texture_t *texture);
|
||||
|
||||
#if DOLPHIN
|
||||
/**
|
||||
* Uploads the TEV settings for the currently bound texture.
|
||||
*/
|
||||
void textureDolphinUploadTEV();
|
||||
#endif
|
||||
@@ -29,6 +29,15 @@
|
||||
#include <psphprm.h>
|
||||
#endif
|
||||
|
||||
#if DOLPHIN
|
||||
#include <ogcsys.h>
|
||||
#include <gccore.h>
|
||||
#include <malloc.h>
|
||||
#include <sys/endian.h>
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
|
||||
typedef bool bool_t;
|
||||
typedef int int_t;
|
||||
typedef float float_t;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "script/scriptmanager.h"
|
||||
#include "debug/debug.h"
|
||||
#include "item/backpack.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
engine_t ENGINE;
|
||||
|
||||
@@ -37,7 +38,6 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
errorChain(uiInit());
|
||||
errorChain(mapInit());
|
||||
errorChain(sceneInit());
|
||||
|
||||
backpackInit();
|
||||
|
||||
// Run the initial script.
|
||||
@@ -50,6 +50,10 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
}
|
||||
|
||||
errorret_t engineUpdate(void) {
|
||||
#if DOLPHIN
|
||||
ENGINE.running = SYS_MainLoop();
|
||||
#endif
|
||||
|
||||
timeUpdate();
|
||||
inputUpdate();
|
||||
|
||||
|
||||
@@ -19,12 +19,19 @@ if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
||||
INPUT_MOUSE=1
|
||||
INPUT_GAMEPAD=1
|
||||
)
|
||||
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
INPUT_SDL2=1
|
||||
INPUT_GAMEPAD=1
|
||||
)
|
||||
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
INPUT_GAMEPAD=1
|
||||
)
|
||||
endif()
|
||||
|
||||
# CSV
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "util/string.h"
|
||||
#include "util/math.h"
|
||||
#include "time/time.h"
|
||||
#include "debug/debug.h"
|
||||
|
||||
input_t INPUT;
|
||||
|
||||
@@ -23,7 +24,13 @@ void inputInit(void) {
|
||||
INPUT.actions[i].currentValue = 0.0f;
|
||||
}
|
||||
|
||||
INPUT.deadzone = 0.2f;
|
||||
#if INPUT_GAMEPAD == 1
|
||||
INPUT.deadzone = 0.2f;
|
||||
#endif
|
||||
|
||||
#if DOLPHIN
|
||||
PAD_Init();
|
||||
#endif
|
||||
|
||||
eventInit(
|
||||
&INPUT.eventPressed, INPUT.pressedListeners, INPUT_LISTENER_PRESSED_MAX
|
||||
@@ -47,6 +54,19 @@ void inputUpdate(void) {
|
||||
#if INPUT_KEYBOARD == 1
|
||||
INPUT.keyboardState = SDL_GetKeyboardState(NULL);
|
||||
#endif
|
||||
#elif DOLPHIN
|
||||
PAD_ScanPads();
|
||||
|
||||
for(uint8_t i = 0; i < INPUT_PAD_COUNT; i++) {
|
||||
INPUT.padState[i] = PAD_ButtonsDown(i);
|
||||
INPUT.pads[i][INPUT_GAMEPAD_AXIS_LEFT_X] = INPUT_AXIS_FLOAT(PAD_StickX(i));
|
||||
INPUT.pads[i][INPUT_GAMEPAD_AXIS_LEFT_Y] = INPUT_AXIS_FLOAT(PAD_StickY(i));
|
||||
INPUT.pads[i][INPUT_GAMEPAD_AXIS_C_X] = INPUT_AXIS_FLOAT(PAD_SubStickX(i));
|
||||
INPUT.pads[i][INPUT_GAMEPAD_AXIS_C_Y] = INPUT_AXIS_FLOAT(PAD_SubStickY(i));
|
||||
INPUT.pads[i][INPUT_GAMEPAD_AXIS_TRIGGER_LEFT] = INPUT_AXIS_FLOAT(PAD_TriggerL(i));
|
||||
INPUT.pads[i][INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT] = INPUT_AXIS_FLOAT(PAD_TriggerR(i));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Reset all actions
|
||||
@@ -69,7 +89,7 @@ void inputUpdate(void) {
|
||||
|
||||
// For each button...
|
||||
inputbuttondata_t *cur = &INPUT_BUTTON_DATA[0];
|
||||
do {
|
||||
while(cur->name) {
|
||||
cur->lastVal = cur->curVal;
|
||||
cur->curVal = inputButtonGetValue(cur->button);
|
||||
|
||||
@@ -95,7 +115,7 @@ void inputUpdate(void) {
|
||||
#endif
|
||||
|
||||
cur++;
|
||||
} while(cur->name);
|
||||
}
|
||||
|
||||
// Do we need to fire off events?
|
||||
#if TIME_FIXED == 0
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
#include "inputaction.h"
|
||||
#include "event/event.h"
|
||||
|
||||
#if DOLPHIN
|
||||
#define INPUT_PAD_COUNT PAD_CHANMAX
|
||||
#define INPUT_AXIS_FLOAT(value) ((float_t)(value) / 128.0f)
|
||||
#endif
|
||||
|
||||
#define INPUT_LISTENER_PRESSED_MAX 16
|
||||
#define INPUT_LISTENER_RELEASED_MAX INPUT_LISTENER_PRESSED_MAX
|
||||
|
||||
@@ -37,6 +42,11 @@ typedef struct {
|
||||
#if INPUT_KEYBOARD == 1
|
||||
const uint8_t *keyboardState;
|
||||
#endif
|
||||
|
||||
#elif DOLPHIN
|
||||
int padState[INPUT_PAD_COUNT];
|
||||
float_t pads[INPUT_PAD_COUNT][INPUT_GAMEPAD_AXIS_COUNT];
|
||||
|
||||
#endif
|
||||
} input_t;
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ inputbuttondata_t INPUT_BUTTON_DATA[] = {
|
||||
{ .name = "lstick_negative_x", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTX, .positive = false } } },
|
||||
{ .name = "lstick_positive_y", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = true } } },
|
||||
{ .name = "lstick_negative_y", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = false } } },
|
||||
#else
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -172,6 +171,61 @@ inputbuttondata_t INPUT_BUTTON_DATA[] = {
|
||||
{ .name = "kp_enter", { .type = INPUT_BUTTON_TYPE_KEYBOARD, .scancode = SDL_SCANCODE_KP_ENTER } },
|
||||
{ .name = "kp_equals", { .type = INPUT_BUTTON_TYPE_KEYBOARD, .scancode = SDL_SCANCODE_KP_EQUALS } },
|
||||
#endif
|
||||
|
||||
#elif DOLPHIN
|
||||
#if WII
|
||||
#if INPUT_GAMEPAD == 1
|
||||
{ .name = "a", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_A } },
|
||||
{ .name = "b", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_B } },
|
||||
{ .name = "x", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_X } },
|
||||
{ .name = "y", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_Y } },
|
||||
{ .name = "start", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_START } },
|
||||
{ .name = "dpad_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_UP } },
|
||||
{ .name = "dpad_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_DOWN } },
|
||||
{ .name = "dpad_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_LEFT } },
|
||||
{ .name = "dpad_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_RIGHT } },
|
||||
{ .name = "l", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_L } },
|
||||
{ .name = "r", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_R } },
|
||||
{ .name = "z", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_Z } },
|
||||
{ .name = "menu", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_MENU } },
|
||||
{ .name = "lstick_positive_x", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_X, .positive = true } } },
|
||||
{ .name = "lstick_negative_x", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_X, .positive = false } } },
|
||||
{ .name = "lstick_positive_y", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = true } } },
|
||||
{ .name = "lstick_negative_y", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = false } } },
|
||||
{ .name = "cstick_positive_x", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_X, .positive = true } } },
|
||||
{ .name = "cstick_negative_x", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_X, .positive = false } } },
|
||||
{ .name = "cstick_positive_y", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_Y, .positive = true } } },
|
||||
{ .name = "cstick_negative_y", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_Y, .positive = false } } },
|
||||
{ .name = "ltrigger", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_TRIGGER_LEFT, .positive = true } } },
|
||||
{ .name = "rtrigger", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT, .positive = true } } },
|
||||
#endif
|
||||
#elif GAMECUBE
|
||||
#if INPUT_GAMEPAD == 1
|
||||
{ .name = "a", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_A } },
|
||||
{ .name = "b", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_B } },
|
||||
{ .name = "x", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_X } },
|
||||
{ .name = "y", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_Y } },
|
||||
{ .name = "start", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_START } },
|
||||
{ .name = "dpad_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_UP } },
|
||||
{ .name = "dpad_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_DOWN } },
|
||||
{ .name = "dpad_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_LEFT } },
|
||||
{ .name = "dpad_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_RIGHT } },
|
||||
{ .name = "l", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_L } },
|
||||
{ .name = "r", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_R } },
|
||||
{ .name = "z", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_Z } },
|
||||
{ .name = "menu", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_MENU } },
|
||||
{ .name = "lstick_positive_x", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_X, .positive = true } } },
|
||||
{ .name = "lstick_negative_x", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_X, .positive = false } } },
|
||||
{ .name = "lstick_positive_y", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = true } } },
|
||||
{ .name = "lstick_negative_y", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = false } } },
|
||||
{ .name = "cstick_positive_x", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_X, .positive = true } } },
|
||||
{ .name = "cstick_negative_x", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_X, .positive = false } } },
|
||||
{ .name = "cstick_positive_y", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_Y, .positive = true } } },
|
||||
{ .name = "cstick_negative_y", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_Y, .positive = false } } },
|
||||
{ .name = "ltrigger", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_TRIGGER_LEFT, .positive = true } } },
|
||||
{ .name = "rtrigger", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT, .positive = true } } },
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
{ .name = NULL }
|
||||
@@ -197,9 +251,9 @@ float_t inputButtonGetValue(const inputbutton_t button) {
|
||||
case INPUT_BUTTON_TYPE_KEYBOARD: {
|
||||
#if INPUT_SDL2 == 1
|
||||
return INPUT.keyboardState[button.scancode] ? 1.0f : 0.0f;
|
||||
#else
|
||||
return 0.0f;
|
||||
#endif
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -209,19 +263,29 @@ float_t inputButtonGetValue(const inputbutton_t button) {
|
||||
if(SDL_GameControllerGetButton(INPUT.controller, button.gpButton)) {
|
||||
return 1.0f;
|
||||
}
|
||||
#elif DOLPHIN
|
||||
if(INPUT.padState[0] & button.gpButton) return 1.0f;
|
||||
|
||||
#endif
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
case INPUT_BUTTON_TYPE_GAMEPAD_AXIS: {
|
||||
float_t value = 0.0f;
|
||||
|
||||
#if INPUT_SDL2 == 1
|
||||
Sint16 axis = SDL_GameControllerGetAxis(INPUT.controller, button.gpAxis.axis);
|
||||
if(!button.gpAxis.positive) axis = -axis;
|
||||
float_t value = (float_t)axis / 32767.0f;
|
||||
// Deadzone
|
||||
if(value < INPUT.deadzone) return 0.0f;
|
||||
return value;
|
||||
value = (float_t)axis / 32767.0f;
|
||||
|
||||
#elif DOLPHIN
|
||||
value = INPUT.pads[0][button.gpAxis.axis];
|
||||
|
||||
#endif
|
||||
|
||||
if(!button.gpAxis.positive) value = -value;
|
||||
if(value >= INPUT.deadzone) return value;
|
||||
return 0.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#if INPUT_SDL2 == 1
|
||||
#include <SDL2/SDL.h>
|
||||
#elif DOLPHIN
|
||||
|
||||
#else
|
||||
#error "No input backend defined"
|
||||
#endif
|
||||
@@ -26,6 +28,18 @@
|
||||
#if INPUT_SDL2 == 1
|
||||
typedef SDL_GameControllerButton inputgamepadbutton_t;
|
||||
typedef SDL_GameControllerAxis inputgamepadaxis_t;
|
||||
#elif DOLPHIN == 1
|
||||
typedef u16 inputgamepadbutton_t;
|
||||
typedef enum {
|
||||
INPUT_GAMEPAD_AXIS_LEFT_X,
|
||||
INPUT_GAMEPAD_AXIS_LEFT_Y,
|
||||
INPUT_GAMEPAD_AXIS_C_X,
|
||||
INPUT_GAMEPAD_AXIS_C_Y,
|
||||
INPUT_GAMEPAD_AXIS_TRIGGER_LEFT,
|
||||
INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT,
|
||||
|
||||
INPUT_GAMEPAD_AXIS_COUNT
|
||||
} inputgamepadaxis_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -35,6 +49,7 @@ typedef enum {
|
||||
#if INPUT_KEYBOARD == 1
|
||||
INPUT_BUTTON_TYPE_KEYBOARD,
|
||||
#endif
|
||||
|
||||
#if INPUT_GAMEPAD == 1
|
||||
INPUT_BUTTON_TYPE_GAMEPAD,
|
||||
INPUT_BUTTON_TYPE_GAMEPAD_AXIS,
|
||||
|
||||
@@ -14,7 +14,6 @@ localemanager_t LOCALE;
|
||||
|
||||
errorret_t localeManagerInit() {
|
||||
memoryZero(&LOCALE, sizeof(localemanager_t));
|
||||
// errorChain(localeManagerSetLocale(DUSK_LOCALE_EN_US));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
#include "engine/engine.h"
|
||||
#include "asset/asset.h"
|
||||
#include "util/string.h"
|
||||
#include "input/input.h"
|
||||
|
||||
|
||||
11
src/null.c
Normal file
11
src/null.c
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
// Empty C file for annoying platforms.
|
||||
void nothing(void) {
|
||||
|
||||
}
|
||||
@@ -76,7 +76,6 @@ errorret_t sceneSet(const char_t *script) {
|
||||
// Create a new script context.
|
||||
errorChain(scriptContextInit(&SCENE.scriptContext));
|
||||
errorChain(scriptContextExecFile(&SCENE.scriptContext, script));
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -87,6 +86,7 @@ void sceneDispose(void) {
|
||||
const char_t *strErr = lua_tostring(SCENE.scriptContext.luaState, -1);
|
||||
lua_pop(SCENE.scriptContext.luaState, 1);
|
||||
debugPrint("Failed to call function '%s': %s\n", "sceneDispose", strErr);
|
||||
debugFlush();
|
||||
}
|
||||
} else {
|
||||
lua_pop(SCENE.scriptContext.luaState, 1);
|
||||
|
||||
@@ -37,6 +37,7 @@ int moduleSysPrint(lua_State *L) {
|
||||
luaL_pushresult(&b);
|
||||
const char *msg = lua_tostring(L, -1);
|
||||
debugPrint("%s\n", msg);
|
||||
debugFlush();
|
||||
return 0; // no values returned to Lua
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ errorret_t scriptContextExec(scriptcontext_t *context, const char_t *script) {
|
||||
if(luaL_dostring(context->luaState, script) != LUA_OK) {
|
||||
const char_t *strErr = lua_tostring(context->luaState, -1);
|
||||
lua_pop(context->luaState, 1);
|
||||
errorThrow("Failed to execute Lua: ", strErr);
|
||||
errorThrow("Failed to execute Lua: %s", strErr);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
|
||||
@@ -21,4 +21,8 @@ elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
PUBLIC
|
||||
THREAD_PTHREAD=1
|
||||
)
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
)
|
||||
endif()
|
||||
@@ -21,4 +21,9 @@ elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
PUBLIC
|
||||
TIME_FIXED=1
|
||||
)
|
||||
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
|
||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
TIME_FIXED=1
|
||||
)
|
||||
endif()
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "display/spritebatch.h"
|
||||
#include "display/screen.h"
|
||||
|
||||
#include "debug/debug.h"
|
||||
|
||||
ui_t UI;
|
||||
|
||||
errorret_t uiInit(void) {
|
||||
|
||||
@@ -27,7 +27,6 @@ void memoryFree(void *ptr) {
|
||||
MEMORY_POINTERS_IN_USE--;
|
||||
}
|
||||
|
||||
|
||||
void memoryCopy(void *dest, const void *src, const size_t size) {
|
||||
assertNotNull(dest, "Cannot copy to NULL memory.");
|
||||
assertNotNull(src, "Cannot copy from NULL memory.");
|
||||
|
||||
Reference in New Issue
Block a user