Integrate all the progress into master #6

Merged
jaby merged 595 commits from ToolBox into main 2025-01-01 13:17:44 +00:00
361 changed files with 18105 additions and 6399 deletions

2
.gitattributes vendored
View File

@ -1,2 +1,4 @@
*.xa filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text

7
.gitignore vendored
View File

@ -1,9 +1,13 @@
# For now we ignore what is in root
**/build
**/bin
**/gcm.cache
**/iso/Info
/iso
# Custom configs should not be part of JabyEngine
**/config
.lfsconfig
*.d
@ -11,3 +15,6 @@
*.o
*.ii
*.xa
# TODO: Remove later
examples/PoolBox/assets/tmp.VAG

6
bin/convert2cdda.sh Normal file
View File

@ -0,0 +1,6 @@
#!/bin/bash
#Made possible by Cody the white tiger
# $1 => Input file
# $2 => Output file
ffmpeg -i $1 -sample_fmt s16 -ar 44100 $2

9
bin/run_pop_fe.sh Normal file
View File

@ -0,0 +1,9 @@
#!/bin/bash
#Made possible by Cody the white tiger
BASEDIR=$(dirname "$0")
cd $BASEDIR
source extern/py3venv/bin/activate
cd extern/pop-fe/
./pop-fe.py --title=$1 --ps1-newemu --cover=$2/Icon.png --pic0=$2/Title.png --pic1=$2/Background.png --ps3-pkg="${3%.*}.pkg" $3

View File

@ -1,19 +0,0 @@
@echo off
rem build_all [clean]
set build_type=build
IF NOT "%~1" == "" (
set build_type=%~1
)
mkdir bin\
cd src\Tools\
call build_all.bat update
call build_all.bat %build_type%
cd ..\Library\
call run_make.bat %build_type% release
cd ..\..\
PAUSE

View File

@ -0,0 +1,6 @@
#include "../dummy_default_config.hpp"
struct CustomConfiguration : public DefaultConfiguration {
};
#define __USE_DEBUG_COLOR__

48
config/Readme.md Normal file
View File

@ -0,0 +1,48 @@
# How to create custom configurations
1. Create folder with name of custom configuration
1. Add `jabyengine_custom_config.hpp` to folder
1. Follow [guidelines](#jabyengine_custom_confighpp)
1. Build JabyEngine and select your configuration
1. Build your application and select your configuration
## jabyengine_custom_config.hpp
### Default configuration file
```c++
// Fix IntelliSense
#include "../dummy_default_config.hpp"
// Overwrite various configurations
struct CustomConfiguration : public DefaultConfiguration {
};
// Define macros here
```
### `CustomConfiguration` options
When overriding an option make sure to mark the function as `override`
```c++
struct DefaultConfiguration {
struct BIOSFont {
// VRAM position and CLUT position to load the BIOS font too
static constexpr GPU::PositionU16 texture_load_pos();
static constexpr GPU::PositionU16 CLUT_load_pos();
};
// Offsets the default origin of the screen by the specified value
static constexpr auto DisplayDefaultOffset;
struct Periphery {
// Turns on the second controller port and enables multi tap support
static constexpr bool include_portB();
static constexpr bool use_multi_tap();
};
};
```
### `CustomConfiguration` macros
```c++
// Turns on debug information of the SPU MMU (on by default [for now])
#define __DEBUG_SPU_MMU__
// Turns on colored rectangles during boot (off by default)
#define __USE_DEBUG_COLOR__
// Turns on PS3 support (on by default)
#define __SUPPORT_PS3__
```

View File

@ -0,0 +1,7 @@
#pragma once
#ifdef __INTELLISENSE__
// This provides a dummy struct so IntelliSense is happy
struct DefaultConfiguration {
};
#endif //! __INTELLISENSE__

View File

@ -0,0 +1,6 @@
# Observed bugs
- [Observed bugs](#observed-bugs)
- [Deadlock](#deadlock)
## Deadlock
It was observed in `PoolBox` when loading the `FontCycler` overlay that a deadlock occurred. This error has not been observed since. The current theory is that accidentally an old save state in the emulator was loaded.

View File

@ -1,68 +1,40 @@
# Auto LBA
## Table of Contents
- [Auto LBA](#auto-lba)
- [In Code](#in-code)
- [Overlay](#overlay)
- [Main file](#main-file)
- [For CD generation](#for-cd-generation)
To support the `Auto LBA` feature changes need to be applied to the source files and the CD configuration file. The changes for the source files depend on if they are an Overlay or part of the main executable.
---
To support the `Auto LBA` feature changes need to be applied to the source files and the CD configuration file.
## In Code
To use the `Auto LBA` feature the LBAs first need to be defined in either an `enum` or `enum struct`. These need to fit a special pattern.
To use the `Auto LBA` feature the LBAs first need to be defined in either an `enum` or `enum struct`. These need to fit a special pattern. The usage of a `namespace` is recommended.
`__jabyengine_start_lba_request` needs to be the first entry while `__jabyengine_end_lba_request` needs to be the last. Each LBA entry needs to be declared with `__jabyengine_request_lba_for` followed by the name for the enum entry and the file path on the disk.
```c++
#include <PSX/AutoLBA/auto_lba.hpp>
namespace Assets {
enum LBA {
__jabyengine_start_lba_request
__jabyengine_request_lba_for(SYSTEM_CNF, "SYSTEM.CNF"),
__jabyengine_end_lba_request
};
```
### __Overlay__
For use with Overlays you need to include the related header file. You must place this include into the Namespace of your overlay to avoid name clash. Now the `lba` array is accessible.
```c++
namespace Overlay {
#include <PSX/Overlay/overlay_declaration.hpp>
// ...
printf("LBA: %i, Words: %i\n", lba[LBA::SYSTEM_CNF].lba, lba[LBA::SYSTEM_CNF].size_words);
// ...
__declare_overlay_header(execute, LBA);
}
```
### __Main file__
For use with the main file you need to include the header file and use the `__declare_lba_header` macro with the name of your enum to create the LBA area in any file. The header allows to access the `lba` array with your enum as the index.
```c++
#include <PSX/AutoLBA/auto_lba_declaration.hpp>
// ...
printf("LBA: %i, Words: %i\n", lba[LBA::SYSTEM_CNF].lba, lba[LBA::SYSTEM_CNF].size_words);
// ...
__declare_lba_header(LBA);
namespace {
void load() {
printf("LBA: %i, Words: %i\n", lba[LBA::SYSTEM_CNF].lba, lba[LBA::SYSTEM_CNF].size_words);
}
}
}
```
## For CD generation
To automatically fill the LBA values `psxcdgen_ex` needs to be used.
For the main file the special XML type `Main` needs to be used while specifing the LBA file being used.
For Overlays the instruction will follow...
The attribute `lba_source` automatically fills in the values. It can be used with the XML `Main` and `Overlay` tag.
```xml
<Track>
<File name = "SYSTEM.CNF">System.cnf</File>
<Main name="SCES_XXX.XX" lba_source="main.cpp">Application.psexe</Main>
<Main name = "%PSX_BOOT_FILE%" lba_source = "main.cpp">Application.psexe</Main>
<Overlay name = "OVL.BIN" lba_source = "state.cpp">Overlay.state</Overlay>
</Track>
```

View File

@ -1,7 +1,14 @@
# JabyEngine Documentation
## Table of Contents
- [JabyEngine Documentation](#jabyengine-documentation)
- [Features](#features)
---
- [Known limitations](#known-limitations)
- [Observed bugs](#observed-bugs)
## Features
- [Auto LBAs](./Features/auto_lba.md)
## Known limitations
- Insufficient documentation
## Observed bugs
- [Observed bugs](./Bugs/observed_bugs.md)

7
examples/PoolBox/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*.bin
*.cue
*.pkg
*.d
*.o
*.lba
**/bin

52
examples/PoolBox/Makefile Normal file
View File

@ -0,0 +1,52 @@
ARTIFACT = PoolBox
make_assets = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C assets
make_application = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C application
make_cd = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C iso
ifndef REGION
$(error REGION has to be set!)
endif
# Add regions on your own
# Extend them with what you need
ifeq ($(REGION),SCEE)
export PSX_TV_FORMAT=PAL
export PSX_LICENSE=LICENSEE
export PSX_BOOT_FILE=SLES_AAA.AA
endif
ifeq ($(REGION),SCEA)
export PSX_TV_FORMAT=NTSC
export PSX_LICENSE=LICENSEA
export PSX_BOOT_FILE=SLUS_AAA.AA
endif
ifeq ($(REGION),SCEI)
export PSX_TV_FORMAT=NTSC
export PSX_LICENSE=LICENSEJ
export PSX_BOOT_FILE=SLJS_AAA.AA
endif
ifndef PSX_TV_FORMAT
$(error PSX_TV_FORMAT has not be set! REGION not specified?)
endif
ifndef PSX_LICENSE
$(error PSX_LICENSE has not be set! REGION not specified?)
endif
all clean rebuild: |assets_$(MAKECMDGOALS) application_$(MAKECMDGOALS) cd_$(MAKECMDGOALS)
all_%: always
$(call make_assets,$*)
$(call make_application,$*)
$(call make_cd,$*)
assets_%: always
$(call make_assets,$*)
application_%: always
$(call make_application,$*)
cd_%: always
$(call make_cd,$*)
pkg_%: always
$(call make_cd,pkg_$*)
always: ;

View File

@ -0,0 +1,108 @@
{
"folders": [
{
"path": ".",
"name": "PoolBox"
}
],
"tasks": {
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"windows": { // v re-export for WSL v re-export for WSL
"command": "wsl make ${input:project}_${input:target} BUILD_PROFILE=${input:build profile} REGION=${input:region} CUSTOM_CONFIG=${input:custom config} PSX_LICENSE_PATH=$(wslpath ${env:PSX_LICENSE_PATH}) JABY_ENGINE_DIR=$(wslpath ${env:JABY_ENGINE_PATH})",
},
"linux": {
"command": "make ${input:project}_${input:target} BUILD_PROFILE=${input:build profile} REGION=${input:region} CUSTOM_CONFIG=${input:custom config}",
},
"group": {
"kind": "build",
"isDefault": true
},
"options": {
"env": {
"PATH": "${env:JABY_ENGINE_PATH}/bin;${env:PATH}"
}
}
},
{
"label": "read memory map",
"type": "shell",
"command": "psxreadmap.exe ${input:output memory map} application/bin/${input:tv format}/PSX-${input:build profile}/PoolBox.elf",
"problemMatcher": [],
"options": {
"env": {
"PATH": "${env:JABY_ENGINE_PATH}/bin;${env:PATH}"
}
}
}
],
"inputs": [
{
"id": "build profile",
"type": "pickString",
"options": ["debug", "release"],
"default": "release",
"description": "The build profile for PoolBox"
},
{
"id": "project",
"type": "pickString",
"options": ["all", "assets", "application", "cd", "pkg"],
"default": "all",
"description": "Project to build"
},
{
"id": "target",
"type": "pickString",
"options": ["all", "clean", "rebuild"],
"default": "all",
"description": "the build target"
},
{
"id": "region",
"type": "pickString",
"options": ["SCEE", "SCEA", "SCEI"],
"default": "SCEE",
"description": "Region profile to use"
},
{
"id": "custom config",
"type": "command",
"command": "shellCommand.execute",
"args": {
"command": "echo ^|^<Default^> && dir /b /a:d",
"cwd": "${env:JABY_ENGINE_PATH}/config",
"fieldSeparator": "|"
}
},
{
"id": "output memory map",
"type": "pickString",
"options": ["", "-o application/bin/PoolBox.map"],
"default": "",
"description": "Output a memory map"
}
]
},
"extensions": {
"recommendations": ["augustocdias.tasks-shell-input"]
},
"settings": {
"C_Cpp.default.includePath": [
"${env:JABY_ENGINE_PATH}/include",
"${env:JABY_ENGINE_PATH}/support/include"
],
"C_Cpp.default.compilerPath": "",
"C_Cpp.default.cStandard": "c17",
"C_Cpp.default.cppStandard": "c++20",
"C_Cpp.default.intelliSenseMode": "linux-gcc-x86",
"C_Cpp.default.compilerArgs": [
],
"C_Cpp.default.defines": [
"JABYENGINE_PAL"
],
}
}

View File

@ -0,0 +1,12 @@
OVERLAY_CONFIG = Overlays.json
include $(JABY_ENGINE_DIR)/mkfile/common/Wildcard.mk
SRCS = $(call rwildcard, src, c cpp)
INCLUDES += -I$(JABY_ENGINE_DIR)/support/include -I$(JABY_ENGINE_DIR)/include
CCFLAGS += -save-temps=obj
SUPPORT_LIBS += FontWriter
include $(JABY_ENGINE_DIR)/mkfile/Makefile
include $(JABY_ENGINE_DIR)/mkfile/PSEXETarget.mk

View File

@ -0,0 +1,22 @@
{
"slot_0": {
"bios_info": {
"pattern": "bin/*/src/Overlay/BIOSInfo/*.o"
},
"controller_tests": {
"pattern": "bin/*/src/Overlay/ControllerTest/*.o"
},
"gpu_tests": {
"pattern": "bin/*/src/Overlay/GPUTest/*.o"
},
"gte_tests": {
"pattern": "bin/*/src/Overlay/GTETest/*.o"
},
"font_cycler": {
"pattern": "bin/*/src/Overlay/FontCycler/*.o"
},
"screen_center": {
"pattern": "bin/*/src/Overlay/ScreenCenter/*.o"
}
}
}

View File

@ -0,0 +1,41 @@
#pragma once
#include <PSX/File/cd_file_types.hpp>
namespace Assets {
using namespace JabyEngine;
namespace Main {
struct ImageInfo {
SimpleTIM tim;
GPU::SizeI16 size;
};
static constexpr auto PacoTIM = SimpleTIM::create(896, 0, 960, 510);
static constexpr auto DoenerFishInfo = ImageInfo{
.tim = SimpleTIM::create(896 + 30, 0, 960 + 16, 510),
.size = GPU::SizeI16::create(128, 64)
};
namespace JabyLoader {
static constexpr auto TIMLoaction = SimpleTIM::create(PacoTIM.get_texture_x(), PacoTIM.get_texture_y() + 128, 960 + 48, 510);
static constexpr auto JabyFrame = GPU::AreaI16::create(0, 0, 32, 44);
static constexpr auto FontFrame = GPU::AreaI16::create(0, 45, 186, 32);
};
void load();
}
namespace Overlay {
void load_bios_info();
void load_controller_test();
void load_gpu_test();
void load_large_gpu_test();
void load_gte_test();
void load_font_cycler();
void load_screen_center();
}
namespace XAAudio {
void play_mix();
}
}

View File

@ -0,0 +1,10 @@
#pragma once
#include "../src/include/menu.hpp"
#include "../src/include/font_writer.hpp"
#include <PSX/GPU/gpu_types.hpp>
namespace Shared {
extern Menu::BackMenu back_menu;
extern JabyEngine::GPU::POLY_G4 background;
extern bool load_test;
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <PSX/File/cd_file_types.hpp>
enum struct FileType : JabyEngine::CDFileType_t {
Jingle,
};
struct CustomCDFileBuilder {
static constexpr JabyEngine::CDFile jingle(uint32_t sfx_id) {
// v we reload Paco
return JabyEngine::CDFile::custom(0, FileType::Jingle, sfx_id);
}
};

View File

@ -0,0 +1,26 @@
#include "custom_files.hpp"
#include <PSX/File/file_processor_helper.hpp>
#include <stdio.hpp>
namespace JabyEngine {
namespace FileProcessor {
struct JingleState {
uint32_t sfx_id;
};
static Progress parse_jingle(State::CDDataProcessor& data_proc, JingleState& jingle) {
SPU::voice[jingle.sfx_id].play();
return Progress::Done;
}
State create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload) {
switch(static_cast<FileType>(file_type)) {
case FileType::Jingle:
return State::from(JingleState{.sfx_id = payload.raw}, data_adr, parse_jingle);
default:
return FileProcessor::create(data_adr, Nothing());
}
}
}
}

View File

@ -0,0 +1,148 @@
#include "../../../include/asset_mgr.hpp"
#include "../../../include/shared.hpp"
#include <PSX/Auxiliary/types.hpp>
#include <PSX/Periphery/periphery.hpp>
#include <PSX/System/syscalls.hpp>
#include <PSX/Timer/frame_timer.hpp>
#include <FontWriter/fonts.hpp>
#include <string.hpp>
namespace BIOSInfo {
using namespace JabyEngine;
static constexpr auto TextOffset = Make::PositionI16(16, 16);
using NameColorPair = pair<const char*, GPU::Color24>;
struct FontSlider {
static constexpr auto MoveTimeout = static_cast<uint8_t>(300_ms);
static constexpr auto WaitTimeout = static_cast<uint8_t>(1000_ms);
int16_t count;
int16_t max;
int8_t delta;
IntervalTimer<uint8_t> wait_timer;
static FontSlider create_for(const FontWriter::FontInfo& font_info, const char* str) {
const auto max = static_cast<int16_t>((strlen(str)*font_info.get_kern_size().width) - GPU::Display::Width + (TextOffset.x << 1));
return FontSlider{
.count = 0,
.max = max,
.delta = static_cast<int8_t>(max < 0 ? 0 : font_info.get_kern_size().width/2),
.wait_timer = IntervalTimer<uint8_t>::create(FontSlider::MoveTimeout)
};
}
void advance() {
if(this->wait_timer.is_expired()) {
this->wait_timer.reset();
this->count += delta;
if(this->count <= 0 || this->count >= this->max) {
this->delta *= -1;
this->wait_timer.set_interval(FontSlider::WaitTimeout);
}
else {
this->wait_timer.set_interval(FontSlider::MoveTimeout);
}
}
}
};
static struct {
using BIOSStringOffset = const char*const (BIOS::Version::*);
const BIOSStringOffset bios_str_offset;
const char*const display_str;
FontSlider font_slider;
} BIOSStringInfo[] = {
{.bios_str_offset = &BIOS::Version::kernel_maker, .display_str = "Kernel-Maker"},
{.bios_str_offset = &BIOS::Version::version_str, .display_str = "Version"},
{.bios_str_offset = &BIOS::Version::gui_version, .display_str = "GUI-Version"},
{.bios_str_offset = &BIOS::Version::copyright, .display_str = "Copyright"},
};
static GPU::TILE::Linked border_tiles[2] = {
Make::TILE(Make::AreaI16(0, 0, TextOffset.x, GPU::Display::Height - 32), GPU::Color24::Black()).linked(),
Make::TILE(Make::AreaI16(GPU::Display::Width - TextOffset.x, 0, TextOffset.x, GPU::Display::Height - 32), GPU::Color24::Black()).linked()
};
static NameColorPair bios_name;
static FontSlider bios_name_slider;
static NameColorPair get_bios_name() {
switch(BIOS::version.type) {
case BIOS::Version::Devboard:
return {"DevBoard", GPU::Color24::Green()};
case BIOS::Version::PS1:
return {"PS1", GPU::Color24::Red()};
case BIOS::Version::PS2:
return {"PS2", GPU::Color24::Blue()};
case BIOS::Version::PS3:
return {"PS3", GPU::Color24::Yellow()};
case BIOS::Version::PSCompatible:
return {"Unkown PS compatible BIOS", GPU::Color24::Grey()};
case BIOS::Version::No$psx:
return {"NO$PSX", GPU::Color24::Purple()};
case BIOS::Version::XEBRA:
return {"XEBRA", GPU::Color24::Turquoise()};
default:
return {"Unkown", GPU::Color24::White()};
}
}
static void setup() {
bios_name = get_bios_name();
Shared::back_menu.reset();
for(auto& bios_str_info : BIOSStringInfo) {
bios_str_info.font_slider = FontSlider::create_for(FontWriter::BIOSFont::Info, BIOS::version.*(bios_str_info.bios_str_offset));
}
bios_name_slider = FontSlider::create_for(FontWriter::BIOSFont::Info, bios_name.first);
border_tiles[0].concat(border_tiles[1]);
}
static bool update_or_exit() {
static const auto move_cursor = [](JabyEngine::Cursor& cursor, int16_t dx, int16_t old_x) -> JabyEngine::Cursor& {
cursor.pos.x = (old_x - dx);
return cursor;
};
Periphery::query_controller();
if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) {
return true;
}
auto cursor = FontWriter::update(TextOffset);
FontWriter::bios_font_writer.write(cursor, "BIOS INFORMATION\n----------------\nDate (day/month/year):\n%i/%i/%i\n", BIOS::version.date.day, BIOS::version.date.month, BIOS::version.date.year);
const auto old_pos_x = cursor.pos.x;
for(auto& bios_str_info : BIOSStringInfo) {
bios_str_info.font_slider.advance();
FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "%s:\n", bios_str_info.display_str);
FontWriter::bios_font_writer.write(move_cursor(cursor, bios_str_info.font_slider.count, old_pos_x), "%s\n", BIOS::version.*(bios_str_info.bios_str_offset));
}
FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "BIOS Type:\n");
FontWriter::bios_font_writer.write(move_cursor(cursor, bios_name_slider.count, old_pos_x), "%s\n", bios_name.second, bios_name.first);
FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "----------------\n");
return false;
}
static void render() {
Shared::back_menu.render();
FontWriter::bios_font_writer.render();
GPU::render(border_tiles[0]);
}
void main() {
setup();
while(true) {
if(update_or_exit()) {
break;
}
GPU::swap_buffers_vsync(1);
render();
}
}
}

View File

@ -0,0 +1,110 @@
#include "include/controller_state.hpp"
#include <PSX/GPU/gpu.hpp>
#include <PSX/SPU/spu.hpp>
namespace ControllerTest {
using DigitalButton = Periphery::AnalogeController::Button;
using namespace JabyEngine;
static void set_active(GPU::SPRT_16::Linked& sprt, bool is_active) {
sprt->tex_offset.y = is_active ? 16 : 0;
if(is_active) {
SPU::voice[1].play_if_end();
}
}
static void set_active(GPU::POLY_FT4::Linked& poly, bool is_active) {
poly->tex_offset0.y = is_active ? 16 : 0;
poly->tex_offset1.y = is_active ? 16 : 0;
poly->tex_offset2.y = is_active ? 32 : 16;
poly->tex_offset3.y = is_active ? 32 : 16;
if(is_active) {
SPU::voice[1].play_if_end();
}
}
static const char* get_type_name(Periphery::ControllerType type) {
switch(type) {
case Periphery::ControllerType::Unkown:
return "Unkown";
case Periphery::ControllerType::Mouse:
return "Mouse";
case Periphery::ControllerType::NegCon:
return "NegCon";
case Periphery::ControllerType::HyperBlaster:
return "HyperBlaster";
case Periphery::ControllerType::Controller:
return "Digital Controller";
case Periphery::ControllerType::ArcadeFlightStick:
return "Flight Stick";
case Periphery::ControllerType::GCon:
return "GCon";
case Periphery::ControllerType::DualShock:
return "DualShock";
case Periphery::ControllerType::MultiTap:
return "MultiTap";
default:
return "???";
}
}
void ControllerState :: setup() {
for(size_t n = 0; n < 2; n++) {
GPU::LinkHelper::link_array(GPU::LinkHelper::link_array(&this->tex_page[n], this->buttons[n]), this->arrows[n]);
}
}
void ControllerState :: update(const Periphery::AnalogeController* controller, JabyEngine::FontWriter& font_writer) {
static const DigitalButton ButtonSprtMap[] = {
DigitalButton::Triangle, DigitalButton::Circle, DigitalButton::Cross, DigitalButton::Square,
DigitalButton::ST, DigitalButton::SEL, DigitalButton::L1, DigitalButton::L2, DigitalButton::R1, DigitalButton::R2,
DigitalButton::L3, DigitalButton::R3
};
static const DigitalButton ArrowPolyMap[] = {
DigitalButton::Up, DigitalButton::Right, DigitalButton::Down, DigitalButton::Left
};
auto& cur_button_sprts = this->buttons[GPU::update_id()];
auto& cur_arrow_poly = this->arrows[GPU::update_id()];
if(controller) {
for(size_t n = 0; n < sizeof(ButtonSprtMap)/sizeof(ButtonSprtMap[0]); n++) {
set_active(cur_button_sprts[n], controller->button.is_down(ButtonSprtMap[n]));
}
for(size_t n = 0; n < sizeof(ArrowPolyMap)/sizeof(ArrowPolyMap[0]); n++) {
set_active(cur_arrow_poly[n], controller->button.is_down(ArrowPolyMap[n]));
}
set_active(cur_button_sprts[12], controller->header.state == Periphery::RawController::State::Disconnected);
// Text stuff down here
const auto offset_point = cur_button_sprts[1]->position;
const auto left_stick = controller->get_left_stick_pos();
const auto right_stick = controller->get_right_stick_pos();
auto cursor = Cursor::create(offset_point.move(16, 0), 0);
font_writer.write(cursor, "Right: %i, %i\nLeft : %i, %i\n", right_stick.x, right_stick.y, left_stick.x, left_stick.y);
font_writer.write(cursor, "[%s]", get_type_name(static_cast<Periphery::ControllerType>(controller->get_type())));
}
else {
auto cursor = Cursor::create(Make::PositionI16(cur_arrow_poly[3]->vertex0.x, cur_button_sprts[0]->position.y), 0);
font_writer.write(cursor, "!!This Port is not\nenabled in JabyEngine!!", GPU::Color24::Red());
this->tex_page[GPU::update_id()].terminate();
}
}
void ControllerState :: render() {
GPU::render(this->tex_page[GPU::render_id()]);
}
}

View File

@ -0,0 +1,47 @@
#include "../../../include/shared.hpp"
#include "include/controller_state.hpp"
#include <PSX/Periphery/periphery.hpp>
namespace ControllerTest {
using namespace JabyEngine;
static auto controller_state0 = ControllerState::create(Make::PositionI16(0, 0));
static auto controller_state1 = ControllerState::create(Make::PositionI16(0, 76));
static void setup() {
Shared::back_menu.reset();
controller_state0.setup();
controller_state1.setup();
}
static bool update_or_exit() {
Periphery::query_controller();
if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) {
return true;
}
controller_state0.update(&Periphery::get_primary_controller_as<JabyEngine::Periphery::AnalogeController>(), FontWriter::bios_font_writer);
controller_state1.update(Periphery::PortCount > 1 ? &Periphery::get_controller_as<JabyEngine::Periphery::AnalogeController>(1, 0) : nullptr, FontWriter::bios_font_writer);
return false;
}
static void render() {
GPU::render(Shared::background);
controller_state0.render();
controller_state1.render();
FontWriter::bios_font_writer.render();
Shared::back_menu.render();
}
void main() {
setup();
while(true) {
if(update_or_exit()) {
break;
}
GPU::swap_buffers_vsync(1);
render();
}
}
}

View File

@ -0,0 +1,18 @@
#include "include/controller_test_assets.hpp"
#include <PSX/File/Processor/cd_file_processor.hpp>
#include <PSX/AutoLBA/auto_lba_declaration.hpp>
namespace ControllerTest {
using namespace JabyEngine;
enum LBA {
__jabyengine_start_lba_request
__jabyengine_request_lba_for(CONT, "ASSETS/CONT/CONT.IMG"),
__jabyengine_end_lba_request
};
__declare_lba_header(LBA);
CDFile Assets[1] = {
CDFileBuilder::simple_tim(LBA::CONT, ControllerButtonTIM),
};
}

View File

@ -0,0 +1,67 @@
#pragma once
#include "controller_test_assets.hpp"
#include <FontWriter/font_writer.hpp>
#include <PSX/GPU/make_gpu_primitives.hpp>
#include <PSX/Periphery/controller.hpp>
namespace ControllerTest {
using namespace JabyEngine;
class ControllerState {
private:
GPU::TexPage::Linked tex_page[2];
GPU::SPRT_16::Linked buttons[2][13];
GPU::POLY_FT4::Linked arrows[2][4];
public:
static constexpr ControllerState create(GPU::PositionI16 offset = Make::PositionI16(0, 0)) {
ControllerState state;
for(auto& tex_page : state.tex_page) {
tex_page = Make::TexPage(ControllerButtonTIM.get_texture_position(), GPU::TextureColorMode::clut4).linked();
}
for(auto& buttons : state.buttons) {
// Triangle
buttons[0] = Make::SPRT_16(Make::Vertex(71, 0).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(0, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// Circle
buttons[1] = Make::SPRT_16(Make::Vertex(82, 12).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(1, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// Cross
buttons[2] = Make::SPRT_16(Make::Vertex(71, 23).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(2, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// Square
buttons[3] = Make::SPRT_16(Make::Vertex(60, 11).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(3, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// Play
buttons[4] = Make::SPRT_16(Make::Vertex(51, 21).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(4, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// Block
buttons[5] = Make::SPRT_16(Make::Vertex(24, 21).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(5, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// L1
buttons[6] = Make::SPRT_16(Make::Vertex(7, 39).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(7, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// L2
buttons[7] = Make::SPRT_16(Make::Vertex(7, 49).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(8, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// R1
buttons[8] = Make::SPRT_16(Make::Vertex(71, 39).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(7, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// R2
buttons[9] = Make::SPRT_16(Make::Vertex(71, 49).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(8, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// L3
buttons[10] = Make::SPRT_16(Make::Vertex(24, 34).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(9, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// R3
buttons[11] = Make::SPRT_16(Make::Vertex(52, 34).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(9, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
// Connection Symbol
buttons[12] = Make::SPRT_16(Make::Vertex(37, 9).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(10, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked();
}
for(auto& arrows : state.arrows) {
arrows[0] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect( Make::AreaI16(Make::PositionI16( 7, 5).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked();
arrows[1] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect270(Make::AreaI16(Make::PositionI16(14, 11).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked();
arrows[2] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect180(Make::AreaI16(Make::PositionI16( 7, 17).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked();
arrows[3] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect90( Make::AreaI16(Make::PositionI16( 0, 11).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked();
}
return state;
}
void setup();
void update(const Periphery::AnalogeController* controller, JabyEngine::FontWriter& font_writer);
void render();
};
}

View File

@ -0,0 +1,8 @@
#pragma once
#include <PSX/File/cd_file_types.hpp>
namespace ControllerTest {
using namespace JabyEngine;
static constexpr auto ControllerButtonTIM = SimpleTIM::create(384, 0, 384, 511);
}

View File

@ -0,0 +1,78 @@
#include "../../../include/shared.hpp"
#include <PSX/GPU/gpu.hpp>
#include <PSX/Periphery/periphery.hpp>
namespace FontCycler {
using namespace JabyEngine;
static const char*const ASCII = "!\"#$%&'()*+,-./0\n123456789:;<=>?@\nABCDEFGHIJKLMNOP\nQRSTUVWXYZ[\\]^_`\nabcdefghijklmnop\nqrstuvwxyz{|}~\n";
static JabyEngine::FontWriter*const FontWriters[] = {
&FontWriter::bios_font_writer,
&FontWriter::new_font_writer,
};
static constexpr auto MaxFontSelector = (sizeof(FontWriters)/sizeof(FontWriters[0])) - 1;
static uint8_t font_selector = 0;
static void increment_font_selector() {
if(font_selector == MaxFontSelector) {
font_selector = 0;
}
else {
font_selector++;
}
}
static void decrement_font_selector() {
if(font_selector == 0) {
font_selector = MaxFontSelector;
}
else {
font_selector--;
}
}
static void setup() {
Shared::back_menu.reset();
font_selector = 0;
}
static bool update_or_exit() {
Periphery::query_controller();
if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) {
return true;
}
const auto& controller = Periphery::get_primary_controller_as<Periphery::GenericController>();
if(controller.button.went_up(Periphery::GenericController::Button::L1)) {
decrement_font_selector();
}
if(controller.button.went_up(Periphery::GenericController::Button::R1)) {
increment_font_selector();
}
auto cursor = FontWriter::update(Make::PositionI16(8, 8));
FontWriters[font_selector]->write(cursor, ASCII);
FontWriters[font_selector]->write(cursor, "\nPress L1 or R1 to cycle\nthrough fonts");
return false;
}
static void render() {
FontWriters[font_selector]->render();
Shared::back_menu.render();
}
void main() {
setup();
while(true) {
if(update_or_exit()) {
break;
}
GPU::swap_buffers_vsync(1);
render();
}
}
}

View File

@ -0,0 +1,174 @@
#include "../../../include/shared.hpp"
#include "include/gpu_test_assets.hpp"
#include <PSX/GPU/gpu.hpp>
#include <PSX/GPU/make_gpu_primitives.hpp>
#include <PSX/Periphery/periphery.hpp>
#include <PSX/Timer/high_res_timer.hpp>
namespace GPUTest {
using namespace JabyEngine;
// Some default values for the objects
static constexpr auto TriangleColor = GPU::Color24::from_rgb(0x0, 0xFF, 0xFF);
static constexpr auto TriangleArea = Make::AreaI16(Make::PositionI16(0, 0), Make::SizeI16(64, 64));
static constexpr auto TriangleTPage = Make::TPage(TexPageTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4);
static constexpr auto TriangleClut = Make::PageClut(TexPageTIM.get_clut_position());
static constexpr auto RectangleColor = GPU::Color24::from_rgb(0x80, 0x80, 0xFF);
static constexpr auto RectangleArea = Make::AreaI16(Make::PositionI16(0, TriangleArea.size.height), Make::SizeI16(80, 80));
static constexpr auto RectangleTPage = Make::TPage(IconTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4);
static constexpr auto RectangleClut = Make::PageClut(IconTIM.get_clut_position());
static constexpr auto LineColor = GPU::Color24::from_rgb(0xFF, 0x0, 0x0);
static constexpr const auto triangle1 = Make::POLY_F3({
Make::Vertex(TriangleArea.position.x, TriangleArea.position.y),
Make::Vertex(TriangleArea.size.width, TriangleArea.size.height),
Make::Vertex(TriangleArea.position.x, TriangleArea.size.height)
}, TriangleColor
);
static constexpr const auto triangle2 = Make::POLY_FT3({
Make::Vertex(TriangleArea.position.x, TriangleArea.position.y),
Make::Vertex(TriangleArea.size.width, TriangleArea.position.y),
Make::Vertex(TriangleArea.size.width, TriangleArea.size.height)
},{
// Texture
Make::PageOffset(TriangleArea.position.x, TriangleArea.position.y),
Make::PageOffset(TriangleArea.size.width, TriangleArea.position.y),
Make::PageOffset(TriangleArea.size.width, TriangleArea.size.height)
}, TriangleTPage, TriangleClut, GPU::Color24::Grey()
);
static constexpr const auto triangle3 = Make::POLY_G3({
{triangle1.vertex0.move(TriangleArea.size.width, 0), GPU::Color24::Red()},
{triangle1.vertex1.move(TriangleArea.size.width, 0), GPU::Color24::Green()},
{triangle1.vertex2.move(TriangleArea.size.width, 0), GPU::Color24::Blue()}}
);
static constexpr const auto triangle4 = Make::POLY_GT3({
{triangle2.vertex0.move(TriangleArea.size.width, 0), triangle2.tex_offset0, GPU::Color24::Red()},
{triangle2.vertex1.move(TriangleArea.size.width, 0), triangle2.tex_offset1, GPU::Color24::Blue()},
{triangle2.vertex2.move(TriangleArea.size.width, 0), triangle2.tex_offset2, GPU::Color24::Green()}},
TriangleTPage,
TriangleClut
);
static constexpr const auto rectangle1 = Make::POLY_F4(RectangleArea, RectangleColor);
static constexpr const auto rectangle2 = Make::POLY_FT4(Make::AreaI16(
RectangleArea.position.move(RectangleArea.size.width, 0), RectangleArea.size), Make::PageOffset(0, 0),
RectangleTPage,
RectangleClut,
GPU::Color24::Grey()
);
static constexpr const auto rectangle3 = Make::POLY_G4(
{RectangleArea.position.move(RectangleArea.size.width*2, 0), RectangleArea.size}, {
GPU::Color24::Red(),
GPU::Color24::Blue(),
GPU::Color24::Green(),
GPU::Color24::White()});
static constexpr const auto rectangle4 = Make::POLY_GT4(Make::AreaI16(
RectangleArea.position.move(RectangleArea.size.width*3, 0), RectangleArea.size), Make::PageOffset(0, 0),
RectangleTPage,
RectangleClut, {
GPU::Color24::Red(),
GPU::Color24::Blue(),
GPU::Color24::Green(),
GPU::Color24::White()}
);
static constexpr const auto rectangle5 = Make::POLY_GT4(Make::AreaI16(
RectangleArea.position.move(0, RectangleArea.size.height), RectangleArea.size), Make::PageOffset(0, 0),
RectangleTPage,
RectangleClut, {
GPU::Color24::Red(),
GPU::Color24::Blue(),
GPU::Color24::Green(),
GPU::Color24::White()}
).set_semi_transparent(true);
static constexpr const auto line1 = Make::LINE_F(LineColor,
Make::Vertex(0, 0),
Make::Vertex(GPU::Display::Width, GPU::Display::Height)
);
static constexpr const auto line2 = Make::LINE_F(LineColor.invert(),
Make::Vertex(0, 0),
Make::Vertex(16, 0),
Make::Vertex(16, 16),
Make::Vertex(0, 0)
);
static constexpr const auto line3 = Make::LINE_G(
GPU::ColorVertex{LineColor, Make::Vertex(GPU::Display::Width, 0)},
GPU::ColorVertex{LineColor.invert(), Make::Vertex(0, GPU::Display::Height)}
);
static constexpr const auto line4 = Make::LINE_G(
GPU::ColorVertex{GPU::Color24::Red(), Make::Vertex(0, 0)},
GPU::ColorVertex{GPU::Color24::Green(), Make::Vertex(0, 16)},
GPU::ColorVertex{GPU::Color24::Blue(), Make::Vertex(16, 16)},
GPU::ColorVertex{GPU::Color24::White(), Make::Vertex(0, 0)}
);
static constexpr const auto rect1 = Make::TILE(Make::AreaI16(Make::PositionI16(GPU::Display::Width - 32, GPU::Display::Height - 32), Make::SizeI16(32, 32)), GPU::Color24::Green());
static constexpr const auto rect2 = Make::TILE_16(Make::PositionI16(GPU::Display::Width - 16, GPU::Display::Height - 16), GPU::Color24::Blue());
static constexpr const auto rect3 = Make::TILE_8(Make::PositionI16(GPU::Display::Width - 8, GPU::Display::Height - 8), GPU::Color24::Yellow());
static constexpr const auto rect4 = Make::TILE_1(Make::PositionI16(GPU::Display::Width - 1, GPU::Display::Height - 1), GPU::Color24::Red());
static constexpr const auto texpage = Make::TexPage(TexPageTIM.get_texture_position(), GPU::TextureColorMode::clut4);
static constexpr const auto rect5 = Make::SPRT(Make::AreaI16(Make::PositionI16(0, GPU::Display::Height - 32), Make::SizeI16(32, 32)), {Make::PageOffset(0, 0), TriangleClut}, GPU::Color24::Green());
static constexpr const auto rect6 = Make::SPRT_16(Make::Vertex(0, GPU::Display::Height - 16), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Blue());
static constexpr const auto rect7 = Make::SPRT_8(Make::Vertex(0, GPU::Display::Height - 8), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Yellow());
static constexpr const auto rect8 = Make::SPRT_1(Make::Vertex(0, GPU::Display::Height - 1), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Red());
static auto rect9 = Make::SPRT(Make::AreaI16(Make::PositionI16(GPU::Display::Width/2, GPU::Display::Height/2), Make::SizeI16(32, 32)).centered(), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Grey()).linked();
static auto rect10 = Make::SPRT(Make::AreaI16(Make::PositionI16(GPU::Display::Width/2, GPU::Display::Height/2 - 32), Make::SizeI16(32, 32)).centered(), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Grey()).linked();
void main() {
rect9.concat(rect10);
Shared::back_menu.reset();
HighResTime::enable();
auto start_time = HighResTime::get_time_stamp();
auto time_passed = 0;
while(true) {
// Update Phase
Periphery::query_controller();
if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) {
break;
}
auto cursor = FontWriter::update(Make::PositionI16((GPU::Display::Width - 160)/2, GPU::Display::Height - 32));
FontWriter::bios_font_writer.write(cursor, "Time: %ims", GPU::Color24::Blue(), time_passed);
GPU::swap_buffers_vsync(1);
const auto end_time = HighResTime::get_time_stamp();
time_passed = start_time.milliseconds_to(end_time);
start_time = end_time;
GPU::render(triangle1);
GPU::render(triangle2);
GPU::render(triangle3);
GPU::render(triangle4);
GPU::render(rectangle1);
GPU::render(rectangle2);
GPU::render(rectangle3);
GPU::render(rectangle4);
GPU::render(rectangle5);
GPU::render(rect1);
GPU::render(rect2);
GPU::render(rect3);
GPU::render(rect4);
GPU::render(texpage);
GPU::render(rect5);
GPU::render(rect6);
GPU::render(rect7);
GPU::render(rect8);
GPU::render(line1);
GPU::render(line2);
GPU::render(line3);
GPU::render(line4);
GPU::render(rect9);
Shared::back_menu.render();
}
HighResTime::disable();
}
}

View File

@ -0,0 +1,60 @@
#include "include/gpu_test_assets.hpp"
#include <PSX/File/Processor/cd_file_processor.hpp>
#include <PSX/AutoLBA/auto_lba_declaration.hpp>
namespace GPUTest {
using namespace JabyEngine;
enum LBA {
__jabyengine_start_lba_request
__jabyengine_request_lba_for(TEX, "ASSETS/TEX.IMG"),
__jabyengine_request_lba_for(ICON, "ASSETS/ICON.IMG"),
__jabyengine_request_lba_for(ALL_THE_JABY, "ASSETS/ATJ.TIM"),
__jabyengine_end_lba_request
};
__declare_lba_header(LBA);
CDFile Assets[2] = {
CDFileBuilder::simple_tim(LBA::TEX, TexPageTIM),
CDFileBuilder::simple_tim(LBA::ICON, IconTIM),
};
CDFile LargeAssets[36] = {
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()),
};
}

View File

@ -0,0 +1,9 @@
#pragma once
#include <PSX/File/cd_file_types.hpp>
namespace GPUTest {
using namespace JabyEngine;
static constexpr auto TexPageTIM = SimpleTIM::create(384, 0, 384, 511);
static constexpr auto IconTIM = SimpleTIM::create(384, 256, 384, 510);
}

View File

@ -0,0 +1,166 @@
#include "../../../include/asset_mgr.hpp"
#include "../../../include/shared.hpp"
#include "include/GTE_Sprite.hpp"
#include "include/gte_test_assets.hpp"
#include <PSX/Periphery/periphery.hpp>
namespace GTETest {
using namespace JabyEngine;
using namespace GTETest;
namespace Jaby {
static constexpr auto AnimationTime = 250_ms;
static const struct {
gte_float scale_left;
gte_float scale_right;
} animation[] = {
{.scale_left = 1.0_gf, .scale_right = 1.0_gf},
{.scale_left = 1.0_gf, .scale_right = 1.0_gf},
{.scale_left = 1.2_gf, .scale_right = 1.5_gf},
{.scale_left = 1.5_gf, .scale_right = 1.2_gf},
{.scale_left = 1.2_gf, .scale_right = 1.5_gf},
{.scale_left = 1.5_gf, .scale_right = 1.2_gf},
{.scale_left = 1.8_gf, .scale_right = 2.3_gf},
{.scale_left = 2.3_gf, .scale_right = 1.8_gf},
{.scale_left = 1.8_gf, .scale_right = 2.3_gf},
{.scale_left = 2.3_gf, .scale_right = 1.8_gf},
{.scale_left = 3.2_gf, .scale_right = 4.5_gf},
{.scale_left = 4.5_gf, .scale_right = 3.2_gf},
{.scale_left = 3.2_gf, .scale_right = 4.5_gf},
{.scale_left = 4.5_gf, .scale_right = 3.2_gf},
{.scale_left = 1.8_gf, .scale_right = 2.3_gf},
{.scale_left = 2.3_gf, .scale_right = 1.8_gf},
{.scale_left = 1.8_gf, .scale_right = 2.3_gf},
{.scale_left = 2.3_gf, .scale_right = 1.8_gf},
{.scale_left = 1.2_gf, .scale_right = 1.5_gf},
{.scale_left = 1.5_gf, .scale_right = 1.2_gf},
{.scale_left = 1.2_gf, .scale_right = 1.5_gf},
{.scale_left = 1.5_gf, .scale_right = 1.2_gf},
};
static IntervalTimer<uint8_t> animation_timer;
static auto animation_id = 0;
static constexpr auto Position = Make::PositionI16(GPU::Display::Width - 64, GPU::Display::Height - 64);
static constexpr GTE_Sprite make_star_eye(GPU::PositionI16 pos) {
return GTE_Sprite::create(Make::POLY_FT4(
Make::AreaI16(pos, GPU::SizeI16(8, 8)),
JabySTARTim.get_page_offset_clut4().add(0, 64),
Make::TPage(JabySTARTim.get_texture_position(), GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4),
Make::PageClut(JabySTARTim.get_clut_position()),
GPU::Color24::Grey()
).linked());
}
static auto star_base = Make::SPRT(
Make::AreaI16(Position, Make::SizeI16(64, 64)),
Make::OffsetPageWithClut(JabySTARTim.get_page_offset_clut4(), Make::PageClut(JabySTARTim.get_clut_position()))
).linked();
static GTE_Sprite star_eyes[2] = {
make_star_eye(Position.add(11, 30)),
make_star_eye(Position.add(33, 31))
};
}
namespace Background {
static constexpr auto ColorBase = 0xC0;
static constexpr GPU::AreaI16 Area[2] = {
Make::AreaI16(-30, -30, 350, 350),
Make::AreaI16(0, 0, GPU::Display::Width, GPU::Display::Width),
};
static constexpr GPU::PositionI16 AreaPivot[2] = {
Make::PositionI16(Area[0].size.width/2, Area[0].size.height/2),
Make::PositionI16(Area[1].size.width/2, Area[1].size.height/2),
};
static GPU::POLY_G4 poly[2] = {
Make::POLY_G4(Area[0], {GPU::Color24::Blue(ColorBase), GPU::Color24::Red(ColorBase), GPU::Color24::Green(ColorBase), GPU::Color24::Purple(ColorBase)}),
Make::POLY_G4(Area[1], {GPU::Color24::Blue(ColorBase), GPU::Color24::Red(ColorBase), GPU::Color24::Green(ColorBase), GPU::Color24::Purple(ColorBase)}),
};
}
static auto doener_fish = GTE_Sprite::create(Make::POLY_FT4(
Make::AreaI16(Make::PositionI16(0, 0), Assets::Main::DoenerFishInfo.size),
Assets::Main::DoenerFishInfo.tim.get_page_offset_clut4(),
Make::TPage(Assets::Main::DoenerFishInfo.tim.get_texture_position(), GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4),
Make::PageClut(Assets::Main::DoenerFishInfo.tim.get_clut_position()),
GPU::Color24::Grey()
).linked());
static auto gbl_rotation = 0.0_deg;
static void setup() {
Jaby::star_base.concat(Jaby::star_eyes[0].display.concat(Jaby::star_eyes[1].display));
Jaby::star_eyes[0].scale = Jaby::animation[0].scale_right;
Jaby::star_eyes[1].scale = Jaby::animation[0].scale_left;
Jaby::animation_id = 1;
Jaby::animation_timer = IntervalTimer<uint8_t>::create(Jaby::AnimationTime);
doener_fish.area.position = GPU::PositionI16::create(100, 100);
Shared::back_menu.reset();
GTE::set_geom_offset(0, 0);
GTE::set_geom_screen(256);
}
static bool update_or_exit() {
Periphery::query_controller();
if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) {
return true;
}
if(Jaby::animation_timer.is_expired()) {
Jaby::star_eyes[0].scale = Jaby::animation[Jaby::animation_id].scale_right;
Jaby::star_eyes[1].scale = Jaby::animation[Jaby::animation_id].scale_left;
Jaby::animation_id = (Jaby::animation_id + 1)%(sizeof(Jaby::animation)/sizeof(Jaby::animation[0]));
Jaby::animation_timer.reset();
}
for(size_t n = 0; n < sizeof(Background::poly)/sizeof(Background::poly[0]); n++) {
auto matrix = [](size_t n) -> GTE::MATRIX {
auto matrix = GTE::MATRIX::translated(-Background::AreaPivot[n].x, -Background::AreaPivot[n].y);
matrix.rotate(0.0_deg, 0.0_deg, (n == 0) ? gbl_rotation : -gbl_rotation);
return matrix.translate(Background::Area[n].position.x + Background::AreaPivot[n].x, Background::Area[n].position.y + Background::AreaPivot[n].y);
}(n);
matrix.apply_to_area(Background::poly[n], Make::AreaI16(Make::PositionI16(), Background::Area[n].size));
}
const auto matrix = GTE::MATRIX::rotated(-gbl_rotation, gbl_rotation, -gbl_rotation);
doener_fish.apply(matrix);
Jaby::star_eyes[0].apply();
Jaby::star_eyes[1].apply();
doener_fish.angle += 25.0_deg;
gbl_rotation += 2.5_deg;
return false;
}
static void render() {
for(const auto& poly : Background::poly) {
GPU::render(poly);
}
doener_fish.render();
GPU::render(Jaby::star_base);
Shared::back_menu.render();
GPU::wait_for_render(); //< Because we are single buffer
}
void main() {
setup();
while(true) {
if(update_or_exit()) {
break;
}
GPU::swap_buffers_vsync(1, false);
render();
}
}
}

View File

@ -0,0 +1,15 @@
#include "include/gte_test_assets.hpp"
#include <PSX/AutoLBA/auto_lba_declaration.hpp>
namespace GTETest {
enum LBA {
__jabyengine_start_lba_request
__jabyengine_request_lba_for(JABY_STAR, "ASSETS/GTE/JABY.IMG"),
__jabyengine_end_lba_request
};
__declare_lba_header(LBA);
CDFile Assets[1] = {
CDFileBuilder::simple_tim(LBA::JABY_STAR, JabySTARTim),
};
}

View File

@ -0,0 +1,47 @@
#pragma once
#include <PSX/GPU/gpu_primitives.hpp>
#include <PSX/GPU/gpu.hpp>
#include <PSX/GTE/gte.hpp>
#include <stdio.hpp>
namespace GTETest {
using namespace JabyEngine;
struct GTE_Sprite {
GPU::AreaI16 area;
GPU::PositionI16 pivot;
deg_t angle;
gte_float scale;
GPU::POLY_FT4::Linked display;
static constexpr GTE_Sprite create(const GPU::POLY_FT4::Linked& base) {
const auto rect_size = base->get_rect_size();
return GTE_Sprite{
.area = GPU::AreaI16::create(base->get_rect_pos(), rect_size),
.pivot = GPU::PositionI16::create(rect_size.width/2, rect_size.height/2),
.angle = 0.0_deg,
.scale = 1.0_gf,
.display = base
};
}
void apply(const GTE::MATRIX& gbl_matrix = GTE::MATRIX::identity()) {
const auto matrix =
GTE::MATRIX::translated(-this->pivot.x, -this->pivot.y, 0)
.rotate(0.0_deg, 0.0_deg, this->angle)
.scale(this->scale, this->scale)
.translate(this->area.position.x + this->pivot.x, this->area.position.y + this->pivot.y, 0)
.comp(gbl_matrix);
this->display->vertex0 = matrix.apply_to(GPU::Vertex::create(0, 0));
this->display->vertex1 = matrix.apply_to(GPU::Vertex::create(this->area.size.width, 0));
this->display->vertex2 = matrix.apply_to(GPU::Vertex::create(0, this->area.size.height));
this->display->vertex3 = matrix.apply_to(GPU::Vertex::create(this->area.size.width, this->area.size.height));
}
void render() {
GPU::render(this->display);
}
};
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "../../../../include/asset_mgr.hpp"
#include <PSX/File/cd_file_types.hpp>
namespace GTETest {
using namespace JabyEngine;
static constexpr auto JabySTARTim = SimpleTIM::create(
// v Doenerfisch rotates so we need some space
Assets::Main::DoenerFishInfo.tim.get_texture_x(), Assets::Main::DoenerFishInfo.tim.get_texture_y() + Assets::Main::DoenerFishInfo.size.height + 2,
Assets::Main::DoenerFishInfo.tim.get_clut_x() + 16, Assets::Main::DoenerFishInfo.tim.get_clut_y()
);
}

View File

@ -0,0 +1,38 @@
#pragma once
#include <PSX/File/cd_file_types.hpp>
namespace BIOSInfo {
void main();
}
namespace ControllerTest {
extern const volatile JabyEngine::AutoLBAEntry lba[];
extern JabyEngine::CDFile Assets[1];
void main();
}
namespace GPUTest {
extern const volatile JabyEngine::AutoLBAEntry lba[];
extern JabyEngine::CDFile Assets[2];
extern JabyEngine::CDFile LargeAssets[36];
void main();
}
namespace GTETest {
extern const volatile JabyEngine::AutoLBAEntry lba[];
extern JabyEngine::CDFile Assets[1];
void main();
}
namespace FontCycler {
void main();
}
namespace ScreenCenter {
extern const volatile JabyEngine::AutoLBAEntry lba[];
extern JabyEngine::CDFile Assets[1];
void main();
}

View File

@ -0,0 +1,5 @@
#include "include/frame.hpp"
#include <PSX/GPU/gpu.hpp>
namespace ScreenCenter {
}

View File

@ -0,0 +1,107 @@
#pragma once
#include <PSX/GPU/gpu.hpp>
#include <PSX/GPU/make_gpu_primitives.hpp>
#include <PSX/System/IOPorts/dma_io.hpp>
namespace ScreenCenter {
using namespace JabyEngine;
class Frame {
private:
struct TopBorder : public GPU::internal::LinkedElementCreator<TopBorder> {
GPU::TILE top_left[2];
GPU::TILE top_right[2];
static constexpr TopBorder::Linked create(GPU::Color24 BaseColor, GPU::SizeI16 Size) {
TopBorder frame;
frame.top_left[0] = Make::TILE(Make::AreaI16(0, 0, Size.width, Size.height), BaseColor);
frame.top_left[1] = Make::TILE(Make::AreaI16(0, 0, Size.height, Size.width), BaseColor);
frame.top_right[0] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.width, 0, Size.width, Size.height), BaseColor);
frame.top_right[1] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.height, 0, Size.height, Size.width), BaseColor);
return frame.linked();
}
};
struct BottomBorder : GPU::internal::LinkedElementCreator<BottomBorder> {
GPU::TILE bottom_left[2];
GPU::TILE bottom_right[2];
static constexpr BottomBorder::Linked create(GPU::Color24 BaseColor, GPU::SizeI16 Size) {
BottomBorder frame;
frame.bottom_left[0] = Make::TILE(Make::AreaI16(0, GPU::Display::Height - Size.width, Size.height, Size.width), BaseColor);
frame.bottom_left[1] = Make::TILE(Make::AreaI16(0, GPU::Display::Height - Size.height, Size.width, Size.height), BaseColor);
frame.bottom_right[0] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.height, GPU::Display::Height - Size.width, Size.height, Size.width), BaseColor);
frame.bottom_right[1] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.width, GPU::Display::Height - Size.height, Size.width, Size.height), BaseColor);
return frame.linked();
}
};
struct LineBorder : GPU::internal::LinkedElementCreator<LineBorder> {
GPU::LINE_G_MULTI<5> border;
static constexpr LineBorder::Linked create(int16_t offset = 0) {
const auto get_color = [](size_t idx, int16_t offset) -> GPU::Color24 {
const GPU::Color24 Colors[4] = {GPU::Color24::Red(), GPU::Color24::Green(), GPU::Color24::Blue(), GPU::Color24::Yellow()};
return Colors[(idx + offset)%4];
};
const int16_t origin = 0 + offset;
const int16_t width = GPU::Display::Width - 1 - offset;
const int16_t height = GPU::Display::Height - 1 - offset;
LineBorder frame;
frame.border = Make::LINE_G(
GPU::ColorVertex{get_color(0, offset), Make::Vertex(origin, origin)},
GPU::ColorVertex{get_color(1, offset), Make::Vertex(origin, height)},
GPU::ColorVertex{get_color(2, offset), Make::Vertex(width, height)},
GPU::ColorVertex{get_color(3, offset), Make::Vertex(width, origin)},
GPU::ColorVertex{get_color(4, offset), Make::Vertex(origin, origin)}
);
return frame.linked();
}
};
struct LineCross : GPU::internal::LinkedElementCreator<LineCross> {
GPU::LINE_G_SINGLE cross[2];
static constexpr LineCross::Linked create(const decltype(LineBorder::border)& border) {
LineCross frame;
frame.cross[0] = Make::LINE_G(border[0], border[2]);
frame.cross[1] = Make::LINE_G(border[3], border[1]);
return frame.linked();
}
};
TopBorder::Linked top_border;
BottomBorder::Linked bottom_border;
LineBorder::Linked line_border[2];
LineCross::Linked line_cross;
public:
static constexpr Frame create() {
constexpr auto BaseColor = GPU::Color24::from_rgb(0x1D, 0xA0, 0xA3);
constexpr auto Size = Make::SizeI16(64, 16);
Frame frame;
frame.top_border = TopBorder::create(BaseColor, Size);
frame.bottom_border = BottomBorder::create(BaseColor, Size);
frame.line_border[0] = LineBorder::create();
frame.line_border[1] = LineBorder::create(1);
frame.line_cross = LineCross::create(frame.line_border[0]->border);
return frame;
}
void setup() {
this->top_border.concat(this->bottom_border.concat(this->line_border[0].concat(this->line_border[1].concat(this->line_cross))));
}
void render() const {
GPU::render(this->top_border);
}
};
}

View File

@ -0,0 +1,209 @@
#include "../../../include/shared.hpp"
#include "include/frame.hpp"
#include <FontWriter/fonts.hpp>
#include <PSX/GPU/gpu.hpp>
#include <PSX/GPU/make_gpu_primitives.hpp>
#include <PSX/Periphery/periphery.hpp>
#include <PSX/Timer/frame_timer.hpp>
namespace ScreenCenter {
using namespace JabyEngine;
using GenericButton = Periphery::GenericController::Button;
struct ButtonPulser {
static constexpr auto StartTime = 2500_ms;
static constexpr auto PulseTime = 100_ms;
enum struct State {
WentDown,
Pulse,
Unkown
};
SimpleTimer<uint8_t> timer;
uint8_t pulse_time;
void setup() {
this->timer.reset();
this->pulse_time = StartTime;
}
void reset() {
ButtonPulser::setup();
}
State check(GenericButton button) {
const auto controller = Periphery::get_primary_controller_as<Periphery::GenericController>();
if(!controller.button.was_down(button)) {
ButtonPulser::reset();
if(controller.button.went_down(button)) {
return State::WentDown;
}
}
if(this->timer.is_expired_for(this->pulse_time)) {
this->pulse_time = PulseTime;
this->timer.reset();
return State::Pulse;
}
return State::Unkown;
}
};
#ifdef JABYENGINE_PAL
static const char TVModeStr[] = "PAL";
static constexpr uint16_t ScanlinesV = 288;
#else
static const char TVModeStr[] = "NTSC";
static constexpr uint16_t ScanlinesV = 240;
#endif //JABYENGINE_PAL
namespace PSYQ {
static const char*const Name = "PSYQ";
static void set_offset(uint16_t x, uint16_t y) {
GPU::Display::set_offset(x, y);
}
}
struct Formular {
const char* name;
void (*function)(uint16_t, uint16_t);
};
static const Formular ScreenFormulars[] = {
Formular{.name = PSYQ::Name, .function = PSYQ::set_offset}
};
static constexpr const GPU::VRAM2VRAM background_img[] = {
// current_id of 0 will be rendering on (0, 256)
GPU::VRAM2VRAM::create(Make::AreaU16(384, 240, 256, 240), Make::PositionU16(32, GPU::Display::Height)),
GPU::VRAM2VRAM::create(Make::AreaU16(384, 240, 256, 240), Make::PositionU16(32, 0)),
};
static auto frame = Frame::create();
static ButtonPulser button_pulse[4];
static void (*update)() = nullptr;
static int16_t offset_x = 0;
static int16_t offset_y = 0;
static uint8_t formular_sel = 0;
static void update_interactive();
static void reset_screen();
static void update_enter_state() {
static const char IntroductionTest[] = "Press START to begin with\n";
static constexpr auto IntroductionTestLength = BIOSFont::Info.estimate_str_render_length(IntroductionTest);
static constexpr auto CenterPoint = Make::PositionI16((GPU::Display::Width - IntroductionTestLength)/2, (GPU::Display::Height - (2*16))/2);
const auto controller = Periphery::get_primary_controller_as<Periphery::GenericController>();
if(controller.button.went_up(GenericButton::R1) || controller.button.went_up(GenericButton::L1)) {
// Only one mode supported
//formular_sel ^= 1;
}
if(controller.button.went_down(GenericButton::ST)) {
update = update_interactive;
}
auto cursor = FontWriter::update(CenterPoint);
FontWriter::bios_font_writer.write(cursor, IntroductionTest, GPU::Color24::White());
FontWriter::bios_font_writer.write(cursor, ScreenFormulars[formular_sel].name, GPU::Color24::White());
}
static void update_interactive() {
static const auto handle_button = [](ButtonPulser& button_pulse, GenericButton button, int16_t &dst, const int16_t mlp) {
switch(button_pulse.check(button)) {
case ButtonPulser::State::WentDown:
dst += (1*mlp);
break;
case ButtonPulser::State::Pulse:
dst += (2*mlp);
break;
}
};
static const char*const ModeStr = "TV-Mode: %s\n";
static const char*const FormularStr = "<<%s>>\n";
static const char OffsetStr[] = "Offset: %i, %i";
static constexpr auto CenterLength = FontWriter::BIOSFont::Info.estimate_str_render_length(OffsetStr);
static constexpr auto CenterPoint = Make::PositionI16((GPU::Display::Width - CenterLength)/2, (GPU::Display::Height - 3*16)/2);
const auto& screen_formular = ScreenFormulars[formular_sel];
const auto controller = Periphery::get_primary_controller_as<Periphery::GenericController>();
handle_button(button_pulse[0], GenericButton::Left, offset_x, -1);
handle_button(button_pulse[1], GenericButton::Right, offset_x, 1);
handle_button(button_pulse[2], GenericButton::Up, offset_y, -1);
handle_button(button_pulse[3], GenericButton::Down, offset_y, 1);
if(controller.button.is_down(GenericButton::R1) && controller.button.is_down(GenericButton::L1)) {
for(auto& pulse : button_pulse) {
pulse.setup();
}
reset_screen();
}
auto cursor = FontWriter::update(CenterPoint.move(-offset_x, -offset_y));
FontWriter::bios_font_writer.write(cursor, ModeStr, GPU::Color24::White(), TVModeStr);
FontWriter::bios_font_writer.write(cursor, FormularStr, GPU::Color24::White(), screen_formular.name);
FontWriter::bios_font_writer.write(cursor, OffsetStr, GPU::Color24::White(), offset_x, offset_y);
screen_formular.function(offset_x, offset_y);
}
static void reset_screen() {
PSYQ::set_offset(0, 0);
offset_x = 0;
offset_y = 0;
}
static void setup() {
Shared::back_menu.reset();
frame.setup();
for(auto& pulse : button_pulse) {
pulse.setup();
}
update = update_enter_state;
formular_sel = 0;
offset_x = 0;
offset_y = 0;
}
static bool update_or_exit() {
Periphery::query_controller();
if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) {
return true;
}
update();
return false;
}
static void render() {
GPU::render(background_img[GPU::Display::current_id]);
frame.render();
Shared::back_menu.render();
}
void main() {
setup();
while(true) {
if(update_or_exit()) {
reset_screen();
break;
}
GPU::swap_buffers_vsync(1);
render();
}
}
}

View File

@ -0,0 +1,17 @@
#include <PSX/File/Processor/cd_file_processor.hpp>
#include <PSX/AutoLBA/auto_lba_declaration.hpp>
namespace ScreenCenter {
using namespace JabyEngine;
enum LBA {
__jabyengine_start_lba_request
__jabyengine_request_lba_for(BG_IMAGE, "ASSETS/SAND.TIM"),
__jabyengine_end_lba_request
};
__declare_lba_header(LBA);
CDFile Assets[1] = {
CDFileBuilder::sony_tim(LBA::BG_IMAGE, TIM::create())
};
}

View File

@ -0,0 +1,299 @@
#include "../include/asset_mgr.hpp"
#include "include/font_writer.hpp"
#include "include/menu.hpp"
#include "include/paco.hpp"
#include "Overlay/Overlays.hpp"
#include <FontWriter/fonts.hpp>
#include <FontWriter/font_writer.hpp>
#include <PSX/Audio/CDDA.hpp>
#include <PSX/Audio/CDXA.hpp>
#include <PSX/Periphery/periphery.hpp>
#include <stdio.hpp>
using namespace JabyEngine;
using DigitalButton = Periphery::GenericController::Button;
struct CDPlayer {
static constexpr auto MaxChannels = 2;
uint8_t channel;
bool is_xa;
static constexpr CDPlayer create() {
return CDPlayer{.channel = 0, .is_xa = true};
}
void play() {
if(this->is_xa) {
Assets::XAAudio::play_mix();
}
else {
const auto [first_track, last_track] = CDDA::get_tracks();
CDDA::play(first_track);
}
}
void stop() {
if(this->is_xa) {
CDXA::stop();
}
else {
CDDA::stop();
}
}
void change_channel(int8_t step) {
if(this->is_xa) {
this->channel = static_cast<uint8_t>((this->channel + step))%MaxChannels;
CDXA::set_channel(this->channel);
}
}
void change_audio() {
CDPlayer::stop();
this->is_xa = !this->is_xa;
CDPlayer::play();
}
void push() {
if(this->is_xa) {
CDXA::push_play();
}
else {
CDDA::push_play();
}
}
void pop() {
if(this->is_xa) {
CDXA::pop_play();
}
else {
CDDA::pop_play();
}
}
};
struct StateChange {
void (*asset_load)();
void (*main)();
static constexpr StateChange empty() {
return StateChange{.asset_load = nullptr, .main = nullptr};
}
void clear() {
this->asset_load = nullptr;
this->main = nullptr;
}
bool contains_state() const {
return this->main;
}
auto operator<=>(const StateChange&) const = default;
};
static const Menu::SimpleMenu::Entry MenuEntries[] = {
{"Controller Test"},
{"GPU Test"},
{"GTE Test"},
{"Font Cycler"},
{"Screen Center"},
{"BIOS Information"}
};
static const auto doener_fish = Make::SPRT(
Make::AreaI16(Make::PositionI16(8, GPU::Display::Height - Assets::Main::DoenerFishInfo.size.height), Assets::Main::DoenerFishInfo.size), // v this needs to be nicer! Has to be
Make::OffsetPageWithClut(Assets::Main::DoenerFishInfo.tim.get_page_offset_clut4(), Make::PageClut(Assets::Main::DoenerFishInfo.tim.get_clut_position())),
GPU::Color24::Grey()
);
static CDPlayer cd_player = CDPlayer::create();
static object::Paco paco;
static Menu::SimpleMenu menu;
static StateChange state_changer;
static StateChange old_state_changer;
namespace Shared {
Menu::BackMenu back_menu;
JabyEngine::GPU::POLY_G4 background = Make::POLY_G4(
Make::AreaI16(0, 0, GPU::Display::Width, GPU::Display::Height),
{GPU::Color24::Red(0xA0), GPU::Color24::Green(0xA0), GPU::Color24::Blue(0xA0), GPU::Color24::Black()}
);
bool load_test = false;
}
static void setup() {
Assets::Main::load();
FontWriter::setup();
paco.setup();
Shared::back_menu.setup(&FontWriter::bios_font_writer);
menu.setup([](uint32_t selection) {
switch(selection) {
case 0:
state_changer.asset_load = Assets::Overlay::load_controller_test;
state_changer.main = ControllerTest::main;
break;
case 1:
state_changer.asset_load = Assets::Overlay::load_gpu_test;
state_changer.main = GPUTest::main;
break;
case 2:
state_changer.asset_load = Assets::Overlay::load_gte_test;
state_changer.main = GTETest::main;
break;
case 3:
state_changer.asset_load = Assets::Overlay::load_font_cycler;
state_changer.main = FontCycler::main;
break;
case 4:
state_changer.asset_load = Assets::Overlay::load_screen_center;
state_changer.main = ScreenCenter::main;
break;
case 5:
state_changer.asset_load = Assets::Overlay::load_bios_info;
state_changer.main = BIOSInfo::main;
break;
}
},MenuEntries);
cd_player.play();
}
namespace NormalScene {
static void update() {
static const char Title[] = ">> Pool Box <<";
static const char Version[] = "Ver. 0.9.0";
static constexpr auto TitleLength = DefaultFont::Info.estimate_str_render_length(Title);
static constexpr auto VersionLength = DefaultFont::Info.estimate_str_render_length(Version);
Periphery::query_controller();
const auto& controller = Periphery::get_primary_controller_as<JabyEngine::Periphery::GenericController>();
if(controller.is_connected()) {
if(controller.button.went_down(DigitalButton::SEL)) {
cd_player.change_audio();
}
if(controller.button.went_down(DigitalButton::R1)) {
cd_player.change_channel(1);
}
if(controller.button.went_down(DigitalButton::L1)) {
cd_player.change_channel(-1);
}
// Trigger load test
if(controller.button.is_down(DigitalButton::R2) && controller.button.is_down(DigitalButton::L2) && controller.button.is_down(DigitalButton::ST)) {
Shared::load_test = true;
}
}
auto cursor = FontWriter::update(Make::PositionI16((GPU::Display::Width-TitleLength)/2, 16));
paco.update();
FontWriter::new_font_writer.write(cursor, Title, GPU::Color24::Yellow(0xD0), &FontWriter::wiggle);
FontWriter::new_font_writer.write(cursor.change_position(Make::PositionI16((GPU::Display::Width-VersionLength)/2, 16 + DefaultFont::Info.get_kern_size().height)), Version, GPU::Color24::Green(0xD0), &FontWriter::wiggle);
menu.update(FontWriter::bios_font_writer, cursor, Make::PositionI16(8, 64));
cursor.change_position(Make::PositionI16(doener_fish.position.x + doener_fish.size.width, GPU::Display::Height - 48));
FontWriter::bios_font_writer.write(cursor, "Audio:\n%s\n(SEL/R1/R2)", cd_player.is_xa ? "CD-XA" : "CD-DA");
if(Shared::load_test) {
// Force state change if we are in the load_test state
state_changer.asset_load = Assets::Overlay::load_large_gpu_test;
state_changer.main = GPUTest::main;
}
}
static void render() {
GPU::render(Shared::background);
FontWriter::new_font_writer.render();
FontWriter::bios_font_writer.render();
paco.render();
GPU::render(doener_fish);
}
static void run() {
update();
GPU::swap_buffers_vsync(1);
render();
}
}
namespace LoadingScene {
static SimpleTimer<uint8_t> jaby_timer;
static uint8_t jaby_frame_offset;
static void update() {
jaby_timer.reset();
jaby_frame_offset = 0;
}
static void vsync_render() {
static constexpr auto StartPosition = Make::PositionI16(24, 64);
const auto load_font = Make::SPRT(
Make::AreaI16(StartPosition.move(Assets::Main::JabyLoader::JabyFrame.size.width + 8, 0), Assets::Main::JabyLoader::FontFrame.size),
Make::OffsetPageWithClut(Assets::Main::JabyLoader::TIMLoaction.get_page_offset_clut4().move(Assets::Main::JabyLoader::FontFrame.position.x, Assets::Main::JabyLoader::FontFrame.position.y), Make::PageClut(Assets::Main::JabyLoader::TIMLoaction.get_clut_position())),
GPU::Color24::Grey()
);
auto jaby_sprt = Make::SPRT(
Make::AreaI16(StartPosition, Assets::Main::JabyLoader::JabyFrame.size),
Make::OffsetPageWithClut(Assets::Main::JabyLoader::TIMLoaction.get_page_offset_clut4(), Make::PageClut(Assets::Main::JabyLoader::TIMLoaction.get_clut_position())),
GPU::Color24::Grey()
);
if(jaby_timer.is_expired_for(500_ms)) {
jaby_frame_offset = jaby_frame_offset ? 0 : 32;
jaby_timer.reset();
}
jaby_sprt.tex_offset.add(jaby_frame_offset, 0);
GPU::swap_buffers(!Shared::load_test);
GPU::render(jaby_sprt);
GPU::render(load_font);
jaby_sprt.position.move(Assets::Main::JabyLoader::FontFrame.size.width + Assets::Main::JabyLoader::JabyFrame.size.width + 8, 0);
GPU::render(jaby_sprt);
}
static void run() {
if(Shared::load_test || old_state_changer != state_changer) {
GPU::set_vsync_callback(vsync_render);
cd_player.push();
state_changer.asset_load();
old_state_changer = state_changer;
cd_player.pop();
GPU::set_vsync_callback(nullptr);
}
state_changer.main();
state_changer.clear();
}
}
void main() {
const auto& controller = Periphery::get_primary_controller_as<JabyEngine::Periphery::GenericController>();
setup();
while(true) {
if(state_changer.contains_state()) {
LoadingScene::run();
}
else {
NormalScene::run();
}
}
}

View File

@ -0,0 +1,135 @@
#include "../include/asset_mgr.hpp"
#include "Custom/custom_files.hpp"
#include "Overlay/Overlays.hpp"
#include <PSX/Audio/CDXA.hpp>
#include <PSX/AutoLBA/auto_lba.hpp>
#include <PSX/AutoLBA/auto_lba_declaration.hpp>
#include <PSX/File/Processor/cd_file_processor.hpp>
#include <stdio.hpp>
extern "C" uint32_t __bios_info_start;
extern "C" uint32_t __controller_tests_start;
extern "C" uint32_t __gpu_tests_start;
extern "C" uint32_t __gte_tests_start;
extern "C" uint32_t __font_cycler_start;
extern "C" uint32_t __screen_center_start;
namespace Assets {
enum LBA {
__jabyengine_start_lba_request
__jabyengine_request_lba_for(PACO, "ASSETS/MAIN/PACO.IMG"),
__jabyengine_request_lba_for(DFISH, "ASSETS/MAIN/DFISH.IMG"),
__jabyengine_request_lba_for(JABY_LOAD, "ASSETS/MAIN/LOAD.IMG"),
__jabyengine_request_lba_for(APPLE_SFX, "SFX/APPLE.VAG"),
__jabyengine_request_lba_for(BLUBB_SFX, "SFX/BLUBB.VAG"),
__jabyengine_request_lba_for(FRIEND_SFX, "SFX/FRIEND.VAG"),
__jabyengine_request_lba_for(MIX_XA, "XAAUDIO/MIX.XA"),
__jabyengine_request_lba_for(BIOS_INFO_OVL, "BIO.BIN"),
__jabyengine_request_lba_for(GPU_TEST_OVL, "GTO.BIN"),
__jabyengine_request_lba_for(GTE_TEST_OVL, "GTE.BIN"),
__jabyengine_request_lba_for(CONT_TEST_OVL, "CTO.BIN"),
__jabyengine_request_lba_for(FONT_CYC_OVL, "FCO.BIN"),
__jabyengine_request_lba_for(SCREEN_CENT_OVL, "SCO.BIN"),
__jabyengine_end_lba_request
};
__declare_lba_header(LBA);
static void load(const volatile AutoLBAEntry* lba, const CDFile* assets, size_t size) {
const auto buffer_cfg = CDFileProcessor::BufferConfiguration::new_default();
CDFileProcessor file_processor;
file_processor.setup(lba, CDFileProcessor::JobArray{assets, size}, buffer_cfg);
while(true) {
switch(file_processor.process()) {
case Progress::InProgress:
break;
case Progress::Done:
if(!file_processor.next(lba, buffer_cfg)) {
return;
}
break;
case Progress::Error:
printf("Error detected! Aborting load\n");
return;
}
}
file_processor.shutdown();
}
template<size_t N>
static void load(const volatile AutoLBAEntry* lba, const CDFile (&files)[N]) {
return load(lba, files, N);
}
namespace Main {
using SPU::operator""_vol;
static const CDFile Files[] = {
CDFileBuilder::simple_tim(LBA::PACO, PacoTIM),
CDFileBuilder::simple_tim(LBA::DFISH, DoenerFishInfo.tim),
CDFileBuilder::simple_tim(LBA::JABY_LOAD, JabyLoader::TIMLoaction),
CDFileBuilder::sony_vag(LBA::APPLE_SFX, VAG::create(0, 1.0_vol)),
CDFileBuilder::sony_vag(LBA::BLUBB_SFX, VAG::create(1, 1.0_vol)),
CDFileBuilder::sony_vag(LBA::FRIEND_SFX, VAG::create(2, 1.0_vol)),
CustomCDFileBuilder::jingle(2),
};
void load() {
::Assets::load(lba, Files);
}
}
namespace Overlay {
static void load(const CDFile& overlay_file, const volatile AutoLBAEntry* overlay_lba, const CDFile* overlay_assets, size_t size) {
::Assets::load(lba, &overlay_file, 1);
if(overlay_lba) {
::Assets::load(overlay_lba, overlay_assets, size);
}
}
static void load(const CDFile& overlay_file) {
load(overlay_file, nullptr, nullptr, 0ull);
}
template<size_t N>
static void load(const CDFile& overlay_file, const volatile AutoLBAEntry* overlay_lba, const CDFile (&overlay_assets)[N]) {
load(overlay_file, overlay_lba, overlay_assets, N);
}
void load_bios_info() {
load(CDFileBuilder::overlay(LBA::BIOS_INFO_OVL, &__bios_info_start));
}
void load_controller_test() {
load(CDFileBuilder::overlay(LBA::CONT_TEST_OVL, &__controller_tests_start), ControllerTest::lba, ControllerTest::Assets);
}
void load_gpu_test() {
load(CDFileBuilder::overlay(LBA::GPU_TEST_OVL, &__gpu_tests_start), GPUTest::lba, GPUTest::Assets);
}
void load_large_gpu_test() {
load(CDFileBuilder::overlay(LBA::GPU_TEST_OVL, &__gpu_tests_start), GPUTest::lba, GPUTest::LargeAssets);
}
void load_gte_test() {
load(CDFileBuilder::overlay(LBA::GTE_TEST_OVL, &__gte_tests_start), GTETest::lba, GTETest::Assets);
}
void load_font_cycler() {
load(CDFileBuilder::overlay(LBA::FONT_CYC_OVL, &__font_cycler_start));
}
void load_screen_center() {
load(CDFileBuilder::overlay(LBA::SCREEN_CENT_OVL, &__screen_center_start), ScreenCenter::lba, ScreenCenter::Assets);
}
}
namespace XAAudio {
void play_mix() {
CDXA::play(lba, MIX_XA, 0, false);
}
}
}

View File

@ -0,0 +1,35 @@
#include "include/font_writer.hpp"
#include <FontWriter/fonts.hpp>
#include <PSX/File/Processor/cd_file_processor.hpp> //< only for __heap_start D:
#include <PSX/Timer/frame_timer.hpp>
namespace FontWriter {
using namespace JabyEngine;
static constexpr auto LibraryFontTIM = SimpleTIM::create(320, 0, 320, DefaultFont::Info.texture_size.height);
static FontPrimitive font_buffer[2*256];
Wiggle wiggle = {Make::PositionI8(0, 0), Make::PositionI8(1, -2), Make::PositionI8(0, -4), Make::PositionI8(-1, -2), Make::PositionI8(0, 0), Make::PositionI8(1, 2), Make::PositionI8(0, 4), Make::PositionI8(-1, 2)};
JabyEngine::FontWriter new_font_writer = JabyEngine::FontWriter::empty();
JabyEngine::FontWriter bios_font_writer = JabyEngine::FontWriter::empty();
static SimpleTimer<uint8_t> timer;
uint8_t wiggle_count = 0;
void setup() {
JabyEngine::DefaultFont::load(&__heap_start, LibraryFontTIM);
JabyEngine::GlobalFontPrimitivePool::setup(font_buffer);
new_font_writer.setup(LibraryFontTIM, JabyEngine::DefaultFont::Info);
bios_font_writer.setup(JabyEngine::BIOSFont::TIM, JabyEngine::BIOSFont::Info);
timer.reset();
}
Cursor update(const GPU::PositionI16& start) {
if(timer.is_expired_for(50_ms)) {
timer.reset();
wiggle_count++;
}
return Cursor::create(start, wiggle_count);
}
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <FontWriter/Type/types.hpp>
#include <FontWriter/font_writer.hpp>
namespace FontWriter {
using namespace JabyEngine;
extern Wiggle wiggle;
extern JabyEngine::FontWriter new_font_writer;
extern JabyEngine::FontWriter bios_font_writer;
void setup();
Cursor update(const GPU::PositionI16& start);
}

View File

@ -0,0 +1,50 @@
#pragma once
#include "font_writer.hpp"
#include <FontWriter/font_writer.hpp>
#include <PSX/Timer/frame_timer.hpp>
namespace Menu {
using namespace JabyEngine;
class SimpleMenu {
public:
struct Entry {
const char* name;
};
typedef void (*Callback)(uint32_t selection);
private:
Callback selection_callback;
const Entry* entries;
size_t size;
uint8_t cur_selection;
public:
void setup(Callback callback, const Entry* entries, size_t size);
template<size_t N>
void setup(Callback callback, const Entry (&entries)[N]) {
SimpleMenu::setup(callback, entries, N);
}
void update(JabyEngine::FontWriter& font_writer, Cursor& cursor, const GPU::PositionI16& start);
};
class BackMenu {
private:
JabyEngine::FontWriter* font_writer;
SimpleTimer<uint32_t> timeout;
bool waiting;
public:
void setup(JabyEngine::FontWriter* font_writer);
void reset() {
this->timeout.reset();
this->waiting = false;
}
bool update(const GPU::PositionI16& position, bool auto_clear = true);
void render();
};
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "../../include/asset_mgr.hpp"
#include <PSX/GPU/make_gpu_primitives.hpp>
#include <PSX/Timer/frame_timer.hpp>
namespace object {
using namespace JabyEngine;
class Paco {
private:
static constexpr auto Size = Make::SizeI16(120, 128);
static const GPU::Color24 Colors[];
GPU::TexPage::Linked tex_page;
GPU::SPRT::Linked sprite;
SimpleTimer<uint8_t> timer;
uint8_t color_idx;
public:
constexpr Paco() :
tex_page(Make::TexPage(Make::PositionU16(
Assets::Main::PacoTIM.get_texture_x(), Assets::Main::PacoTIM.get_texture_y()),
GPU::TextureColorMode::clut4).linked()),
sprite(Make::SPRT(
Make::AreaI16(Make::PositionI16(GPU::Display::Width - Size.width, GPU::Display::Height - Size.height), Size),
Make::OffsetPageWithClut(Make::PageOffset(0, 0), Make::PageClut(Assets::Main::PacoTIM.get_clut_x(), Assets::Main::PacoTIM.get_clut_y())),
GPU::Color24::Blue()).linked()),
timer(),
color_idx(0) {}
void setup();
void update();
void render();
};
}

View File

@ -0,0 +1,81 @@
#include "../include/shared.hpp"
#include "include/menu.hpp"
#include <PSX/Periphery/periphery.hpp>
#include <PSX/SPU/spu.hpp>
namespace Menu {
using DigitalButton = Periphery::GenericController::Button;
void SimpleMenu :: setup(Callback callback, const Entry* entries, size_t size) {
this->selection_callback = callback;
this->entries = entries;
this->size = size;
this->cur_selection = 0;
}
void SimpleMenu :: update(JabyEngine::FontWriter& font_writer, Cursor& cursor, const GPU::PositionI16& start) {
const auto& controller = Periphery::get_primary_controller_as<JabyEngine::Periphery::GenericController>();
if(controller.button.went_down(DigitalButton::Up) && this->cur_selection > 0) {
this->cur_selection -= 1;
}
if(controller.button.went_down(DigitalButton::Down) && this->cur_selection < (this->size - 1)) {
this->cur_selection += 1;
}
if(controller.button.went_down(DigitalButton::Cross)) {
SPU::voice[0].play();
this->selection_callback(this->cur_selection);
}
cursor.pos = Make::PositionI16(8, 64);
for(size_t n = 0; n < this->size; n++) {
const auto& cur_entry = this->entries[n];
if(this->cur_selection == n) {
FontWriter::bios_font_writer.write(cursor, ">%s<\n", cur_entry.name);
}
else {
FontWriter::bios_font_writer.write(cursor, "%s\n", cur_entry.name);
}
}
}
void BackMenu :: setup(JabyEngine::FontWriter* font_writer) {
this->font_writer = font_writer;
this->timeout.reset();
this->waiting = false;
}
bool BackMenu :: update(const GPU::PositionI16& position, bool auto_clear) {
const auto& controller = Periphery::get_primary_controller_as<JabyEngine::Periphery::GenericController>();
if(Shared::load_test || controller.button.is_down(DigitalButton::Circle)) {
this->waiting = true;
if(this->timeout.is_expired_for(2500_ms)) {
return true;
}
}
else {
this->waiting = false;
this->timeout.reset();
}
if(this->waiting) {
auto cursor = JabyEngine::Cursor::create(position);
this->font_writer->write(cursor, "Press and hold O\nto get back", GPU::Color24::Red(0xD0));
}
else if(auto_clear) {
this->font_writer->clear();
}
return false;
}
void BackMenu :: render() {
this->font_writer->render();
}
}

View File

@ -0,0 +1,24 @@
#include "include/paco.hpp"
namespace object {
const GPU::Color24 Paco :: Colors[] = {GPU::Color24::Red(), GPU::Color24::Green(), GPU::Color24::Blue(), GPU::Color24::Yellow()};
void Paco :: setup() {
this->timer.reset();
this->tex_page.concat(this->sprite);
}
void Paco :: update() {
if(this->timer.is_expired_for(325_ms)) {
static constexpr uint8_t LastIDX = (sizeof(Paco::Colors)/sizeof(Paco::Colors[0])) - 1;
this->color_idx = (this->color_idx == LastIDX) ? 0 : this->color_idx + 1;
this->timer.reset();
}
}
void Paco :: render() {
this->sprite->color = Paco::Colors[this->color_idx];
GPU::render(this->tex_page);
}
}

BIN
examples/PoolBox/assets/AllTheJaby.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/Controller.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/IMG_6921.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/IconTexture.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/JabyStar.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/JabyTails.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,66 @@
include $(JABY_ENGINE_DIR)/mkfile/common/ExportPath.mk
include $(JABY_ENGINE_DIR)/mkfile/common/RebuildTarget.mk
OUTPUT_DIR = bin
CLUT_4_COLOR_TRANS_FLAGS = simple-tim clut4 --color-trans
# Ressources to convert
## Music tracks
INPUT += $(OUTPUT_DIR)/Evacuation_cdda.xa
INPUT += $(OUTPUT_DIR)/OnMyOwn_BailBonds.xa
INPUT += $(OUTPUT_DIR)/apple.vag
INPUT += $(OUTPUT_DIR)/blubb-mono.vag
INPUT += $(OUTPUT_DIR)/Friendship_samp.vag
## Images
INPUT += $(OUTPUT_DIR)/TexturePage.img
TexturePage_FLAGS = simple-tim clut4
INPUT += $(OUTPUT_DIR)/IconTexture.img
IconTexture_FLAGS = simple-tim clut4 --semi-trans --color-trans
INPUT += $(OUTPUT_DIR)/Paco.img
Paco_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS)
INPUT += $(OUTPUT_DIR)/Controller.img
Controller_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS)
INPUT += $(OUTPUT_DIR)/doener_fish.img
doener_fish_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS)
INPUT += $(OUTPUT_DIR)/JabyStar.img
JabyStar_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS)
INPUT += $(OUTPUT_DIR)/JabyTails.img
JabyTails_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS)
INPUT += $(OUTPUT_DIR)/IMG_6921.tim
IMG_6921_TIM_FLAGS = tim full16 --clut-pos {384,255} --tex-pos {384,256}
INPUT += $(OUTPUT_DIR)/AllTheJaby.tim
AllTheJaby_TIM_FLAGS = tim full16 --tex-pos {0,0}
$(OUTPUT_DIR)/%.vag: audio/%.wav
@mkdir -p $(OUTPUT_DIR)
psxfileconv --lz4 $< -o $@ vag
$(OUTPUT_DIR)/OnMyOwn_BailBonds.xa: audio/OnMyOwn_BailBonds.mp3
@mkdir -p $(OUTPUT_DIR)
psxfileconv $< -o $@ xa
$(OUTPUT_DIR)/%.xa: audio/%.wav
@mkdir -p $(OUTPUT_DIR)
psxfileconv $< -o $@ xa
$(OUTPUT_DIR)/%.img: %.png
@mkdir -p $(OUTPUT_DIR)
psxfileconv --lz4 $< -o $@ $($*_FLAGS)
$(OUTPUT_DIR)/%.tim: %.png
@mkdir -p $(OUTPUT_DIR)
psxfileconv --lz4 $< -o $@ $($*_TIM_FLAGS)
all: $(INPUT)
clean:
rm -fr $(OUTPUT_DIR)

BIN
examples/PoolBox/assets/Paco.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/TexturePage.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/audio/Evacuation_cdda.wav (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/audio/Friendship_samp.wav (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/audio/OnMyOwn_BailBonds.mp3 (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/audio/apple.wav (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/audio/blubb-mono.wav (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

BIN
examples/PoolBox/assets/doener_fish.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/pkg/Background.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/pkg/Icon.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
examples/PoolBox/assets/pkg/Title.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,60 @@
<PSXCD>
<!--
TODO: Support configurable default values for this
<Defaults>
<Data lead-out="0:2:0"\>
<Directory hidden="true"\>
<File lz4="already"\>
<CD_Audio Alignment="True"\>
</Defaults>-->
<Description>
<Publisher>Jaby</Publisher>
<License alt-logo = "%JABY_ENGINE_DIR%/bin/extern/32BIT.TMD" alt-text = " Not licensed by Sony Will not work on all hardware/software">
%PSX_LICENSE_PATH%/%PSX_LICENSE%.DAT
</License>
<!--<AltLicense text = " Not licensed by Sony Will not work on all hardware/software">%JABY_ENGINE_DIR%/bin/extern/32BIT.TMD</AltLicense>-->
</Description>
<Filesystem lead-out="0:2:0">
<File name = "SYSTEM.CNF">System.cnf.subst</File>
<Main name = "%PSX_BOOT_FILE%" lba_source = "../application/src/asset_mgr.cpp" >../application/bin/%PSX_TV_FORMAT%/PSX-release/PoolBox.psexe</Main>
<Overlay name = "BIO.BIN" lba_source = "" >../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.bios_info</Overlay>
<Overlay name = "CTO.BIN" lba_source = "../application/src/Overlay/ControllerTest/controller_test_assets.cpp">../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.controller_tests</Overlay>
<Overlay name = "GTO.BIN" lba_source = "../application/src/Overlay/GPUTest/gpu_test_assets.cpp" >../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.gpu_tests</Overlay>
<Overlay name = "GTE.BIN" lba_source = "../application/src/Overlay/GTETest/gte_test_assets.cpp" >../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.gte_tests</Overlay>
<Overlay name = "FCO.BIN" lba_source = "" >../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.font_cycler</Overlay>
<Overlay name = "SCO.BIN" lba_source = "../application/src/Overlay/ScreenCenter/screen_center_assets.cpp" >../application/bin/%PSX_TV_FORMAT%/PSX-release/Overlay.screen_center</Overlay>
<Directory name = "ASSETS" hidden = "true">
<Directory name = "MAIN">
<File name = "PACO.IMG" lz4 = "already">../assets/bin/Paco.img</File>
<File name = "DFISH.IMG" lz4 = "already">../assets/bin/doener_fish.img</File>
<File name = "LOAD.IMG" lz4 = "already">../assets/bin/JabyTails.img</File>
</Directory>
<Directory name = "CONT">
<File name = "CONT.IMG" lz4 = "already">../assets/bin/Controller.img</File>
</Directory>
<Directory name = "GTE">
<File name = "JABY.IMG" lz4 = "already">../assets/bin/JabyStar.img</File>
</Directory>
<File name = "TEX.IMG" lz4 = "already">../assets/bin/TexturePage.img</File>
<File name = "ICON.IMG" lz4 = "already">../assets/bin/IconTexture.img</File>
<File name = "SAND.TIM" lz4 = "already">../assets/bin/IMG_6921.tim</File>
<File name = "ATJ.TIM" lz4 = "already">../assets/bin/AllTheJaby.tim</File>
</Directory>
<Directory name = "XAAUDIO" hidden = "true">
<InterleavedFile name = "MIX.XA">
<Channel>../assets/bin/Evacuation_cdda.xa</Channel>
<Channel>../assets/bin/OnMyOwn_BailBonds.xa</Channel>
</InterleavedFile>
</Directory>
<Directory name = "SFX" hidden = "true">
<File name = "APPLE.VAG" lz4 = "already">../assets/bin/apple.vag</File>
<File name = "BLUBB.VAG" lz4 = "already">../assets/bin/blubb-mono.vag</File>
<File name = "FRIEND.VAG" lz4 = "already">../assets/bin/Friendship_samp.vag</File>
</Directory>
</Filesystem>
<AudioTrack align = "true">../assets/audio/jlbrock44_Three_Kings_Funk_cdda_ready.wav</AudioTrack>
</PSXCD>

View File

@ -0,0 +1,2 @@
include $(JABY_ENGINE_DIR)/mkfile/ISOMakefile.mk
include $(JABY_ENGINE_DIR)/mkfile/common/RebuildTarget.mk

View File

@ -0,0 +1,4 @@
BOOT=cdrom:\%PSX_BOOT_FILE%;1
TCB=4
EVENT=10
STACK=801FFFF0

View File

@ -0,0 +1,23 @@
#pragma once
#include "../jabyengine_defines.hpp"
namespace JabyEngine {
namespace CDDA {
struct TrackList {
uint8_t first_track;
uint8_t last_track;
static constexpr TrackList empty() {
return TrackList{.first_track = 0, .last_track = 0};
}
};
TrackList get_tracks();
void play(uint8_t track);
void stop();
void push_play();
void pop_play();
}
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "../AutoLBA/auto_lba.hpp"
namespace JabyEngine {
namespace CDXA {
void play(const volatile AutoLBAEntry* lba, uint8_t rel_lba_idx, uint8_t channel, bool double_speed);
void stop();
void set_channel(uint8_t channel);
void push_play();
void pop_play();
}
}

View File

@ -1,5 +1,4 @@
#ifndef __JABYENGINE_AUTO_LBA_HPP__
#define __JABYENGINE_AUTO_LBA_HPP__
#pragma once
#include "../Auxiliary/bits.hpp"
namespace JabyEngine {
@ -40,5 +39,3 @@ namespace JabyEngine {
}
};
}
#endif //!__JABYENGINE_AUTO_LBA_HPP__

View File

@ -1,9 +1,6 @@
#ifndef __JABYENGINE_AUTO_LBA_DECLARATION_HPP__
#define __JABYENGINE_AUTO_LBA_DECLARATION_HPP__
#pragma once
extern const volatile JabyEngine::AutoLBAEntry lba[];
#define __declare_lba_header(enum_struct) \
[[gnu::used]] \
const volatile JabyEngine::AutoLBAEntry __section(".header.lbas") lba[static_cast<int>(enum_struct::EndOfRequest)] = {0}
#endif //!__JABYENGINE_AUTO_LBA_DECLARATION_HPP__

View File

@ -1,6 +1,5 @@
#ifndef __JABYENGINE_ARRAY_RANGE_HPP__
#define __JABYENGINE_ARRAY_RANGE_HPP__
#include "../../stddef.h"
#pragma once
#include "../../stddef.hpp"
namespace JabyEngine {
template<typename T>
@ -40,5 +39,3 @@ namespace JabyEngine {
}
};
}
#endif //!__JABYENGINE_ARRAY_RANGE_HPP__

View File

@ -0,0 +1,19 @@
#pragma once
#include "../jabyengine_defines.hpp"
namespace JabyEngine {
// Taken from boost endian
static constexpr uint8_t read_be(uint8_t x) {
return x;
}
static constexpr uint16_t read_be(uint16_t x) {
return (x << 8) | (x >> 8);
}
static constexpr uint32_t read_be(uint32_t x) {
const uint32_t step16 = x << 16 | x >> 16;
return ((step16 << 8) & 0xff00ff00) | ((step16 >> 8) & 0x00ff00ff);
}
}

View File

@ -1,6 +1,5 @@
#ifndef __JABYENGINE_BITS_HPP__
#define __JABYENGINE_BITS_HPP__
#include "../jabyengine_defines.h"
#pragma once
#include "../jabyengine_defines.hpp"
#include "types.hpp"
namespace JabyEngine {
@ -151,7 +150,10 @@ namespace JabyEngine {
return *reinterpret_cast<S*>(&value);
}
}
static constexpr uint32_t operator<<(uint32_t value, const Bit& bit) {
return value << bit.pos;
}
}
#define __start_end_bit2_start_length(start_bit, end_bit) start_bit, (end_bit - start_bit + 1)
#endif //!__JABYENGINE_BITS_HPP__

View File

@ -1,5 +1,4 @@
#ifndef __JABYENGINE_CIRCULAR_BUFFER_HPP__
#define __JABYENGINE_CIRCULAR_BUFFER_HPP__
#pragma once
#include "array_range.hpp"
namespace JabyEngine {
@ -60,5 +59,3 @@ namespace JabyEngine {
}
};
}
#endif //!__JABYENGINE_CIRCULAR_BUFFER_HPP__

View File

@ -0,0 +1,30 @@
#pragma once
#include "../../stdint.hpp"
static constexpr int8_t operator""_i8(unsigned long long int value) {
return static_cast<int8_t>(value);
}
static constexpr uint8_t operator""_u8(unsigned long long int value) {
return static_cast<uint8_t>(value);
}
// ###################################################################
static constexpr int16_t operator""_i16(unsigned long long int value) {
return static_cast<int16_t>(value);
}
static constexpr uint16_t operator""_u16(unsigned long long int value) {
return static_cast<uint16_t>(value);
}
// ###################################################################
static constexpr int32_t operator""_i32(unsigned long long int value) {
return static_cast<int32_t>(value);
}
static constexpr uint32_t operator""_u32(unsigned long long int value) {
return static_cast<uint32_t>(value);
}

View File

@ -1,6 +1,5 @@
#ifndef __JABYENGINE_LZ4_DECOMPRESSOR_HPP__
#define __JABYENGINE_LZ4_DECOMPRESSOR_HPP__
#include "../../stddef.h"
#pragma once
#include "../../stddef.hpp"
#include "array_range.hpp"
#include "types.hpp"
@ -77,5 +76,3 @@ namespace JabyEngine {
Result process(ArrayRange<const uint8_t> data, bool is_last);
};
}
#endif //!__JABYENGINE_LZ4_DECOMPRESSOR_HPP__

View File

@ -1,8 +1,18 @@
#ifndef __JABYENGINE_MATH_HELPER_HPP__
#define __JABYENGINE_MATH_HELPER_HPP__
#pragma once
#include "types.hpp"
#include <stddef.hpp>
namespace JabyEngine {
template<typename T>
static constexpr T pow(T base, T power) {
T result = base;
while(power > 1) {
result = result*base;
power--;
}
return result;
}
template<typename T>
static constexpr pair<T, T> div_and_mod(T value, T div) {
const auto result = value/div;
@ -13,6 +23,25 @@ namespace JabyEngine {
const auto [tenth, rest] = div_and_mod(value, static_cast<uint8_t>(10));
return (tenth << 4 | rest);
}
template<typename T>
static constexpr T from_bcd(T value) {
T result = 0;
for(size_t n = 1; n < pow(10u, sizeof(T)*2); n *= 10) {
result += (value & 0b1111)*n;
value = value >> 4;
}
return result;
}
#endif //!__JABYENGINE_MATH_HELPER_HPP__
template<typename T>
static constexpr T min_of(T a, T b) {
return (a < b) ? a : b;
}
template<typename T>
static constexpr T max_of(T a, T b) {
return (a > b) ? a : b;
}
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <stdio.h>
namespace JabyEngine {
template<typename T>
static inline void dump_to_stdoutln(const T& object) {
const uint8_t* raw_ptr = reinterpret_cast<const uint8_t*>(&object);
for(size_t raw_pos = 0; raw_pos < sizeof(T); raw_pos++) {
printf("[%02X]", raw_ptr[raw_pos]);
}
printf("\n");
}
}

View File

@ -0,0 +1,95 @@
#pragma once
namespace JabyEngine {
template <class T, T v>
struct integral_constant {
static constexpr T value = v;
typedef T value_type;
typedef integral_constant<T,v> type;
constexpr operator T() const {
return v;
}
constexpr T operator()() const {
return v;
}
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
// #############################################
template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> {
typedef T type;
};
// #############################################
template<class T, class U>
struct is_same {
static constexpr bool value = false;
};
template<class T>
struct is_same<T, T> {
static constexpr bool value = true;
};
// #############################################
template<bool B, class T, class F>
struct conditional {
using type = T;
};
template<class T, class F>
struct conditional<false, T, F> {
using type = F;
};
// #############################################
template<class...>
struct conjunction {
static constexpr bool value = true;
};
template<class B1>
struct conjunction<B1> : B1 {
};
template<class B1, class... Bn>
struct conjunction<B1, Bn...> : conditional<bool(B1::value), conjunction<Bn...>, B1>::type {
};
// #############################################
template<class T>
struct is_pointer : false_type {};
template<class T>
struct is_pointer<T*> : true_type {};
template<class T>
struct is_pointer<T* const> : true_type {};
template<class T>
struct is_pointer<T* volatile> : true_type {};
template<class T>
struct is_pointer<T* const volatile> : true_type {};
// #############################################
template<typename T, typename... Ts>
using variadic_force_same = enable_if<conjunction<is_same<T, Ts>...>::value>::type;
// #############################################
}

View File

@ -1,5 +1,4 @@
#ifndef __JABYENGINE_TYPES_HPP__
#define __JABYENGINE_TYPES_HPP__
#pragma once
namespace JabyEngine {
template<typename T, typename S>
@ -8,11 +7,27 @@ namespace JabyEngine {
S second;
};
template<typename T, typename S>
struct cplx_pair {
T first;
S second;
template<typename T2, typename S2>
constexpr cplx_pair<T, S>& operator=(const pair<T2, S2>& obj) {
this->first = obj.first;
this->second = obj.second;
return *this;
}
};
template <typename... Args>
constexpr cplx_pair<Args&...> tie(Args&... args) {
return {args...};
}
enum struct Progress {
InProgress = 0,
Done,
Error
};
}
#endif //!__JABYENGINE_TYPES_HPP__

View File

@ -1,11 +1,8 @@
#ifndef __JABYENGINE_UNALIGNED_READ_HPP__
#define __JABYENGINE_UNALIGNED_READ_HPP__
#include "../../stdint.h"
#pragma once
#include "../../stdint.hpp"
namespace JabyEngine {
uint16_t unaligned_lhu(const uint8_t* adr) {
return (static_cast<uint16_t>(adr[0]) | static_cast<uint16_t>(adr[1]) << 8);
}
}
#endif //!__JABYENGINE_UNALIGNED_READ_HPP__

View File

@ -0,0 +1,15 @@
#pragma once
#include <stddef.hpp>
namespace JabyEngine {
using word_t = uint32_t;
static constexpr size_t bytes_to_words(size_t bytes) {
return bytes/sizeof(word_t);
}
static constexpr size_t words_to_bytes(size_t words) {
return words*sizeof(word_t);
}
}

View File

@ -1,5 +1,4 @@
#ifndef __JABYENGINE_CD_FILE_PROCESSOR_HPP__
#define __JABYENGINE_CD_FILE_PROCESSOR_HPP__
#pragma once
#include "../../AutoLBA/auto_lba.hpp"
#include "../../Auxiliary/circular_buffer.hpp"
#include "../../Auxiliary/lz4_decompressor.hpp"
@ -7,7 +6,7 @@
#include "../cd_file_types.hpp"
#include "file_processor.hpp"
extern "C" uint32_t __heap_base;
extern "C" uint32_t __heap_start;
namespace JabyEngine {
class CDFileProcessor {
@ -20,7 +19,7 @@ namespace JabyEngine {
size_t sector_count = 0;
static constexpr BufferConfiguration new_default() {
return {&__heap_base, BufferConfiguration::MediumSectorCount};
return {&__heap_start, BufferConfiguration::MediumSectorCount};
}
};
@ -49,6 +48,7 @@ namespace JabyEngine {
CDFileProcessor() = default;
void setup(const volatile AutoLBAEntry* lba, JobArray jobs, const BufferConfiguration& buf_cfg);
void shutdown();
template<size_t N>
void setup(const volatile AutoLBAEntry* lba, const CDFile (&file_array)[N], const BufferConfiguration& buf_cfg) {
@ -67,5 +67,3 @@ namespace JabyEngine {
}
};
}
#endif //!__JABYENGINE_CD_FILE_PROCESSOR_HPP__

View File

@ -1,59 +1,73 @@
#ifndef __JABYENGINE_FILE_PROCESSOR_HPP__
#define __JABYENGINE_FILE_PROCESSOR_HPP__
#pragma once
#include "../../Auxiliary/types.hpp"
#include "../file_types.hpp"
#include "../cd_file_types.hpp"
namespace JabyEngine {
namespace FileProcessor {
class State {
private:
public:
struct Reserved {
uint32_t reserved[4];
uint32_t reserved[8];
};
struct Configuration;
struct CDDataProcessor;
template<typename T>
using GenericProcessRoutine = Progress (*)(Configuration&, T&);
using GenericProcessRoutine = Progress (*)(CDDataProcessor&, T&);
typedef GenericProcessRoutine<Reserved> ProcessRoutine;
struct Configuration {
struct CDDataProcessor {
ProcessRoutine process_routine = nullptr;
const uint8_t* data_adr = nullptr;
size_t data_bytes = 0ull;
template<typename T>
static __always_inline Configuration from(GenericProcessRoutine<T> process_routine, const uint8_t* data_adr) {
static __always_inline CDDataProcessor from(GenericProcessRoutine<T> process_routine, const uint8_t* data_adr) {
return {reinterpret_cast<ProcessRoutine>(process_routine), data_adr};
}
template<typename T>
T simple_read_r() {
static constexpr size_t T_SIZE = sizeof(T);
T value = *reinterpret_cast<const T*>(this->data_adr);
CDDataProcessor::processed(T_SIZE);
return value;
}
constexpr void processed(size_t bytes) {
this->data_adr += bytes;
this->data_bytes -= bytes;
}
constexpr void skip(size_t bytes) {
CDDataProcessor::processed(bytes);
}
};
private:
Configuration config;
CDDataProcessor data_proc;
Reserved reserved;
template<typename T>
static __always_inline State from(const T& reserved, const uint8_t* data_adr, GenericProcessRoutine<T> process_routine) {
return {Configuration::from(process_routine, data_adr), *reinterpret_cast<const Reserved*>(&reserved)};
static __always_inline State from(const T& state, const uint32_t* data_adr, GenericProcessRoutine<T> process_routine) {
return {CDDataProcessor::from(process_routine, reinterpret_cast<const uint8_t*>(data_adr)), *reinterpret_cast<const Reserved*>(&state)};
static_assert(sizeof(T) <= sizeof(Reserved));
}
public:
Progress process(size_t bytes_ready) {
this->config.data_bytes += bytes_ready;
return (*this->config.process_routine)(this->config, this->reserved);
this->data_proc.data_bytes += bytes_ready;
return (*this->data_proc.process_routine)(this->data_proc, this->reserved);
}
};
// The nothing state
State create(const uint32_t* data_adr, const Nothing& nothing);
State create(const uint32_t* data_adr, const SimpleTIM& file);
State create(const uint32_t* data_adr, const TIM& file);
State create(const uint32_t* data_adr, const VAG& file);
State create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload);
}
}
#endif // !__JABYENGINE_FILE_PROCESSOR_HPP__

View File

@ -1,19 +1,28 @@
#ifndef __JABYENGINE_CD_FILE_TYPES_HPP__
#define __JABYENGINE_CD_FILE_TYPES_HPP__
#pragma once
#include <PSX/jabyengine_config.hpp>
#include "../Overlay/overlay.hpp"
#include "file_types.hpp"
namespace JabyEngine {
enum struct CDFileType : uint8_t {
SimpleTIM = 0,
CopyTo,
using CDFileType_t = uint8_t;
using RawPayload_t = uint32_t;
enum struct CDFileType : CDFileType_t {
CopyTo = 0,
SimpleTIM,
SonyTIM,
SonyVAG,
Custom,
};
struct __no_align CDFile {
union __no_align Payload {
uint32_t raw;
SimpleTIM simple_tim;
#pragma pack(push, 1)
struct CDFile {
union Payload {
RawPayload_t raw;
CopyTo copy_to;
SimpleTIM simple_tim;
TIM tim;
VAG vag;
Overlay overlay;
};
@ -21,16 +30,33 @@ namespace JabyEngine {
CDFileType type;
Payload payload;
template<typename S>
static constexpr CDFile custom(uint8_t lba_idx, S cd_file_type, RawPayload_t raw) {
return CDFile{
.rel_lba_idx = lba_idx,
.type = static_cast<CDFileType>(static_cast<CDFileType_t>(CDFileType::Custom) + static_cast<CDFileType_t>(cd_file_type)),
.payload = {.raw = raw}
};
}
static_assert(sizeof(Payload) == sizeof(uint32_t));
};
#pragma pack(pop)
struct CDFileBuilder {
static constexpr CDFile copy_to(uint8_t rel_lba_idx, uint32_t* dst) {
return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::CopyTo, .payload = {.copy_to = CopyTo{dst}}};
}
static constexpr CDFile simple_tim(uint8_t rel_lba_idx, SimpleTIM simple_tim) {
return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::SimpleTIM, .payload = {.simple_tim = simple_tim}};
}
static constexpr CDFile copy_to(uint8_t rel_lba_idx, uint32_t* dst) {
return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::CopyTo, .payload = {.copy_to = CopyTo{dst}}};
static constexpr CDFile sony_tim(uint8_t rel_lba_idx, TIM tim) {
return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::SonyTIM, .payload = {.tim = tim}};
}
static constexpr CDFile sony_vag(uint8_t lba_idx, VAG vag) {
return CDFile{.rel_lba_idx = lba_idx, .type = CDFileType::SonyVAG, .payload = {.vag = vag}};
}
static constexpr CDFile overlay(uint8_t rel_lba_idx, uint32_t* overlay_dst) {
@ -38,4 +64,3 @@ namespace JabyEngine {
}
};
}
#endif //!__JABYENGINE_CD_FILE_TYPES_HPP__

View File

@ -0,0 +1,62 @@
#pragma once
#include "Processor/file_processor.hpp"
#include "cd_file_types.hpp"
#include <limits.hpp>
namespace JabyEngine {
namespace FileProcessor {
namespace Helper {
template<typename T>
static Progress exchange_and_execute_process_function(State::GenericProcessRoutine<T> process_routine, State::CDDataProcessor& data_proc, T& state) {
data_proc.process_routine = reinterpret_cast<State::ProcessRoutine>(process_routine);
return process_routine(data_proc, state);
}
namespace DMA {
struct WordsReady {
uint32_t words_to_use;
bool is_last;
static constexpr WordsReady calculate(const State::CDDataProcessor& data_proc, size_t words_left) {
const auto config_data_words = (data_proc.data_bytes/sizeof(uint32_t));
const auto words_to_use = (config_data_words > words_left) ? words_left : config_data_words;
return {
.words_to_use = words_to_use,
.is_last = words_to_use == words_left
};
}
};
template<typename T>
static size_t send_words(size_t words_to_send, bool send_all) {
auto blocks_to_send = words_to_send/16;
while(blocks_to_send > 0) {
const auto block_send = (blocks_to_send > UI16_MAX) ? UI16_MAX : blocks_to_send;
// Send data!
T::wait();
T::Receive::start(blocks_to_send);
blocks_to_send -= block_send;
}
if(send_all) {
const auto last_words_to_send = (words_to_send & 0b1111);
if(last_words_to_send > 0) {
T::wait();
T::Receive::start(1, last_words_to_send);
}
T::wait();
T::end();
return words_to_send;
}
else {
return (words_to_send & ~0b1111);
}
}
}
}
}
}

View File

@ -1,13 +1,19 @@
#ifndef __JABYENGINE_FILE_TYPES_HPP__
#define __JABYENGINE_FILE_TYPES_HPP__
#pragma once
#include "../Auxiliary/bits.hpp"
#include "../jabyengine_defines.h"
#include "../GPU/gpu_types.hpp"
#include "../jabyengine_defines.hpp"
#include "../SPU/spu.hpp"
namespace JabyEngine {
struct __no_align Nothing {
#pragma pack(push, 1)
struct Nothing {
};
struct __no_align SimpleTIM {
struct CopyTo {
uint32_t* dst;
};
struct SimpleTIM {
static constexpr auto TextureX = BitRange::from_to(0, 8);
static constexpr auto TextureY = BitRange::from_to(9, 16);
static constexpr auto ClutX = BitRange::from_to(17, 22);
@ -15,34 +21,68 @@ namespace JabyEngine {
uint32_t raw;
constexpr SimpleTIM() {
this->raw = 0;
static constexpr SimpleTIM create(uint16_t texX, uint16_t texY, uint16_t clutX, uint16_t clutY) {
return SimpleTIM{.raw = TextureX.as_value(texX >> 1) | TextureY.as_value(texY >> 1) | ClutX.as_value(clutX >> 4) | ClutY.as_value(static_cast<uint32_t>(clutY))};
}
constexpr SimpleTIM(uint16_t texX, uint16_t texY, uint16_t clutX, uint16_t clutY) : raw(TextureX.as_value(texX >> 1) | TextureY.as_value(texY >> 1) | ClutX.as_value(clutX >> 4) | ClutY.as_value(clutY)) {
}
constexpr uint16_t getTextureX() const {
constexpr uint16_t get_texture_x() const {
return bit::value::get_normalized(this->raw, TextureX) << 1;
}
constexpr uint16_t getTextureY() const {
constexpr uint16_t get_texture_y() const {
return bit::value::get_normalized(this->raw, TextureY) << 1;
}
constexpr uint16_t getClutX() const {
constexpr GPU::PositionU16 get_texture_position() const {
return GPU::PositionU16::create(SimpleTIM::get_texture_x(), SimpleTIM::get_texture_y());
}
constexpr uint16_t get_clut_x() const {
return bit::value::get_normalized(this->raw, SimpleTIM::ClutX) << 4;
}
constexpr uint16_t getClutY() const {
constexpr uint16_t get_clut_y() const {
return bit::value::get_normalized(this->raw, ClutY);
}
};
struct __no_align CopyTo {
uint32_t* dst;
};
typedef CopyTo Overlay;
constexpr GPU::PositionU16 get_clut_position() const {
return GPU::PositionU16::create(SimpleTIM::get_clut_x(), SimpleTIM::get_clut_y());
}
constexpr GPU::PageOffset get_page_offset() const {
const auto tex_page = SimpleTIM::get_texture_position();
return GPU::PageOffset::create(tex_page.x&0x3F, tex_page.y);
}
constexpr GPU::PageOffset get_page_offset_clut8() const {
const auto page_offset = SimpleTIM::get_page_offset();
return GPU::PageOffset::create(page_offset.x*2, page_offset.y);
}
constexpr GPU::PageOffset get_page_offset_clut4() const {
const auto page_offset = SimpleTIM::get_page_offset();
return GPU::PageOffset::create(page_offset.x*4, page_offset.y);
}
};
struct TIM {
uint32_t zero;
static constexpr TIM create() {
return TIM{.zero = 0};
}
};
struct VAG {
uint8_t voice_number;
SPU::SimpleVolume inital_stereo_vol;
static constexpr VAG create(uint8_t voice_num, SPU::SimpleVolume volume) {
return VAG{.voice_number = voice_num, .inital_stereo_vol = volume};
}
};
#pragma pack(pop)
using Overlay = CopyTo;
}
#endif // !__JABYENGINE_FILE_TYPES_HPP__

View File

@ -0,0 +1,113 @@
#pragma once
#include "../../Auxiliary/bits.hpp"
#include "../../Auxiliary/type_traits.hpp"
#include "../../System/IOPorts/gpu_io.hpp"
namespace JabyEngine {
namespace GPU {
struct Link {
static constexpr auto AdrRange = BitRange::from_to(0, 23);
static constexpr auto SizeRange = BitRange::from_to(24, 31);
static constexpr uint32_t TerminationValue = 0x00FFFFFF;
static constexpr uint32_t default_link_value(size_t size) {
return SizeRange.as_value(size >> 2) | TerminationValue;
}
uint32_t link_value;
constexpr void set_link_identitiy(size_t size) {
this->link_value = default_link_value(size);
}
void set_adr(const void* adr) {
this->link_value = bit::value::set_normalized(this->link_value, AdrRange.with(reinterpret_cast<uint32_t>(adr)));
}
void* get_adr() const {
return reinterpret_cast<void*>(bit::value::get_normalized(this->link_value, AdrRange));
}
template<typename T>
T& insert_after(T& obj) {
const auto adr = Link::get_adr();
Link::set_adr(&obj);
obj.set_adr(adr);
return obj;
}
template<typename T>
enable_if<!is_pointer<T>::value, Link&>::type concat(T& obj) {
Link::set_adr(&obj);
return *this;
}
template<typename T>
enable_if<!is_pointer<T>::value, const Link&>::type concat(const T& obj) {
return concat(const_cast<Link&>(obj));
}
constexpr void terminate() {
this->link_value |= TerminationValue;
}
};
template<typename T>
struct LinkedElement : public Link {
T element;
static constexpr LinkedElement create(const T& element) {
LinkedElement new_element;
new_element.element = element;
new_element.set_link_identitiy();
return new_element;
}
constexpr void set_link_identitiy() {
Link::set_link_identitiy(sizeof(T));
}
constexpr const T* operator->() const {
return &this->element;
}
constexpr T* operator->() {
return &this->element;
}
static_assert((sizeof(T) >> 2) <= GPU_IO::FIFOWordSize);
};
namespace internal {
template<typename T>
struct LinkedElementCreator {
typedef LinkedElement<T> Linked;
constexpr LinkedElement<T> linked() {
return LinkedElement<T>::create(*static_cast<T*>(this));
}
};
}
namespace LinkHelper {
template<typename T>
static Link* link_array(Link* last_prim, T* elements, size_t length) {
for(size_t n = 0; n < length; n++) {
last_prim->concat(elements[n]);
last_prim = &elements[n];
}
last_prim->terminate();
return last_prim;
}
template<typename T, size_t N>
static Link* link_array(Link* last_prim, T(&elements)[N]) {
return link_array(last_prim, elements, N);
}
}
}
}

View File

@ -0,0 +1,52 @@
#pragma once
#include "../../System/IOPorts/gpu_io.hpp"
#include "linked_elements.hpp"
#include "primitive_support_types.hpp"
namespace JabyEngine {
namespace GPU {
struct TexPage : public internal::LinkedElementCreator<TexPage> {
static constexpr bool is_render_primitive = true;
GPU_IO_Values::GP0 value;
static constexpr TexPage create(const PositionU16& tex_pos, TextureColorMode tex_color, SemiTransparency transparency = SemiTransparency::B_Half_add_F_Half, bool dither = false) {
return TexPage{.value = GPU_IO_Values::GP0::TexPage(tex_pos, transparency, tex_color, dither, false)};
}
};
struct CPU2VRAM {
static constexpr bool is_render_primitive = true;
GPU_IO_Values::GP0 cmd;
GPU_IO_Values::GP0 pos;
GPU_IO_Values::GP0 size;
static constexpr CPU2VRAM create(const AreaU16& dst) {
return CPU2VRAM{
.cmd = GPU_IO_Values::GP0::CPU2VRAMBlitting(),
.pos = GPU_IO_Values::GP0::PostionTopLeft(dst.position),
.size = GPU_IO_Values::GP0::WidthHeight(dst.size)
};
}
};
struct VRAM2VRAM {
static constexpr bool is_render_primitive = true;
GPU_IO_Values::GP0 cmd;
GPU_IO_Values::GP0 src_pos;
GPU_IO_Values::GP0 dst_pos;
GPU_IO_Values::GP0 size;
static constexpr VRAM2VRAM create(const AreaU16& src, const PositionU16& dst) {
return VRAM2VRAM{
.cmd = GPU_IO_Values::GP0::VRAM2VRAMBlitting(),
.src_pos = GPU_IO_Values::GP0::PostionTopLeft(src.position),
.dst_pos = GPU_IO_Values::GP0::PostionTopLeft(dst),
.size = GPU_IO_Values::GP0::WidthHeight(src.size)
};
}
};
}
}

View File

@ -0,0 +1,135 @@
#pragma once
#include "linked_elements.hpp"
#include "primitive_support_types.hpp"
namespace JabyEngine {
namespace GPU {
namespace internal {
struct LineCode : public CodeBase<LineCode> {
static constexpr uint8_t CmdValue = 0b010;
static constexpr auto GouraudShading = Bit(28 - BitCorrection);
static constexpr auto FlatShading = !GouraudShading;
static constexpr auto PolyLine = Bit(27 - BitCorrection);
static constexpr auto SingleLine = !PolyLine;
static constexpr LineCode create() {
return CodeBase<LineCode>::create(CmdValue);
}
};
template<typename T>
struct LineCodeInterface {
typedef ::JabyEngine::GPU::internal::LineCode Code;
constexpr T& set_semi_transparent(bool set = true) {
static_cast<T*>(this)->head.code.set_tenary(set, Code::SemiTransparent, Code::NonTransparent);
return *static_cast<T*>(this);
}
};
struct LineHead {
Color24 color;
LineCode code;
static constexpr LineHead create(const Color24& color, const LineCode& code, bool is_poly) {
return LineHead{.color = color, .code = code}.set_poly_line(is_poly);
}
constexpr LineHead& set_poly_line(bool set = true) {
if(set) {
this->code.set(LineCode::PolyLine);
}
else {
this->code.set(LineCode::SingleLine);
}
return *this;
}
};
struct Termination {
Vertex value;
static constexpr Termination create() {
// 0x55555555 is more common then 0x50005000
return {.value = Vertex::create(static_cast<short>(0x5555), static_cast<short>(0x5555))};
}
};
template<typename Body>
struct SingleLine : public internal::RenderPrimitive<SingleLine<Body>>, public LineCodeInterface<SingleLine<Body>>, public internal::LinkedElementCreator<SingleLine<Body>> {
LineHead head;
Vertex start_point;
Body end_point;
};
template<typename Body, size_t N>
struct MultiLine : public internal::RenderPrimitive<MultiLine<Body, N>>, public LineCodeInterface<MultiLine<Body, N>>, public internal::LinkedElementCreator<MultiLine<Body, N>> {
LineHead head;
Vertex start_point;
Body points[N];
Termination end;
// Could also be none const in the future
template<typename T = Body>
constexpr typename enable_if<is_same<T, Vertex>::value, Vertex>::type operator[](size_t idx) const {
if(idx == 0) {
return this->start_point;
}
return this->points[idx - 1];
}
template<typename T = Body>
constexpr typename enable_if<is_same<T, ColorVertex>::value, ColorVertex>::type operator[](size_t idx) const {
if(idx == 0) {
return ColorVertex::create(this->head.color, this->start_point);
}
return this->points[idx - 1];
}
};
}
struct LINE_F {
typedef internal::LineCode Code;
static constexpr auto IdentityCode = Code::create().set(Code::FlatShading).set(Code::SingleLine).set(Code::NonTransparent);
static constexpr internal::SingleLine<Vertex> create(const Color24& color, const Vertex& start_point, const Vertex& end_point) {
using namespace internal;
return {.head = LineHead::create(color, IdentityCode, false), .start_point = start_point, .end_point = end_point};
}
template<typename...ARGS>
static constexpr internal::MultiLine<Vertex, sizeof...(ARGS)> create(const Color24& color, const Vertex& start_point, const ARGS&...rest) {
using namespace internal;
return {.head = LineHead::create(color, IdentityCode, true), .start_point = start_point, .points = {rest...}, .end = Termination::create()};
}
};
struct LINE_G {
typedef LINE_F::Code Code;
static constexpr auto IdentityCode = Code(LINE_F::IdentityCode).set(Code::GouraudShading);
static constexpr internal::SingleLine<ColorVertex> create(const ColorVertex& start_point, const ColorVertex& end_point) {
using namespace internal;
return {.head = LineHead::create(start_point.color, IdentityCode, false), .start_point = start_point.position, .end_point = end_point};
}
template<typename...ARGS>
static constexpr internal::MultiLine<ColorVertex, sizeof...(ARGS)> create(const ColorVertex& start_point, const ARGS&...rest) {
using namespace internal;
return {.head = LineHead::create(start_point.color, IdentityCode, true), .start_point = start_point.position, .points = {rest...}, .end = Termination::create()};
}
};
using LINE_F_SINGLE = internal::SingleLine<Vertex>;
template<size_t N>
using LINE_F_MULTI = internal::MultiLine<Vertex, N - 1>;
using LINE_G_SINGLE = internal::SingleLine<ColorVertex>;
template<size_t N>
using LINE_G_MULTI = internal::MultiLine<ColorVertex, N - 1>;
}
}

View File

@ -0,0 +1,453 @@
#pragma once
#include "linked_elements.hpp"
#include "primitive_support_types.hpp"
namespace JabyEngine {
namespace GPU {
namespace internal {
struct PolyCode : public CodeBase<PolyCode> {
static constexpr uint8_t CmdValue = 0b001;
static constexpr auto GouraudShading = Bit(28 - BitCorrection);
static constexpr auto FlatShading = !GouraudShading;
static constexpr auto QuadVertics = Bit(27 - BitCorrection);
static constexpr auto TriVertics = !QuadVertics;
static constexpr PolyCode create() {
return CodeBase<PolyCode>::create(CmdValue);
}
};
template<typename T>
struct PolyCodeInterface {
typedef ::JabyEngine::GPU::internal::PolyCode Code;
constexpr T& set_semi_transparent(bool set = true) {
static_cast<T*>(this)->code.set_tenary(set, Code::SemiTransparent, Code::NonTransparent);
return *static_cast<T*>(this);
}
constexpr T& set_texture_blending(bool set = true) {
static_cast<T*>(this)->code.set_tenary(set, Code::BlendTexture, Code::NoBlendTexture);
return *static_cast<T*>(this);
}
};
template<typename T>
struct Poly3Interface {};
template<typename T>
struct Poly4Interface {
static constexpr Vertex vertex0_from(const AreaI16& area) {
return area.get_top_left();
}
static constexpr Vertex vertex1_from(const AreaI16& area) {
return area.get_top_right();
}
static constexpr Vertex vertex2_from(const AreaI16& area) {
return area.get_bottom_left();
}
static constexpr Vertex vertex3_from(const AreaI16& area) {
return area.get_bottom_right();
}
constexpr T& set_rect_size(const SizeI16& size) {
static_cast<T*>(this)->vertex1 = static_cast<const T*>(this)->vertex0.add(size.width, 0);
static_cast<T*>(this)->vertex2 = static_cast<const T*>(this)->vertex0.add(0, size.height);
static_cast<T*>(this)->vertex3 = static_cast<const T*>(this)->vertex0.add(size.width, size.height);
return *static_cast<T*>(this);
}
constexpr T& set_rect_size_fast(const SizeI16& size) {
static_cast<T*>(this)->vertex1.x = static_cast<const T*>(this)->vertex0.x + size.width;
static_cast<T*>(this)->vertex2.y = static_cast<const T*>(this)->vertex0.y + size.height;
static_cast<T*>(this)->vertex3 = static_cast<const T*>(this)->vertex0.add(size.width, size.height);
return *static_cast<T*>(this);
}
constexpr PositionI16 get_rect_pos() const {
return PositionI16::create(
static_cast<const T*>(this)->vertex0.x,
static_cast<const T*>(this)->vertex0.y
);
}
constexpr SizeI16 get_rect_size() const {
return SizeI16::create(
static_cast<const T*>(this)->vertex1.x - static_cast<const T*>(this)->vertex0.x,
static_cast<const T*>(this)->vertex2.y - static_cast<const T*>(this)->vertex0.y
);
}
};
}
/*
1
/ \
3 - 2
*/
struct POLY_F3 : public internal::RenderPrimitive<POLY_F3>, public internal::PolyCodeInterface<POLY_F3>, public internal::Poly3Interface<POLY_F3>, public internal::LinkedElementCreator<POLY_F3> {
static constexpr auto IdentityCode = Code::create().set(Code::FlatShading).set(Code::TriVertics).set(Code::Untextured).set(Code::NonTransparent);
Color24 color; // a
Code code; // a
Vertex vertex0; // b
Vertex vertex1; // c
Vertex vertex2; // d
static constexpr POLY_F3 create(const Vertex (&verticies)[3], Color24 color) {
return POLY_F3 {
.color = color, .code = IdentityCode,
.vertex0 = verticies[0],
.vertex1 = verticies[1],
.vertex2 = verticies[2]
};
}
};
struct POLY_FT3 : public internal::RenderPrimitive<POLY_FT3>, public internal::PolyCodeInterface<POLY_FT3>, public internal::Poly3Interface<POLY_FT3>, public internal::LinkedElementCreator<POLY_FT3> {
struct VertexEx {
Vertex position;
PageOffset tex_offset;
};
static constexpr auto IdentityCode = Code(POLY_F3::IdentityCode).set(Code::Textured);
Color24 color; // a
Code code; // a
Vertex vertex0; // b
PageOffset tex_offset0; // c
PageClut page_clut; // c
Vertex vertex1; // d
PageOffset tex_offset1; // e
TPage tpage; // e
Vertex vertex2; // f
PageOffset tex_offset2; // g
uint16_t padded2; // g
static constexpr POLY_FT3 create(const Vertex (&verticies)[3], const PageOffset (&tex_offsets)[3], TPage tpage, PageClut clut, Color24 color = Color24::Grey()) {
return POLY_FT3::create({
{verticies[0], tex_offsets[0]},
{verticies[1], tex_offsets[1]},
{verticies[2], tex_offsets[2]}
}, tpage, clut, color);
}
static constexpr POLY_FT3 create(const VertexEx (&vertices_ex)[3], TPage tpage, PageClut clut, Color24 color) {
return POLY_FT3 {
.color = color, .code = IdentityCode,
.vertex0 = vertices_ex[0].position, .tex_offset0 = vertices_ex[0].tex_offset, .page_clut = clut,
.vertex1 = vertices_ex[1].position, .tex_offset1 = vertices_ex[1].tex_offset, .tpage = tpage,
.vertex2 = vertices_ex[2].position, .tex_offset2 = vertices_ex[2].tex_offset};
}
};
struct POLY_G3 : public internal::RenderPrimitive<POLY_G3>, public internal::PolyCodeInterface<POLY_G3>, public internal::Poly3Interface<POLY_G3>, public internal::LinkedElementCreator<POLY_G3> {
static constexpr auto IdentityCode = Code(POLY_F3::IdentityCode).set(Code::GouraudShading);
Color24 color0; // a
Code code; // a
Vertex vertex0; // b
Color24 color1; // c
uint8_t pad1; // c
Vertex vertex1; // d
Color24 color2; // e
uint8_t pad2; // e
Vertex vertex2; // f
static constexpr POLY_G3 create(const Vertex (&verticies)[3], const Color24 (&color)[3]) {
return POLY_G3::create({
{verticies[0], color[0]},
{verticies[1], color[1]},
{verticies[2], color[2]}
});
}
static constexpr POLY_G3 create(const VertexColor (&verticies_ex)[3]) {
return POLY_G3 {
.color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position,
.color1 = verticies_ex[1].color, .pad1 = 0, .vertex1 = verticies_ex[1].position,
.color2 = verticies_ex[2].color, .pad2 = 0, .vertex2 = verticies_ex[2].position
};
}
};
struct POLY_GT3 : public internal::RenderPrimitive<POLY_GT3>, public internal::PolyCodeInterface<POLY_GT3>, public internal::Poly3Interface<POLY_GT3>, public internal::LinkedElementCreator<POLY_GT3> {
struct VertexEx {
Vertex position;
PageOffset tex_offset;
Color24 color;
};
static constexpr auto IdentityCode = Code(POLY_G3::IdentityCode).set(Code::Textured);
Color24 color0; // a
Code code; // a
Vertex vertex0; // b
PageOffset tex_offset0; // c
PageClut page_clut; // c
Color24 color1; // d
uint8_t pad1; // d
Vertex vertex1; // e
PageOffset tex_offset1; // f
TPage tpage; // f
Color24 color2; // g
uint8_t pad2; // g
Vertex vertex2; // h
PageOffset tex_offset2; // i
uint16_t pad3; // i
static constexpr POLY_GT3 create(const Vertex (&verticies)[3], const PageOffset (&tex_offsets)[3], const Color24 (&color)[3], TPage tpage, PageClut clut) {
return POLY_GT3::create({
{verticies[0], tex_offsets[0], color[0]},
{verticies[1], tex_offsets[1], color[1]},
{verticies[2], tex_offsets[2], color[2]}
}, tpage, clut);
}
static constexpr POLY_GT3 create(const VertexEx (&verticies_ex)[3], TPage tpage, PageClut clut) {
return POLY_GT3 {
.color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position, .tex_offset0 = verticies_ex[0].tex_offset, .page_clut = clut,
.color1 = verticies_ex[1].color, .pad1 = 0, .vertex1 = verticies_ex[1].position, .tex_offset1 = verticies_ex[1].tex_offset, .tpage = tpage,
.color2 = verticies_ex[2].color, .pad2 = 0, .vertex2 = verticies_ex[2].position, .tex_offset2 = verticies_ex[2].tex_offset, .pad3 = 0
};
}
};
/*
1 - 2
| |
3 - 4
*/
struct POLY_F4 : public internal::RenderPrimitive<POLY_F4>, public internal::PolyCodeInterface<POLY_F4>, public internal::Poly4Interface<POLY_F4>, public internal::LinkedElementCreator<POLY_F4> {
static constexpr auto IdentityCode = Code(POLY_F3::IdentityCode).set(Code::QuadVertics);
Color24 color; // a
Code code; // a
Vertex vertex0; // b
Vertex vertex1; // c
Vertex vertex2; // d
Vertex vertex3; // e
static constexpr POLY_F4 create(const Vertex (&verticies)[4], Color24 color) {
return POLY_F4 {
.color = color, .code = IdentityCode,
.vertex0 = verticies[0],
.vertex1 = verticies[1],
.vertex2 = verticies[2],
.vertex3 = verticies[3]
};
}
static constexpr POLY_F4 create(const AreaI16& area, Color24 color) {
return POLY_F4::create({
POLY_F4::vertex0_from(area),
POLY_F4::vertex1_from(area),
POLY_F4::vertex2_from(area),
POLY_F4::vertex3_from(area)
}, color);
}
};
struct POLY_FT4 : public internal::RenderPrimitive<POLY_FT4>, public internal::PolyCodeInterface<POLY_FT4>, public internal::Poly4Interface<POLY_FT4>, public internal::LinkedElementCreator<POLY_FT4> {
typedef POLY_FT3::VertexEx VertexEx;
static constexpr auto IdentityCode = Code(POLY_FT3::IdentityCode).set(Code::QuadVertics);
Color24 color; // a
Code code; // a
Vertex vertex0; // b
PageOffset tex_offset0; // c
PageClut page_clut; // c
Vertex vertex1; // d
PageOffset tex_offset1; // e
TPage tpage; // e
Vertex vertex2; // f
PageOffset tex_offset2; // g
uint16_t pad2; // g
Vertex vertex3; // h
PageOffset tex_offset3; // i
uint16_t pad3; // i
static constexpr POLY_FT4 create(const Vertex (&verticies)[4], const PageOffset (&tex_offsets)[4], TPage tpage, PageClut clut, Color24 color = Color24::Grey()) {
return POLY_FT4::create({
{verticies[0], tex_offsets[0]},
{verticies[1], tex_offsets[1]},
{verticies[2], tex_offsets[2]},
{verticies[3], tex_offsets[3]}
}, tpage, clut, color);
}
static constexpr POLY_FT4 create(const VertexEx (&vertices_ex)[4], TPage tpage, PageClut clut, Color24 color = Color24::Grey()) {
return POLY_FT4 {
.color = color, .code = IdentityCode,
.vertex0 = vertices_ex[0].position, .tex_offset0 = vertices_ex[0].tex_offset, .page_clut = clut,
.vertex1 = vertices_ex[1].position, .tex_offset1 = vertices_ex[1].tex_offset, .tpage = tpage,
.vertex2 = vertices_ex[2].position, .tex_offset2 = vertices_ex[2].tex_offset, .pad2 = 0,
.vertex3 = vertices_ex[3].position, .tex_offset3 = vertices_ex[3].tex_offset, .pad3 = 0
};
}
static constexpr POLY_FT4 create(const AreaI16& area, const PageOffset& tex_offset, TPage tpage, PageClut clut, Color24 color = Color24::Grey()) {
return POLY_FT4::create({
{POLY_FT4::vertex0_from(area), tex_offset},
{POLY_FT4::vertex1_from(area), tex_offset.move(area.size.width - 1, 0)},
{POLY_FT4::vertex2_from(area), tex_offset.move(0, area.size.height - 1)},
{POLY_FT4::vertex3_from(area), tex_offset.move(area.size.width - 1, area.size.height - 1)}
}, tpage, clut, color);
}
};
struct POLY_G4 : public internal::RenderPrimitive<POLY_G4>, public internal::PolyCodeInterface<POLY_G4>, public internal::Poly4Interface<POLY_G4>, public internal::LinkedElementCreator<POLY_G4> {
static constexpr auto IdentityCode = Code(POLY_G3::IdentityCode).set(Code::QuadVertics);
Color24 color0; // a
Code code; // a
Vertex vertex0; // b
Color24 color1; // c
uint8_t pad1; // c
Vertex vertex1; // d
Color24 color2; // e
uint8_t pad2; // e
Vertex vertex2; // f
Color24 color3; // g
uint8_t pad3; // g
Vertex vertex3; // h
static constexpr POLY_G4 create(const Vertex (&verticies)[4], const Color24 (&color)[4]) {
return POLY_G4::create({
{verticies[0], color[0]},
{verticies[1], color[1]},
{verticies[2], color[2]},
{verticies[3], color[3]}
});
}
static constexpr POLY_G4 create(const VertexColor (&verticies_ex)[4]) {
return POLY_G4 {
.color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position,
.color1 = verticies_ex[1].color, .pad1 = 0, .vertex1 = verticies_ex[1].position,
.color2 = verticies_ex[2].color, .pad2 = 0, .vertex2 = verticies_ex[2].position,
.color3 = verticies_ex[3].color, .pad3 = 0, .vertex3 = verticies_ex[3].position
};
}
static constexpr POLY_G4 create(const AreaI16& area, const Color24 (&color)[4]) {
return POLY_G4::create({
{POLY_FT4::vertex0_from(area), color[0]},
{POLY_FT4::vertex1_from(area), color[1]},
{POLY_FT4::vertex2_from(area), color[2]},
{POLY_FT4::vertex3_from(area), color[3]}
});
}
};
struct POLY_GT4 : public internal::RenderPrimitive<POLY_GT4>, public internal::PolyCodeInterface<POLY_GT4>, public internal::Poly4Interface<POLY_GT4>, public internal::LinkedElementCreator<POLY_GT4> {
typedef POLY_GT3::VertexEx VertexEx;
static constexpr auto IdentityCode = Code(POLY_GT3::IdentityCode).set(Code::QuadVertics);
Color24 color0; // a
Code code; // a
Vertex vertex0; // b
PageOffset tex_offset0; // c
PageClut page_clut; // c
Color24 color1; // d
uint8_t pad1; // d
Vertex vertex1; // e
PageOffset tex_offset1; // f
TPage tpage; // f
Color24 color2; // g
uint8_t pad2; // g
Vertex vertex2; // h
PageOffset tex_offset2; // i
uint16_t pad3; // i
Color24 color3; // j
uint8_t pad4; // j
Vertex vertex3; // k
PageOffset tex_offset3; // l
uint16_t pad5; // l
static constexpr POLY_GT4 create(const Vertex (&verticies)[4], const PageOffset (&tex_offsets)[4], const Color24 (&color)[4], TPage tpage, PageClut clut) {
return POLY_GT4::create({
{verticies[0], tex_offsets[0], color[0]},
{verticies[1], tex_offsets[1], color[1]},
{verticies[2], tex_offsets[2], color[2]},
{verticies[3], tex_offsets[3], color[3]},
}, tpage, clut);
}
static constexpr POLY_GT4 create(const VertexEx (&verticies_ex)[4], TPage tpage, PageClut clut) {
return POLY_GT4 {
.color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position, .tex_offset0 = verticies_ex[0].tex_offset, .page_clut = clut,
.color1 = verticies_ex[1].color, .pad1 = 0, .vertex1 = verticies_ex[1].position, .tex_offset1 = verticies_ex[1].tex_offset, .tpage = tpage,
.color2 = verticies_ex[2].color, .pad2 = 0, .vertex2 = verticies_ex[2].position, .tex_offset2 = verticies_ex[2].tex_offset, .pad3 = 0,
.color3 = verticies_ex[3].color, .pad4 = 0, .vertex3 = verticies_ex[3].position, .tex_offset3 = verticies_ex[3].tex_offset, .pad5 = 0
};
}
static constexpr POLY_GT4 create(const AreaI16& area, const PageOffset& tex_offset, TPage tpage, PageClut clut, const Color24 (&color)[4]) {
return POLY_GT4::create({
{POLY_FT4::vertex0_from(area), tex_offset, color[0]},
{POLY_FT4::vertex1_from(area), tex_offset.move(area.size.width, 0), color[1]},
{POLY_FT4::vertex2_from(area), tex_offset.move(0, area.size.height), color[2]},
{POLY_FT4::vertex3_from(area), tex_offset.move(area.size.width, area.size.height), color[3]}
}, tpage, clut);
}
};
#define __jabyengine_poly_top_left(x, y, w, h) x, y
#define __jabyengine_poly_top_right(x, y, w, h) (x + w), y
#define __jabyengine_poly_bottom_left(x, y, w, h) x, (y + h)
#define __jabyengine_poly_bottom_right(x, y, w, h) (x + w), (y + h)
#define __jabyengine_polyFT4_vertex_rect(area, tex_off) { \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
}
#define __jabyengine_polyFT4_vertex_rect90(area, tex_off) { \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
}
#define __jabyengine_polyFT4_vertex_rect180(area, tex_off) { \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
}
#define __jabyengine_polyFT4_vertex_rect270(area, tex_off) { \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
}
typedef POLY_F3 FlatTriangle;
typedef POLY_FT3 FlatTexturedTriangle;
typedef POLY_G3 GouraudTriangle;
typedef POLY_GT3 GouraudTexturedTriangle;
typedef POLY_F4 FlatRectangle;
typedef POLY_FT4 FlatTexturedRectangle;
typedef POLY_G4 GouraudRectangle;
typedef POLY_GT4 GouraudTexturedRectangle;
static_assert(sizeof(POLY_F3) == 16);
static_assert(sizeof(POLY_FT3) == 28);
static_assert(sizeof(POLY_G3) == 24);
static_assert(sizeof(POLY_GT3) == 36);
static_assert(sizeof(POLY_F4) == 20);
static_assert(sizeof(POLY_FT4) == 36);
static_assert(sizeof(POLY_G4) == 32);
static_assert(sizeof(POLY_GT4) == 48);
}
}

View File

@ -0,0 +1,128 @@
#pragma once
#include "linked_elements.hpp"
#include "primitive_support_types.hpp"
namespace JabyEngine {
namespace GPU {
struct OffsetPageWithClut {
PageOffset tex_offset;
PageClut clut;
static constexpr OffsetPageWithClut create(PageOffset tex_offset, PageClut clut) {
return OffsetPageWithClut{tex_offset, clut};
}
};
namespace internal {
struct RectCode : public CodeBase<RectCode> {
enum struct SizeType : uint8_t {
Variable = 0,
Pixel1x1 = 1,
Sprite8x8 = 2,
Sprite16x16 = 3
};
static constexpr uint8_t CmdValue = 0b011;
static constexpr auto Size = BitRange::from_to(27 - BitCorrection, 28 - BitCorrection);
static constexpr RectCode create() {
return CodeBase<RectCode>::create(CmdValue);
}
};
template<typename T>
struct RectCodeInterface {
typedef typename ::JabyEngine::GPU::internal::RectCode Code;
constexpr T& set_semi_transparent(bool set = true) {
static_cast<T*>(this)->code.set_tenary(set, Code::SemiTransparent, Code::NonTransparent);
return *static_cast<T*>(this);
}
};
template<typename RectCode::SizeType Size>
struct RECT_BASE_F : public RectCodeInterface<RECT_BASE_F<Size>> {
typedef RectCodeInterface<RECT_BASE_F<Size>>::Code Code;
static constexpr auto IdentityCode = Code::create().set(Code::Size.with(static_cast<uint8_t>(Size))).set(Code::Untextured).set(Code::NonTransparent);
Color24 color;
Code code;
Vertex position;
static constexpr RECT_BASE_F create(const Vertex& position, const Color24& color) {
return RECT_BASE_F {
.color = color, .code = IdentityCode, .position = position
};
}
};
template<typename RectCode::SizeType Size>
struct RECT_BASE_T : public RectCodeInterface<RECT_BASE_T<Size>> {
typedef RectCodeInterface<RECT_BASE_T<Size>>::Code Code;
static constexpr auto IdentityCode = Code(RECT_BASE_F<Size>::IdentityCode).set(Code::Textured);
Color24 color;
Code code;
Vertex position;
PageOffset tex_offset;
PageClut clut;
static constexpr RECT_BASE_T create(const Vertex& position, const OffsetPageWithClut& tex_offset_w_clut, const Color24& color = Color24::Grey()) {
return RECT_BASE_T {
.color = color, .code = IdentityCode, .position = position, .tex_offset = tex_offset_w_clut.tex_offset, .clut = tex_offset_w_clut.clut
};
}
};
template<typename RectCode::SizeType Size>
struct RECT_F : public RECT_BASE_F<Size>, public internal::RenderPrimitive<RECT_F<Size>>, public internal::LinkedElementCreator<RECT_F<Size>> {
static constexpr RECT_F create(const Vertex& position, const Color24& color) {
RECT_F rect;
static_cast<RECT_BASE_F<Size>&>(rect) = RECT_BASE_F<Size>::create(position, color);
return rect;
}
};
template<typename RectCode::SizeType Size>
struct RECT_T : public RECT_BASE_T<Size>, public internal::RenderPrimitive<RECT_T<Size>>, public internal::LinkedElementCreator<RECT_T<Size>> {
static constexpr RECT_T create(const Vertex& position, const OffsetPageWithClut& tex_offset_w_clut, const Color24& color = Color24::Grey()) {
RECT_T rect;
static_cast<RECT_BASE_T<Size>&>(rect) = RECT_BASE_T<Size>::create(position, tex_offset_w_clut, color);
return rect;
}
};
}
typedef internal::RECT_F<internal::RectCode::SizeType::Pixel1x1> TILE_1;
typedef internal::RECT_F<internal::RectCode::SizeType::Sprite8x8> TILE_8;
typedef internal::RECT_F<internal::RectCode::SizeType::Sprite16x16> TILE_16;
struct TILE : public internal::RECT_BASE_F<internal::RectCode::SizeType::Variable>, public internal::RenderPrimitive<TILE>, public internal::LinkedElementCreator<TILE> {
SizeI16 size;
static constexpr TILE create(const AreaI16& area, const Color24& color) {
TILE tile;
static_cast<RECT_BASE_F&>(tile) = RECT_BASE_F::create(area.position, color);
tile.size = area.size;
return tile;
}
};
typedef internal::RECT_T<internal::RectCode::SizeType::Pixel1x1> SPRT_1;
typedef internal::RECT_T<internal::RectCode::SizeType::Sprite8x8> SPRT_8;
typedef internal::RECT_T<internal::RectCode::SizeType::Sprite16x16> SPRT_16;
struct SPRT : public internal::RECT_BASE_T<internal::RectCode::SizeType::Variable>, public internal::RenderPrimitive<SPRT>, public internal::LinkedElementCreator<SPRT> {
SizeI16 size;
static constexpr SPRT create(const AreaI16& area, const OffsetPageWithClut& page, const Color24& color = Color24::Grey()) {
SPRT sprt;
static_cast<RECT_BASE_T&>(sprt) = RECT_BASE_T::create(area.position, page, color);
sprt.size = area.size;
return sprt;
}
};
}
}

View File

@ -0,0 +1,98 @@
#pragma once
#include "../../Auxiliary/type_traits.hpp"
#include "../../System/IOPorts/gpu_io.hpp"
#include "../gpu_types.hpp"
namespace JabyEngine {
namespace GPU {
namespace internal {
template<typename T>
struct CodeBase {
static constexpr auto BitCorrection = 24;
static constexpr auto CmdID = BitRange::from_to(29 - BitCorrection, 31 - BitCorrection);
uint8_t value;
// Common values for all the primitves
static constexpr auto Textured = Bit(26 - BitCorrection);
static constexpr auto Untextured = !Textured;
static constexpr auto SemiTransparent = Bit(25 - BitCorrection);
static constexpr auto NonTransparent = !SemiTransparent;
static constexpr auto NoBlendTexture = Bit(24 - BitCorrection);
static constexpr auto BlendTexture = !NoBlendTexture;
static constexpr T create(uint8_t value) {
return T{bit::value::set_normalized<uint8_t>(0u, CmdID.with(value))};
}
static constexpr T create(const T& code) {
return CodeBase::create(code.value);
}
constexpr T& set(Bit bit) {
this->value = bit::set(this->value, bit);
return static_cast<T&>(*this);
}
constexpr T& set(ClearBit bit) {
this->value = bit::set(this->value, bit);
return static_cast<T&>(*this);
}
constexpr T& set(BitRange::RangeValuePair<uint8_t> value_pair) {
this->value = bit::value::set_normalized(this->value, value_pair);
return static_cast<T&>(*this);
}
template<typename S, typename R>
constexpr T& set_tenary(bool use_first, const S& first, const R& second) {
if(use_first) {
return this->set(first);
}
else {
return this->set(second);
}
}
};
template<typename T>
struct RenderPrimitive {
static constexpr bool is_render_primitive = true;
void set_identitiy() {
static_cast<T&>(*this).code = T::IdentityCode;
}
};
}
struct PageClut {
uint16_t value;
static constexpr PageClut create(uint16_t x, uint16_t y) {
return PageClut{static_cast<uint16_t>((y << 6) | ((x >> 4) & 0x3f))};
}
static constexpr PageClut create(const PositionU16& clut_pos) {
return PageClut::create(clut_pos.x, clut_pos.y);
}
};
struct TPage {
static constexpr auto TexturePageX = BitRange::from_to(0, 3);
static constexpr auto TexturePageY = BitRange::from_to(4, 4);
static constexpr auto SemiTransparency = BitRange::from_to(5, 6);
static constexpr auto TextureClut = BitRange::from_to(7, 8);
uint16_t value;
static constexpr TPage create(uint16_t x, uint16_t y, ::JabyEngine::GPU::SemiTransparency transparency, TextureColorMode clut_color) {
return TPage{static_cast<uint16_t>(TexturePageX.as_value(x >> 6) | TexturePageY.as_value(y >> 8) | SemiTransparency.as_value(static_cast<uint16_t>(transparency)) | TextureClut.as_value(static_cast<uint16_t>(clut_color)))};
}
static constexpr TPage create(const PositionU16& pos, ::JabyEngine::GPU::SemiTransparency transparency, TextureColorMode clut_color) {
return TPage::create(pos.x, pos.y, transparency, clut_color);
}
};
}
}

View File

@ -1,6 +1,8 @@
#ifndef __JABYENGINE_GPU_HPP__
#define __JABYENGINE_GPU_HPP__
#pragma once
#include "../Auxiliary/type_traits.hpp"
#include "../System/IOPorts/gpu_io.hpp"
#include "../jabyengine_config.hpp"
#include "gpu_primitives.hpp"
#if !defined(JABYENGINE_NTSC) && !defined(JABYENGINE_PAL)
#error "JABYENGINE_NTSC or JABYENGINE_PAL must be defined"
@ -12,29 +14,71 @@
namespace JabyEngine {
namespace GPU {
namespace internal {
void render(const uint32_t* data, size_t words);
void render_dma(const uint32_t* data);
}
struct Display {
#ifdef JABYENGINE_PAL
static constexpr size_t Width = 320;
static constexpr size_t Height = 256;
static constexpr uint32_t frames_per_sec = 50;
#else
static constexpr size_t Width = 320;
static constexpr size_t Height = 240;
static constexpr uint32_t frames_per_sec = 60;
#endif
static uint8_t current_id;
template<typename T>
static constexpr Area<T> center(const Area<T>& area) {
return Area<T>::create(Position<T>::create((Display::Width - area.size.width)/2, (Display::Height - area.size.height)/2), area.size);
}
static void enable() {
GPU_IO::GP1 = GPU_IO::Command::SetDisplayState(GPU_IO::DisplayState::On);
GPU_IO::GP1.set_display_state(GPU_IO_Values::DisplayMode::State::On);
}
static void disable() {
GPU_IO::GP1 = GPU_IO::Command::SetDisplayState(GPU_IO::DisplayState::Off);
GPU_IO::GP1.set_display_state(GPU_IO_Values::DisplayMode::State::Off);
}
};
struct Screen {
static uint8_t CurrentDisplayAreaID;
static void set_offset(uint16_t x, uint16_t y);
static void set_offset(int16_t x, int16_t y);
};
using VSyncCallback = void (*)();
static uint32_t update_id() {
return Display::current_id;
}
static uint32_t render_id() {
return Display::current_id ^ 1;
}
void set_vsync_callback(VSyncCallback callback);
template<typename T>
static void render(const LinkedElement<T>& linked_primitives) {
internal::render_dma(&linked_primitives.link_value);
}
template<typename T>
static enable_if<T::is_render_primitive>::type render(const T& primitive) {
internal::render(reinterpret_cast<const uint32_t*>(&primitive), sizeof(T)/sizeof(uint32_t));
}
template<typename T, size_t N>
static enable_if<T::is_render_primitive>::type render(const LINE_F (&primitives)[N]) {
internal::render(reinterpret_cast<const uint32_t*>(&primitives), (sizeof(T)/sizeof(uint32_t))*N);
}
static void wait_for_render() {
while(!GPU_IO::GPUSTAT.read().is_set(GPU_IO_Values::GPUSTAT::GP0ReadyForCMD));
}
void swap_buffers(bool clear_screen = true);
uint8_t swap_buffers_vsync(uint8_t syncs, bool clear_screen = true);
}
}
#endif //!__JABYENGINE_GPU_HPP__

View File

@ -0,0 +1,35 @@
#pragma once
#include "../jabyengine_config.hpp"
#include "gpu_primitives.hpp"
namespace JabyEngine {
namespace GPU {
struct BIOS_Font {
// This size is by Hardware limitation
static constexpr auto Size = SizeU16::create(16, 16);
static constexpr auto TextureLoadPos = Configuration::BIOSFont::texture_load_pos();
static constexpr auto CLUTLoadPos = Configuration::BIOSFont::CLUT_load_pos();
static constexpr TexPage get_tex_page() {
return TexPage::create(BIOS_Font::TextureLoadPos, GPU::TextureColorMode::clut4);
}
static constexpr TPage get_tpage() {
return TPage::create(TextureLoadPos.x, TextureLoadPos.y, SemiTransparency::B_add_F, TextureColorMode::clut4);
}
static constexpr PageOffset get_offset_page() {
return PageOffset::create(BIOS_Font::CLUTLoadPos.x & 0x3F, BIOS_Font::CLUTLoadPos.y & 0xFF);
}
static constexpr PageClut get_page_clut() {
return PageClut::create(BIOS_Font::CLUTLoadPos);
}
static constexpr OffsetPageWithClut get_offset_page_with_clut() {
return OffsetPageWithClut::create(BIOS_Font::get_offset_page(), BIOS_Font::get_page_clut());
}
};
}
}

View File

@ -0,0 +1,6 @@
#pragma once
#include "../Auxiliary/literals.hpp"
#include "Primitives/primitive_gpu_commands.hpp"
#include "Primitives/primitive_line_types.hpp"
#include "Primitives/primitive_rectangle_types.hpp"
#include "Primitives/primitive_poly_types.hpp"

View File

@ -1,102 +1,329 @@
#ifndef __JABYENGINE_GPU_TYPES_HPP__
#define __JABYENGINE_GPU_TYPES_HPP__
#include "../jabyengine_defines.h"
#pragma once
#include "../Auxiliary/bits.hpp"
#include "../jabyengine_defines.hpp"
namespace JabyEngine {
namespace GPU {
struct Color24 {
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 0;
namespace internal {
template<typename T, typename S>
struct XYMovement {
constexpr T& add(S dx, S dy) {
static_cast<T*>(this)->x += dx;
static_cast<T*>(this)->y += dy;
constexpr Color24() = default;
constexpr Color24(uint8_t r, uint8_t g, uint8_t b) : blue(b), green(g), red(r) {
return *static_cast<T*>(this);
}
constexpr T add(S dx, S dy) const {
return T::create(static_cast<const T*>(this)->x, static_cast<const T*>(this)->y).add(dx, dy);
}
constexpr T& add(const T& offset) {
return add(offset.x, offset.y);
}
constexpr T add(const T& offset) const {
return add(offset.x, offset.y);
}
constexpr T& sub(S dx, S dy) {
static_cast<T*>(this)->x -= dx;
static_cast<T*>(this)->y -= dy;
return *static_cast<T*>(this);
}
constexpr T sub(S dx, S dy) const {
return T::create(static_cast<const T*>(this)->x, static_cast<const T*>(this)->y).sub(dx, dy);
}
constexpr T& sub(const T& offset) {
return sub(offset.x, offset.y);
}
constexpr T sub(const T& offset) const {
return sub(offset.x, offset.y);
}
constexpr T& move(S dx, S dy) {
return this->add(dx, dy);
}
constexpr T move(S dx, S dy) const {
return T::create(static_cast<const T*>(this)->x, static_cast<const T*>(this)->y).move(dx, dy);
}
};
template<typename T>
struct PredefinedColors {
static constexpr T Black() {
return T::from_rgb(0, 0, 0);
}
static constexpr T Grey() {
return T::from_rgb(0x80, 0x80, 0x80);
}
static constexpr T White(uint8_t base = 0xFF) {
return T::from_rgb(base, base, base);
}
static constexpr T Red(uint8_t base = 0xFF) {
return T::from_rgb(base, 0x0, 0x0);
}
static constexpr T Green(uint8_t base = 0xFF) {
return T::from_rgb(0x0, base, 0x0);
}
static constexpr T Blue(uint8_t base = 0xFF) {
return T::from_rgb(0x0, 0x0, base);
}
static constexpr T Yellow(uint8_t base = 0xFF) {
return T::from_rgb(base, base, 0x0);
}
static constexpr T Purple(uint8_t base = 0xFF) {
return T::from_rgb(base, 0x0, base);
}
static constexpr T Turquoise(uint8_t base = 0xFF) {
return T::from_rgb(0x0, base, base);
}
};
}
enum struct SemiTransparency {
B_Half_add_F_Half = 0,
B_add_F = 1,
B_sub_F = 2,
B_add_F_Quarter = 3,
};
enum struct TextureColorMode {
clut4 = 0,
clut8 = 1,
direct16 = 2,
};
struct Color24 : public internal::PredefinedColors<Color24> {
uint8_t red;
uint8_t green;
uint8_t blue;
static constexpr Color24 from_rgb(uint8_t r, uint8_t g, uint8_t b) {
return Color24{.red = r, .green = g, .blue = b};
}
constexpr uint32_t raw() const {
return ((this->blue << 16) | (this->green << 8) | this->red);
}
static constexpr Color24 Black() {
return Color24(0, 0, 0);
}
static constexpr Color24 White() {
return Color24(0xFF, 0xFF, 0xFF);
}
static constexpr Color24 Red() {
return Color24(0xFF, 0x0, 0x0);
}
static constexpr Color24 Green() {
return Color24(0x0, 0xFF, 0x0);
}
static constexpr Color24 Blue() {
return Color24(0x0, 0x0, 0xFF);
constexpr Color24 invert() const {
return Color24::from_rgb(this->red^0xFF, this->green^0xFF, this->blue^0xFF);
}
};
class Color {
private:
struct Color : public internal::PredefinedColors<Color> {
static constexpr auto RedRange = BitRange::from_to(0, 4);
static constexpr auto GreenRange = BitRange::from_to(5, 9);
static constexpr auto BlueRange = BitRange::from_to(10, 14);
static constexpr auto SemiTransperancyBit = Bit(15);
uint16_t value = 0;
uint16_t raw;
public:
static constexpr Color from_rgb(uint8_t r, uint8_t g, uint8_t b) {
return Color().set_red(r).set_green(g).set_blue(b);
return Color().set_red(r >> 3).set_green(g >> 3).set_blue(b >> 3);
}
static constexpr Color from(const Color24& color) {
return Color::from_rgb(color.red, color.green, color.blue);
}
constexpr Color invert() const {
return Color{.raw = static_cast<uint16_t>(this->raw^0xFFFF)};
}
constexpr Color& set_red(uint8_t red) {
this->value = bit::value::set_normalized(this->value, RedRange.with(red));
this->raw = bit::value::set_normalized(this->raw, RedRange.with(red));
return *this;
}
constexpr Color& set_green(uint8_t green) {
this->value = bit::value::set_normalized(this->value, GreenRange.with(green));
this->raw = bit::value::set_normalized(this->raw, GreenRange.with(green));
return *this;
}
constexpr Color& set_blue(uint8_t blue) {
this->value = bit::value::set_normalized(this->value, BlueRange.with(blue));
this->raw = bit::value::set_normalized(this->raw, BlueRange.with(blue));
return *this;
}
};
template<typename T>
struct Position {
T x = 0;
T y = 0;
struct LookUpColor8 {
uint8_t lu_id[2];
constexpr Position() = default;
constexpr Position(T x, T y) : x(x), y(y) {
static constexpr LookUpColor8 create(const uint8_t (&data)[2]) {
return LookUpColor8::create(data[0], data[1]);
}
static constexpr LookUpColor8 create(uint8_t px0, uint8_t px1) {
return LookUpColor8{{px0, px1}};
}
constexpr uint8_t get_lu_id(size_t at) const {
return this->lu_id[at];
}
constexpr void set_lu_id(uint8_t new_lu_id, size_t at) {
this->lu_id[at] = new_lu_id;
}
};
struct LookUpColor4 {
uint8_t lu_id[2];
static constexpr LookUpColor4 create(const uint8_t (&data)[4]) {
return LookUpColor4::create(data[0], data[1], data[2], data[3]);
}
static constexpr LookUpColor4 create(uint8_t px0, uint8_t px1, uint8_t px2, uint8_t px3) {
return LookUpColor4{{static_cast<uint8_t>((px1 << 4) | px0), static_cast<uint8_t>((px3 << 4) | px2)}};
}
};
template<typename T>
struct Position : public internal::XYMovement<Position<T>, T> {
using PrimitiveType = T;
T x;
T y;
static constexpr Position create(T x, T y) {
return Position{.x = x, .y = y};
}
};
using PositionI8 = Position<int8_t>;
using PositionU8 = Position<uint8_t>;
using PositionI16 = Position<int16_t>;
using PositionU16 = Position<uint16_t>;
using Vertex = PositionI16;
template<typename T>
struct Size {
T width = 0;
T height = 0;
T width;
T height;
constexpr Size() = default;
constexpr Size(T w, T h) : width(w), height(h) {
static constexpr Size create(T w, T h) {
return Size{w, h};
}
template<typename S>
static constexpr Size from(const Size<S>& size) {
return Size::create(static_cast<T>(size.width), static_cast<T>(size.height));
}
auto operator<=>(const Size<T>&) const = default;
};
using SizeI8 = Size<int8_t>;
using SizeU8 = Size<uint8_t>;
using SizeI16 = Size<int16_t>;
using SizeU16 = Size<uint16_t>;
template<typename T, typename S>
static constexpr T tile_id_for(S id, S row_count, Size<S> size) {
const auto x = id%row_count;
const auto y = id/row_count;
return T::create(static_cast<S>(size.width*x), static_cast<S>(size.height*y));
}
template<typename T, typename S>
static constexpr T tile_id_for16(S id, Size<S> size) {
const auto x = id&0xF;
const auto y = id >> 4;
return T::create(static_cast<S>(x*size.width), static_cast<S>(y*size.height));
}
template<typename T>
struct Area {
Position<T> position;
Size<T> size;
static constexpr Area create(Position<T> position, Size<T> size) {
return Area{position, size};
}
static constexpr Area create(T position_x, T position_y, T size_width, T size_height) {
return Area{Position<T>::create(position_x, position_y), Size<T>::create(size_width, size_height)};
}
constexpr Area centered() const {
return Area(this->position.sub(this->size.width/2, this->size.height/2), this->size);
}
constexpr Position<T> get_top_left() const {
return this->position;
}
constexpr Position<T> get_top_right() const {
return this->position.add(this->size.width, 0);
}
constexpr Position<T> get_bottom_left() const {
return this->position.add(0, this->size.height);
}
constexpr Position<T> get_bottom_right() const {
return this->position.move(this->size.width, this->size.height);
}
};
typedef Area<int16_t> AreaI16;
typedef Area<uint16_t> AreaU16;
// Type used for primitives
struct PageOffset : public internal::XYMovement<PageOffset, uint8_t> {
union {
uint8_t x;
uint8_t u;
};
union {
uint8_t y;
uint8_t v;
};
static constexpr PageOffset create(uint8_t u, uint8_t v) {
return PageOffset{.x = u, .y = v}; //< Activate x and y to use XYMovement during constexpr
}
static constexpr PageOffset from_tile_id(int16_t id, int16_t row_count, SizeI16 size) {
return tile_id_for<PageOffset>(id, row_count, size);
}
static constexpr PageOffset from_tile_id16(int16_t id, SizeI16 size) {
return tile_id_for16<PageOffset>(id, size);
}
};
typedef Position<int16_t> PositionI16;
typedef Position<uint16_t> PositionU16;
struct VertexColor {
Vertex position;
Color24 color;
typedef Size<int16_t> SizeI16;
typedef Size<uint16_t> SizeU16;
static constexpr VertexColor create(Vertex vertex, Color24 color) {
return VertexColor{vertex, color};
}
};
struct ColorVertex {
Color24 color;
alignas(2) Vertex position;
static constexpr ColorVertex create(Color24 color, Vertex vertex) {
return ColorVertex{color, vertex};
}
};
}
}
#endif //!__JABYENGINE_GPU_TYPES_HPP__

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