Compare commits
11 Commits
19890802a6
...
hans
| Author | SHA1 | Date | |
|---|---|---|---|
| 84a507da38 | |||
| 21a5e18e3b | |||
| 1b6007c323 | |||
| 6a05210aa1 | |||
| f13d50a9e1 | |||
| f65f4e3e55 | |||
| 3298623305 | |||
| f6adc18215 | |||
| 1b8d4e8c70 | |||
| 9d09b70bae | |||
| 49f45423d1 |
@@ -1,46 +1,60 @@
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
project(HansTheGatherer)
|
||||
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/riscv-toolchain.cmake)
|
||||
|
||||
project(HansTheGatherer C CXX ASM)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# Option to switch real platform vs. SDL implementation...
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
SDL3
|
||||
URL https://github.com/libsdl-org/SDL/releases/download/release-3.2.14/SDL3-3.2.14.tar.gz
|
||||
OVERRIDE_FIND_PACKAGE
|
||||
)
|
||||
FetchContent_MakeAvailable(SDL3)
|
||||
|
||||
FetchContent_Declare(
|
||||
SDL3_ttf
|
||||
URL https://github.com/libsdl-org/SDL_ttf/releases/download/release-3.2.2/SDL3_ttf-3.2.2.tar.gz
|
||||
entt
|
||||
URL https://github.com/skypjack/entt/archive/refs/tags/v3.15.0.tar.gz
|
||||
OVERRIDE_FIND_PACKAGE
|
||||
)
|
||||
FetchContent_MakeAvailable(SDL3_ttf)
|
||||
FetchContent_MakeAvailable(entt)
|
||||
|
||||
FetchContent_Declare(
|
||||
flecs
|
||||
URL https://github.com/SanderMertens/flecs/archive/refs/tags/v4.0.5.tar.gz
|
||||
OVERRIDE_FIND_PACKAGE
|
||||
find_package(entt CONFIG REQUIRED)
|
||||
|
||||
add_library(RISCV_Options INTERFACE)
|
||||
target_compile_options(RISCV_Options INTERFACE
|
||||
-fno-exceptions
|
||||
-fno-unwind-tables
|
||||
-fno-rtti
|
||||
-fno-pic # PIC?
|
||||
-mno-relax
|
||||
-march=rv32im
|
||||
-mabi=ilp32
|
||||
-std=c++20
|
||||
)
|
||||
FetchContent_MakeAvailable(flecs)
|
||||
|
||||
find_package(SDL3 CONFIG REQUIRED)
|
||||
find_package(SDL3_ttf CONFIG REQUIRED)
|
||||
find_package(flecs CONFIG REQUIRED)
|
||||
find_package(spdlog CONFIG REQUIRED)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(wuehans)
|
||||
|
||||
add_executable(HansTheGatherer
|
||||
src/main.cpp
|
||||
src/audio.cpp
|
||||
src/assets.cpp
|
||||
src/level.cpp
|
||||
src/physics.cpp
|
||||
src/render.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(HansTheGatherer SDL3::SDL3 SDL3_ttf::SDL3_ttf flecs::flecs spdlog::spdlog)
|
||||
target_link_options(HansTheGatherer PRIVATE
|
||||
-nostartfiles
|
||||
-Wl,--gc-sections
|
||||
-march=rv32im
|
||||
-mabi=ilp32
|
||||
-lstdc++
|
||||
-lc
|
||||
-lgcc
|
||||
-mcmodel=medany
|
||||
)
|
||||
|
||||
set_property(TARGET HansTheGatherer PROPERTY CXX_STANDARD 20)
|
||||
target_link_libraries(HansTheGatherer PRIVATE
|
||||
RISCV_Options
|
||||
WueHans
|
||||
Hall
|
||||
EnTT
|
||||
)
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 228 KiB After Width: | Height: | Size: 912 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 375 KiB |
|
Before Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 32 KiB |
BIN
assets/sounds/hit.raw
Normal file
BIN
assets/sounds/pickup.raw
Normal file
19
cmake/riscv-toolchain.cmake
Normal file
@@ -0,0 +1,19 @@
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_PROCESSOR riscv)
|
||||
|
||||
set(RISCV_PREFIX riscv32-unknown-elf)
|
||||
set(CMAKE_C_COMPILER ${RISCV_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${RISCV_PREFIX}-g++)
|
||||
set(CMAKE_ASM_COMPILER ${RISCV_PREFIX}-gcc)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH root)
|
||||
|
||||
# Don't run the linker on compiler check
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
|
||||
# adjust the default behavior of the FIND_XXX() commands:
|
||||
# search programs in the host environment
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
# search headers and libraries in the target environment
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
1
lib/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
add_subdirectory(Hall)
|
||||
11
lib/Hall/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
add_library(Hall STATIC
|
||||
source/Audio.cpp
|
||||
source/System.cpp
|
||||
source/Video.cpp
|
||||
)
|
||||
|
||||
target_include_directories(Hall
|
||||
PUBLIC SYSTEM include
|
||||
)
|
||||
|
||||
target_link_libraries(Hall PRIVATE RISCV_Options)
|
||||
2
lib/Hall/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# Hall
|
||||
Hallo, hier ist Hall
|
||||
63
lib/Hall/include/Hall/Audio.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
namespace Hall
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the global volume. 0 is muted, 128 is the default, 255 is max
|
||||
/// </summary>
|
||||
/// <param name="volume">0 is muted, 128 is the default, 255 is max</param>
|
||||
void SetGlobalVolume(unsigned char volume);
|
||||
|
||||
/// <summary>
|
||||
/// Prepares a channel to be used to play a non-looped single-channel audio
|
||||
/// </summary>
|
||||
/// <param name="channelID">The ID of the channel. Must be within [0,7]</param>
|
||||
/// <param name="data">A pointer to the first sample of the audio data</param>
|
||||
/// <param name="sampleCount">The total number of samples in the audio data</param>
|
||||
/// <param name="volume">The channel's local volume. 0 is muted, 128 is the default, 255 is max</param>
|
||||
void SetupMono(int channelID, short* data, int sampleCount, unsigned char volume = 128);
|
||||
|
||||
/// <summary>
|
||||
/// Prepares a channel to be used to play a looped single-channel audio
|
||||
/// </summary>
|
||||
/// <param name="channelID">The ID of the channel. Must be within [0,7]</param>
|
||||
/// <param name="data">A pointer to the first sample of the audio data</param>
|
||||
/// <param name="sampleCount">The total number of samples in the audio data</param>
|
||||
/// <param name="loopStart">The index of the first sample of the loop (inclusive)</param>
|
||||
/// <param name="loopEnd">The index of the last sample of the loop (exclusive?)</param>
|
||||
/// <param name="volume">The channel's local volume. 0 is muted, 128 is the default, 255 is max</param>
|
||||
void SetupMono(int channelID, short* data, int sampleCount, unsigned int loopStart, unsigned int loopEnd, unsigned char volume = 128);
|
||||
|
||||
/// <summary>
|
||||
/// Prepares two channels to be used to play a non-looped stereo audio
|
||||
/// </summary>
|
||||
/// <param name="channelID_left">The ID of the channel for the left audio. Must be within [0,7]</param>
|
||||
/// <param name="channelID_right">The ID of the channel for the right audio. Must be within [0,7]</param>
|
||||
/// <param name="data">A pointer to the first sample of the audio data</param>
|
||||
/// <param name="sampleCount">The total number of samples PER CHANNEL in the audio data</param>
|
||||
/// <param name="volume">The channel's local volume. 0 is muted, 128 is the default, 255 is max</param>
|
||||
void SetupStereo(int channelID_left, int channelID_right, short* data, int sampleCount, unsigned char volume = 128);
|
||||
|
||||
/// <summary>
|
||||
/// Prepares two channels to be used to play a looped stereo audio
|
||||
/// </summary>
|
||||
/// <param name="channelID_left">The ID of the channel for the left audio. Must be within [0,7]</param>
|
||||
/// <param name="channelID_right">The ID of the channel for the right audio. Must be within [0,7]</param>
|
||||
/// <param name="data">A pointer to the first sample of the audio data</param>
|
||||
/// <param name="sampleCount">The total number of samples PER CHANNEL in the audio data</param>
|
||||
/// <param name="loopStart">The index of the first sample of the loop (inclusive)</param>
|
||||
/// <param name="loopEnd">The index of the last sample of the loop (exclusive?)</param>
|
||||
/// <param name="volume">The channel's local volume. 0 is muted, 128 is the default, 255 is max</param>
|
||||
void SetupStereo(int channelID_left, int channelID_right, short* data, int sampleCount, unsigned int loopStart, unsigned int loopEnd, unsigned char volume = 128);
|
||||
|
||||
|
||||
void Play(unsigned char channelSelect);
|
||||
void Pause(unsigned char channelSelect);
|
||||
void SetData(unsigned char channelSelect, short* data);
|
||||
void SetLoop(unsigned char channelSelect, bool isLooping);
|
||||
void SetLoopBoundaries(unsigned char channelSelect, int start, int end);
|
||||
void SetPosition(unsigned char channelSelect, int position);
|
||||
void SetSample(unsigned char channelSelect, short sample);
|
||||
void SetVolume(unsigned char channelSelect, unsigned char volume);
|
||||
|
||||
}
|
||||
5
lib/Hall/include/Hall/Hall.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <Hall/System.h>
|
||||
#include <Hall/Video.h>
|
||||
#include <Hall/Audio.h>
|
||||
36
lib/Hall/include/Hall/System.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
namespace Hall
|
||||
{
|
||||
static const int SYSTEM_CLK_FREQUENCY = 50000000; //50 MHz
|
||||
static void* const SDRAM_START = 0x0; //Start of the RAM. It is 32 MB large
|
||||
static void* const BOOTLOADER_START = (void* const) 0x02010000; //Start of the bootloader. It is 32 kB large
|
||||
static void* const SD_CARD_START = (void* const) 0x80000000; //Start of the SD-Card
|
||||
|
||||
/// <summary>
|
||||
/// Returns an 8-Byte int, that represents the number of ticks that passed since the system's boot-up. Divide by SYSTEM_CLK_FREQUENCY to get seconds
|
||||
/// </summary>
|
||||
/// <returns>The system time since boot-up in ticks</returns>
|
||||
unsigned long long GetSystemTime();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the state of all buttons on the controller.
|
||||
/// </summary>
|
||||
/// <param name="id">Must be in the range [0,1]</param>
|
||||
/// <returns>Each button corresponds to one bit: 0 - B, 1 - Y, 2 - Select, 3 - Start, 4 - Up, 5 - Down, 6 - Left, 7 - Right, 8 - A, 9 - X, 10 - L, 11 - R</returns>
|
||||
unsigned short GetController(int id);
|
||||
|
||||
unsigned int GetSystemTimeExcerpt(int precision);
|
||||
bool GetA(unsigned short controller);
|
||||
bool GetB(unsigned short controller);
|
||||
bool GetX(unsigned short controller);
|
||||
bool GetY(unsigned short controller);
|
||||
bool GetStart(unsigned short controller);
|
||||
bool GetSelect(unsigned short controller);
|
||||
bool GetUp(unsigned short controller);
|
||||
bool GetDown(unsigned short controller);
|
||||
bool GetLeft(unsigned short controller);
|
||||
bool GetRight(unsigned short controller);
|
||||
bool GetL(unsigned short controller);
|
||||
bool GetR(unsigned short controller);
|
||||
}
|
||||
43
lib/Hall/include/Hall/Video.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
namespace Hall
|
||||
{
|
||||
const int SCREEN_HEIGHT = 240;
|
||||
const int SCREEN_WIDTH = 400;
|
||||
|
||||
/// <summary>
|
||||
/// Draws an excerpt of the given data onto the screen. All coordinates describe the top-left corner
|
||||
/// </summary>
|
||||
/// <param name="data">A pointer to the first pixel of an image</param>
|
||||
/// <param name="xOffset">The x offset within that image</param>
|
||||
/// <param name="yOffset">The y offset within that image</param>
|
||||
/// <param name="screenX">The x position on screen.</param>
|
||||
/// <param name="screenY">The y position on screen.</param>
|
||||
/// <param name="width">The width of the excerpt</param>
|
||||
/// <param name="height">The height of the excerpt</param>
|
||||
/// <param name="dataWidth">The width of the image (NOT EXCERPT)</param>
|
||||
void Draw(const unsigned short* data, unsigned short xOffset, unsigned short yOffset, unsigned short screenX, unsigned short screenY, unsigned short width, unsigned short height, unsigned short dataWidth);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the whole screen with the given color
|
||||
/// </summary>
|
||||
/// <param name="color">The format is R5G5B5A1, with the alpha bit being lsb</param>
|
||||
void Clear(unsigned short color);
|
||||
|
||||
void SetData(const unsigned short* data);
|
||||
void SetXOffset(unsigned short xOffset);
|
||||
void SetYOffset(unsigned short yOffset);
|
||||
void SetImageWidth(unsigned short imageWidth);
|
||||
void SetWidth(unsigned short width);
|
||||
void SetHeight(unsigned short height);
|
||||
void SetScreenX(unsigned short x);
|
||||
void SetScreenY(unsigned short y);
|
||||
void SetClearColor(unsigned short color);
|
||||
void SetCommandDraw();
|
||||
void SetCommandClear();
|
||||
void SetCommandSwapBuffers();
|
||||
|
||||
bool GetIsGPUBusy();
|
||||
bool GetVSync();
|
||||
bool GetHSync();
|
||||
}
|
||||
132
lib/Hall/source/Audio.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#include <Hall/Audio.h>
|
||||
|
||||
volatile char* AUDIO_START = (char*) 0x2000100;
|
||||
volatile short** AUDIO_START_ADDRESS = (volatile short**)(AUDIO_START + 4);
|
||||
volatile int* AUDIO_SAMPLE_COUNT = (volatile int*)(AUDIO_START + 8);
|
||||
volatile int* AUDIO_LOOP_START = (volatile int*)(AUDIO_START + 12);
|
||||
volatile int* AUDIO_LOOP_END = (volatile int*)(AUDIO_START + 16);
|
||||
volatile int* AUDIO_CURRENT_POSITION = (volatile int*)(AUDIO_START + 20);
|
||||
volatile short* AUDIO_LAST_SAMPLE = (volatile short*)(AUDIO_START + 24);
|
||||
volatile unsigned char* AUDIO_VOLUME = (volatile unsigned char*)(AUDIO_START + 28);
|
||||
volatile bool* AUDIO_IS_LOOPING = (volatile bool*)(AUDIO_START + 32);
|
||||
volatile bool* AUDIO_IS_PLAYING = (volatile bool*)(AUDIO_START + 36);
|
||||
volatile bool* AUDIO_IS_MONO = (volatile bool*)(AUDIO_START + 40);
|
||||
volatile bool* AUDIO_IS_RIGHT = (volatile bool*)(AUDIO_START + 44);
|
||||
unsigned char* AUDIO_GLOBAL_VOLUME = (unsigned char*)(AUDIO_START + 48); //I think we can skip volatile for these two
|
||||
unsigned char* AUDIO_CHANNEL_SELECT = (unsigned char*)(AUDIO_START + 52); //Because they will never change and always address the same value
|
||||
|
||||
|
||||
void Hall::SetGlobalVolume(unsigned char volume)
|
||||
{
|
||||
*AUDIO_GLOBAL_VOLUME = volume;
|
||||
}
|
||||
|
||||
void Hall::SetupMono(int channelID, short* data, int sampleCount, unsigned char volume)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = 1 << channelID;
|
||||
*AUDIO_START_ADDRESS = data;
|
||||
*AUDIO_SAMPLE_COUNT = sampleCount;
|
||||
*AUDIO_CURRENT_POSITION = 0;
|
||||
*AUDIO_VOLUME = volume;
|
||||
*AUDIO_IS_LOOPING = false;
|
||||
*AUDIO_IS_PLAYING = false;
|
||||
*AUDIO_IS_MONO = true;
|
||||
}
|
||||
|
||||
void Hall::SetupMono(int channelID, short* data, int sampleCount, unsigned int loopStart, unsigned int loopEnd, unsigned char volume)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = 1 << channelID;
|
||||
*AUDIO_START_ADDRESS = data;
|
||||
*AUDIO_SAMPLE_COUNT = sampleCount;
|
||||
*AUDIO_CURRENT_POSITION = 0;
|
||||
*AUDIO_VOLUME = volume;
|
||||
*AUDIO_IS_LOOPING = true;
|
||||
*AUDIO_LOOP_START = loopStart;
|
||||
*AUDIO_LOOP_END = loopEnd;
|
||||
*AUDIO_IS_PLAYING = false;
|
||||
*AUDIO_IS_MONO = true;
|
||||
}
|
||||
|
||||
void Hall::SetupStereo(int channelID_left, int channelID_right, short* data, int sampleCount, unsigned char volume)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = (1 << channelID_left) | (1 << channelID_right);
|
||||
*AUDIO_START_ADDRESS = data;
|
||||
*AUDIO_SAMPLE_COUNT = sampleCount;
|
||||
*AUDIO_CURRENT_POSITION = 0;
|
||||
*AUDIO_VOLUME = volume;
|
||||
*AUDIO_IS_LOOPING = false;
|
||||
*AUDIO_IS_PLAYING = false;
|
||||
*AUDIO_IS_MONO = false;
|
||||
*AUDIO_IS_RIGHT = false;
|
||||
|
||||
*AUDIO_CHANNEL_SELECT = 1 << channelID_right;
|
||||
*AUDIO_IS_RIGHT = true;
|
||||
}
|
||||
|
||||
void Hall::SetupStereo(int channelID_left, int channelID_right, short* data, int sampleCount, unsigned int loopStart, unsigned int loopEnd, unsigned char volume)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = (1 << channelID_left) | (1 << channelID_right);
|
||||
*AUDIO_START_ADDRESS = data;
|
||||
*AUDIO_SAMPLE_COUNT = sampleCount;
|
||||
*AUDIO_CURRENT_POSITION = 0;
|
||||
*AUDIO_VOLUME = volume;
|
||||
*AUDIO_LOOP_START = loopStart;
|
||||
*AUDIO_LOOP_END = loopEnd;
|
||||
*AUDIO_IS_LOOPING = true;
|
||||
*AUDIO_IS_PLAYING = false;
|
||||
*AUDIO_IS_MONO = false;
|
||||
*AUDIO_IS_RIGHT = false;
|
||||
|
||||
*AUDIO_CHANNEL_SELECT = 1 << channelID_right;
|
||||
*AUDIO_IS_RIGHT = true;
|
||||
|
||||
}
|
||||
|
||||
void Hall::Play(unsigned char channelSelect)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = channelSelect;
|
||||
*AUDIO_IS_PLAYING = true;
|
||||
}
|
||||
|
||||
void Hall::Pause(unsigned char channelSelect)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = channelSelect;
|
||||
*AUDIO_IS_PLAYING = false;
|
||||
}
|
||||
|
||||
void Hall::SetData(unsigned char channelSelect, short* data)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = channelSelect;
|
||||
*AUDIO_START_ADDRESS = data;
|
||||
}
|
||||
|
||||
void Hall::SetLoop(unsigned char channelSelect, bool isLooping)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = channelSelect;
|
||||
*AUDIO_IS_LOOPING;
|
||||
}
|
||||
|
||||
void Hall::SetLoopBoundaries(unsigned char channelSelect, int start, int end)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = channelSelect;
|
||||
*AUDIO_LOOP_START = start;
|
||||
*AUDIO_LOOP_END = end;
|
||||
}
|
||||
|
||||
void Hall::SetPosition(unsigned char channelSelect, int position)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = channelSelect;
|
||||
*AUDIO_CURRENT_POSITION = position;
|
||||
}
|
||||
|
||||
void Hall::SetSample(unsigned char channelSelect, short sample)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = channelSelect;
|
||||
*AUDIO_LAST_SAMPLE = sample;
|
||||
}
|
||||
|
||||
void Hall::SetVolume(unsigned char channelSelect, unsigned char volume)
|
||||
{
|
||||
*AUDIO_CHANNEL_SELECT = channelSelect;
|
||||
*AUDIO_VOLUME = volume;
|
||||
}
|
||||
90
lib/Hall/source/System.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <Hall/System.h>
|
||||
|
||||
volatile char* SYSTEM_TIME = (volatile char*)0x02000300;
|
||||
volatile unsigned int* SYSTEM_TIME_0 = (volatile unsigned int*)(SYSTEM_TIME + 0); //Least precise
|
||||
volatile unsigned int* SYSTEM_TIME_1 = (volatile unsigned int*)(SYSTEM_TIME + 4);
|
||||
volatile unsigned int* SYSTEM_TIME_2 = (volatile unsigned int*)(SYSTEM_TIME + 8);
|
||||
volatile unsigned int* SYSTEM_TIME_3 = (volatile unsigned int*)(SYSTEM_TIME + 12);
|
||||
volatile unsigned int* SYSTEM_TIME_4 = (volatile unsigned int*)(SYSTEM_TIME + 16);//Most precise
|
||||
|
||||
volatile char* CONTROLLER_START = (volatile char*)0x02000200;
|
||||
volatile unsigned short* CONTROLLER_0 = (volatile unsigned short*)(CONTROLLER_START + 0);
|
||||
volatile unsigned short* CONTROLLER_1 = (volatile unsigned short*)(CONTROLLER_START + 2);
|
||||
|
||||
unsigned long long Hall::GetSystemTime()
|
||||
{
|
||||
unsigned long long result = *SYSTEM_TIME_0;
|
||||
result = result << 32;
|
||||
result += *SYSTEM_TIME_4;
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int Hall::GetSystemTimeExcerpt(int precision)
|
||||
{
|
||||
return *(SYSTEM_TIME_0 + precision);
|
||||
}
|
||||
|
||||
unsigned short Hall::GetController(int id)
|
||||
{
|
||||
return *(CONTROLLER_0 + id);
|
||||
}
|
||||
|
||||
bool Hall::GetA(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 8);
|
||||
}
|
||||
|
||||
bool Hall::GetB(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 0);
|
||||
}
|
||||
|
||||
bool Hall::GetX(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 9);
|
||||
}
|
||||
|
||||
bool Hall::GetY(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 1);
|
||||
}
|
||||
|
||||
bool Hall::GetStart(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 3);
|
||||
}
|
||||
|
||||
bool Hall::GetSelect(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 2);
|
||||
}
|
||||
|
||||
bool Hall::GetUp(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 4);
|
||||
}
|
||||
|
||||
bool Hall::GetDown(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 5);
|
||||
}
|
||||
|
||||
bool Hall::GetLeft(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 6);
|
||||
}
|
||||
|
||||
bool Hall::GetRight(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 7);
|
||||
}
|
||||
|
||||
bool Hall::GetL(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 10);
|
||||
}
|
||||
|
||||
bool Hall::GetR(unsigned short controller)
|
||||
{
|
||||
return controller & (1 << 11);
|
||||
}
|
||||
117
lib/Hall/source/Video.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
#include <Hall/Video.h>
|
||||
|
||||
volatile char* GPU_START = (char*)0x02000000;
|
||||
volatile unsigned short const** GPU_IMAGE_START = (volatile unsigned short const**)(GPU_START + 0);
|
||||
volatile unsigned short* GPU_IMAGE_X_OFFSET = (volatile unsigned short*)(GPU_START + 4);
|
||||
volatile unsigned short* GPU_IMAGE_Y_OFFSET = (volatile unsigned short*)(GPU_START + 8);
|
||||
volatile unsigned short* GPU_IMAGE_WIDTH = (volatile unsigned short*)(GPU_START + 12);
|
||||
volatile unsigned short* GPU_WIDTH = (volatile unsigned short*)(GPU_START + 16);
|
||||
volatile unsigned short* GPU_HEIGHT = (volatile unsigned short*)(GPU_START + 20);
|
||||
volatile unsigned short* GPU_SCREEN_X = (volatile unsigned short*)(GPU_START + 24);
|
||||
volatile unsigned short* GPU_SCREEN_Y = (volatile unsigned short*)(GPU_START + 28);
|
||||
volatile unsigned short* GPU_CLEAR_COLOR = (volatile unsigned short*)(GPU_START + 32);
|
||||
volatile bool* GPU_COMMAND_DRAW = (volatile bool*)(GPU_START + 36);
|
||||
volatile bool* GPU_COMMAND_CLEAR = (volatile bool*)(GPU_START + 40);
|
||||
volatile bool* GPU_IS_BUSY = (volatile bool*)(GPU_START + 44);
|
||||
volatile bool* GPU_VSYNC = (volatile bool*)(GPU_START + 48);
|
||||
volatile bool* GPU_HSYNC = (volatile bool*)(GPU_START + 52);
|
||||
volatile bool* GPU_COMMAND_SWAP_BUFFERS = (volatile bool*)(GPU_START + 56);
|
||||
volatile bool* VSYNC_BUFFER_SWAP = (volatile bool*)(GPU_START + 60);
|
||||
|
||||
|
||||
void Hall::Draw(const unsigned short* data, unsigned short xOffset, unsigned short yOffset, unsigned short screenX, unsigned short screenY, unsigned short width, unsigned short height, unsigned short dataWidth)
|
||||
{
|
||||
*GPU_IMAGE_START = data;
|
||||
*GPU_IMAGE_X_OFFSET = xOffset;
|
||||
*GPU_IMAGE_Y_OFFSET = yOffset;
|
||||
*GPU_IMAGE_WIDTH = dataWidth;
|
||||
*GPU_WIDTH = width;
|
||||
*GPU_HEIGHT = height;
|
||||
*GPU_SCREEN_X = screenX;
|
||||
*GPU_SCREEN_Y = screenY;
|
||||
*GPU_COMMAND_DRAW = true;
|
||||
}
|
||||
|
||||
|
||||
void Hall::Clear(unsigned short color)
|
||||
{
|
||||
*GPU_CLEAR_COLOR = color;
|
||||
*GPU_COMMAND_CLEAR = true;
|
||||
}
|
||||
|
||||
void Hall::SetData(const unsigned short* data)
|
||||
{
|
||||
*GPU_IMAGE_START = data;
|
||||
}
|
||||
|
||||
void Hall::SetXOffset(unsigned short xOffset)
|
||||
{
|
||||
*GPU_IMAGE_X_OFFSET = xOffset;
|
||||
}
|
||||
|
||||
void Hall::SetYOffset(unsigned short yOffset)
|
||||
{
|
||||
*GPU_IMAGE_Y_OFFSET = yOffset;
|
||||
}
|
||||
|
||||
void Hall::SetImageWidth(unsigned short imageWidth)
|
||||
{
|
||||
*GPU_IMAGE_WIDTH = imageWidth;
|
||||
}
|
||||
|
||||
void Hall::SetWidth(unsigned short width)
|
||||
{
|
||||
*GPU_WIDTH = width;
|
||||
}
|
||||
|
||||
void Hall::SetHeight(unsigned short height)
|
||||
{
|
||||
*GPU_HEIGHT = height;
|
||||
}
|
||||
|
||||
|
||||
void Hall::SetScreenX(unsigned short x)
|
||||
{
|
||||
*GPU_SCREEN_X = x;
|
||||
}
|
||||
|
||||
|
||||
void Hall::SetScreenY(unsigned short y)
|
||||
{
|
||||
*GPU_SCREEN_Y = y;
|
||||
}
|
||||
|
||||
void Hall::SetClearColor(unsigned short color)
|
||||
{
|
||||
*GPU_CLEAR_COLOR = color;
|
||||
}
|
||||
|
||||
void Hall::SetCommandDraw()
|
||||
{
|
||||
*GPU_COMMAND_DRAW = true;
|
||||
}
|
||||
|
||||
void Hall::SetCommandClear()
|
||||
{
|
||||
*GPU_COMMAND_CLEAR = true;
|
||||
}
|
||||
|
||||
void Hall::SetCommandSwapBuffers()
|
||||
{
|
||||
*GPU_COMMAND_SWAP_BUFFERS = true;
|
||||
}
|
||||
|
||||
bool Hall::GetIsGPUBusy()
|
||||
{
|
||||
return *GPU_IS_BUSY;
|
||||
}
|
||||
|
||||
bool Hall::GetVSync()
|
||||
{
|
||||
return *GPU_VSYNC;
|
||||
}
|
||||
|
||||
bool Hall::GetHSync()
|
||||
{
|
||||
return *GPU_HSYNC;
|
||||
}
|
||||
114
src/assets.cpp
@@ -1,9 +1,7 @@
|
||||
#include "assets.hpp"
|
||||
#include "audio.hpp"
|
||||
#include "definitions.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
static constexpr uint8_t BACKGROUND_DATA[] = {
|
||||
#embed "../assets/images/jungle.bmp"
|
||||
@@ -22,94 +20,48 @@ static constexpr uint8_t BASKET_DATA[] = {
|
||||
};
|
||||
|
||||
static constexpr uint8_t BACKGROUND_MUSIC_DATA[] = {
|
||||
#embed "../assets/sounds/JamaicanSunrise.wav"
|
||||
#embed "../assets/sounds/JamaicanSunrise.raw"
|
||||
};
|
||||
|
||||
static constexpr uint8_t PICKUP_SOUND_DATA[] = {
|
||||
#embed "../assets/sounds/pickup.wav"
|
||||
#embed "../assets/sounds/pickup.raw"
|
||||
};
|
||||
|
||||
static constexpr uint8_t HIT_SOUND_DATA[] = {
|
||||
#embed "../assets/sounds/hit.wav"
|
||||
#embed "../assets/sounds/hit.raw"
|
||||
};
|
||||
|
||||
static constexpr uint8_t DEFAULT_FONT_DATA[] = {
|
||||
#embed "../assets/fonts/OpenTTD-Sans.ttf"
|
||||
};
|
||||
|
||||
SDL_Texture* load_texture(uint8_t const* data, size_t size, SDL_Renderer* renderer)
|
||||
AssetModule::AssetModule(entt::registry& registry)
|
||||
{
|
||||
auto* iostream = SDL_IOFromConstMem(data, size);
|
||||
SDL_Surface* surface = SDL_LoadBMP_IO(iostream, false);
|
||||
if (surface == nullptr)
|
||||
{
|
||||
spdlog::error("Failed to load SDL surface!\nCause: {}", SDL_GetError());
|
||||
}
|
||||
TextureAtlasLayout background_layout{.width = 400, .height = 240, .rows = 1, .columns = 1};
|
||||
TextureAtlasLayout fruits_layout{.width = 32, .height = 32, .rows = 6, .columns = 38};
|
||||
TextureAtlasLayout spiders_layout{.width = 32, .height = 32, .rows = 2, .columns = 4};
|
||||
TextureAtlasLayout basket_layout{.width = 64, .height = 32, .rows = 1, .columns = 1};
|
||||
Texture background{.data = BACKGROUND_DATA,
|
||||
.data_length = sizeof(BACKGROUND_DATA),
|
||||
.texture_atlas_layout = background_layout};
|
||||
Texture fruits{.data = FRUITS_DATA,
|
||||
.data_length = sizeof(FRUITS_DATA),
|
||||
.texture_atlas_layout = fruits_layout};
|
||||
Texture spiders{.data = SPIDERS_DATA,
|
||||
.data_length = sizeof(SPIDERS_DATA),
|
||||
.texture_atlas_layout = spiders_layout};
|
||||
Texture basket{.data = BASKET_DATA,
|
||||
.data_length = sizeof(BASKET_DATA),
|
||||
.texture_atlas_layout = basket_layout};
|
||||
|
||||
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
if (texture == nullptr)
|
||||
{
|
||||
spdlog::error("Failed to create texture from surface!\nCause: {}", SDL_GetError());
|
||||
}
|
||||
registry.ctx().emplace<TextureAssets>(TextureAssets{
|
||||
.background = background, .fruits = fruits, .spiders = spiders, .basket = basket});
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
AudioAsset load_audio(uint8_t const* data, size_t size)
|
||||
{
|
||||
AudioAsset audio_asset;
|
||||
|
||||
auto* iostream = SDL_IOFromConstMem(data, size);
|
||||
bool res = SDL_LoadWAV_IO(
|
||||
iostream, false, &audio_asset.spec, &audio_asset.buffer, &audio_asset.buffer_length);
|
||||
if (!res)
|
||||
{
|
||||
spdlog::error("Failed to load audio file!\nCause: {}", SDL_GetError());
|
||||
}
|
||||
return audio_asset;
|
||||
}
|
||||
|
||||
FontAsset load_font(uint8_t const* data, size_t size)
|
||||
{
|
||||
FontAsset font_asset;
|
||||
|
||||
auto* iostream = SDL_IOFromConstMem(data, size);
|
||||
auto* ttf = TTF_OpenFontIO(iostream, false, 20);
|
||||
|
||||
font_asset.font = ttf;
|
||||
|
||||
return font_asset;
|
||||
}
|
||||
|
||||
AssetModule::AssetModule(flecs::world& world)
|
||||
{
|
||||
auto* renderer = world.get<SdlHandles>()->renderer;
|
||||
|
||||
auto* background = load_texture(BACKGROUND_DATA, sizeof(BACKGROUND_DATA), renderer);
|
||||
TextureAtlasLayout background_layout = {.width = 866, .height = 510, .rows = 1, .columns = 1};
|
||||
|
||||
auto* fruits = load_texture(FRUITS_DATA, sizeof(FRUITS_DATA), renderer);
|
||||
TextureAtlasLayout fruits_layout = {.width = 16, .height = 16, .rows = 6, .columns = 38};
|
||||
|
||||
auto* spiders = load_texture(SPIDERS_DATA, sizeof(SPIDERS_DATA), renderer);
|
||||
TextureAtlasLayout spiders_layout = {.width = 16, .height = 16, .rows = 2, .columns = 4};
|
||||
|
||||
auto* basket = load_texture(BASKET_DATA, sizeof(BASKET_DATA), renderer);
|
||||
TextureAtlasLayout basket_layout = {.width = 16, .height = 16, .rows = 1, .columns = 1};
|
||||
|
||||
world.set<TextureAssets>(TextureAssets{
|
||||
.background = Texture{.sdl_texture = background, .texture_atlas_layout = background_layout},
|
||||
.fruits = Texture{.sdl_texture = fruits, .texture_atlas_layout = fruits_layout},
|
||||
.spiders = Texture{.sdl_texture = spiders, .texture_atlas_layout = spiders_layout},
|
||||
.basket = Texture{.sdl_texture = basket, .texture_atlas_layout = basket_layout}});
|
||||
|
||||
auto background_music = load_audio(BACKGROUND_MUSIC_DATA, sizeof(BACKGROUND_MUSIC_DATA));
|
||||
auto pickup_sound = load_audio(PICKUP_SOUND_DATA, sizeof(PICKUP_SOUND_DATA));
|
||||
auto hit_sound = load_audio(HIT_SOUND_DATA, sizeof(HIT_SOUND_DATA));
|
||||
world.set<AudioAssets>(AudioAssets{.background_music = background_music,
|
||||
.pickup_sound = pickup_sound,
|
||||
.hit_sound = hit_sound});
|
||||
|
||||
auto font = load_font(DEFAULT_FONT_DATA, sizeof(DEFAULT_FONT_DATA));
|
||||
world.set<FontAssets>(FontAssets{.default_font = font});
|
||||
AudioAsset background_music{.buffer = BACKGROUND_MUSIC_DATA,
|
||||
.buffer_length = sizeof(BACKGROUND_MUSIC_DATA)};
|
||||
AudioAsset pickup_sound{.buffer = PICKUP_SOUND_DATA,
|
||||
.buffer_length = sizeof(PICKUP_SOUND_DATA)};
|
||||
AudioAsset hit_sound{.buffer = HIT_SOUND_DATA, .buffer_length = sizeof(HIT_SOUND_DATA)};
|
||||
registry.ctx().emplace<AudioAssets>(AudioAssets{.background_music = background_music,
|
||||
.pickup_sound = pickup_sound,
|
||||
.hit_sound = hit_sound});
|
||||
|
||||
// auto font = load_font(DEFAULT_FONT_DATA, sizeof(DEFAULT_FONT_DATA));
|
||||
// registry.ctx().emplace<FontAssets>(FontAssets{.default_font = font});
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
#include "audio.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_ttf/SDL_ttf.h>
|
||||
#include <flecs.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
struct TextureAtlasLayout
|
||||
{
|
||||
@@ -16,7 +14,8 @@ struct TextureAtlasLayout
|
||||
|
||||
struct Texture
|
||||
{
|
||||
SDL_Texture* sdl_texture;
|
||||
uint8_t const* data;
|
||||
uint32_t data_length;
|
||||
TextureAtlasLayout texture_atlas_layout;
|
||||
};
|
||||
|
||||
@@ -35,17 +34,17 @@ struct AudioAssets
|
||||
AudioAsset hit_sound;
|
||||
};
|
||||
|
||||
struct FontAsset
|
||||
{
|
||||
TTF_Font* font;
|
||||
};
|
||||
// struct FontAsset
|
||||
// {
|
||||
// TTF_Font* font;
|
||||
// };
|
||||
|
||||
struct FontAssets
|
||||
{
|
||||
FontAsset default_font;
|
||||
};
|
||||
// struct FontAssets
|
||||
// {
|
||||
// FontAsset default_font;
|
||||
// };
|
||||
|
||||
struct AssetModule
|
||||
{
|
||||
AssetModule(flecs::world& world);
|
||||
AssetModule(entt::registry& registry);
|
||||
};
|
||||
|
||||
@@ -1,34 +1,10 @@
|
||||
#include "audio.hpp"
|
||||
#include "assets.hpp"
|
||||
|
||||
AudioModule::AudioModule(flecs::world& world)
|
||||
AudioModule::AudioModule(entt::registry& registry)
|
||||
{
|
||||
auto* audio_assets = world.get<AudioAssets>();
|
||||
auto* music_stream = SDL_OpenAudioDeviceStream(
|
||||
SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audio_assets->background_music.spec, NULL, NULL);
|
||||
auto* sound_stream = SDL_OpenAudioDeviceStream(
|
||||
SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &audio_assets->pickup_sound.spec, NULL, NULL);
|
||||
auto const& audio_assets = registry.ctx().get<AudioAssets>();
|
||||
|
||||
SDL_ResumeAudioStreamDevice(music_stream);
|
||||
SDL_ResumeAudioStreamDevice(sound_stream);
|
||||
|
||||
world.set<AudioStreams>(
|
||||
AudioStreams{.music_stream = music_stream, .sound_stream = sound_stream});
|
||||
|
||||
world.system<AudioStreams, AudioAssets>("FeedAudioStreams")
|
||||
.term_at(0)
|
||||
.singleton()
|
||||
.term_at(1)
|
||||
.singleton()
|
||||
.each(
|
||||
[](AudioStreams& audio_streams, AudioAssets& audio_assets)
|
||||
{
|
||||
if (SDL_GetAudioStreamQueued(audio_streams.music_stream) <
|
||||
static_cast<int>(audio_assets.background_music.buffer_length))
|
||||
{
|
||||
SDL_PutAudioStreamData(audio_streams.music_stream,
|
||||
audio_assets.background_music.buffer,
|
||||
audio_assets.background_music.buffer_length);
|
||||
}
|
||||
});
|
||||
registry.ctx().emplace<AudioStreams>(AudioStreams{.music_stream = {.id_left = 0, .id_right = 1},
|
||||
.sound_stream = {.id_mono = 2}});
|
||||
}
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <cstdint>
|
||||
#include <flecs.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
struct AudioAsset
|
||||
{
|
||||
SDL_AudioSpec spec;
|
||||
uint8_t* buffer;
|
||||
uint8_t const* buffer;
|
||||
uint32_t buffer_length;
|
||||
};
|
||||
|
||||
struct MonoChannel
|
||||
{
|
||||
int id_mono;
|
||||
};
|
||||
|
||||
struct StereoChannel
|
||||
{
|
||||
int id_left;
|
||||
int id_right;
|
||||
};
|
||||
|
||||
struct AudioStreams
|
||||
{
|
||||
SDL_AudioStream* music_stream;
|
||||
SDL_AudioStream* sound_stream;
|
||||
StereoChannel music_stream;
|
||||
MonoChannel sound_stream;
|
||||
};
|
||||
|
||||
struct AudioModule
|
||||
{
|
||||
AudioModule(flecs::world& world);
|
||||
AudioModule(entt::registry& registry);
|
||||
};
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_ttf/SDL_ttf.h>
|
||||
#include <random>
|
||||
|
||||
static constexpr int WINDOW_WIDTH = 400;
|
||||
static constexpr int WINDOW_HEIGHT = 240;
|
||||
|
||||
struct SdlHandles
|
||||
{
|
||||
SDL_Window* window;
|
||||
SDL_Renderer* renderer;
|
||||
TTF_TextEngine* text_engine;
|
||||
};
|
||||
// struct SdlHandles
|
||||
// {
|
||||
// SDL_Window* window;
|
||||
// SDL_Renderer* renderer;
|
||||
// TTF_TextEngine* text_engine;
|
||||
// };
|
||||
|
||||
struct Game
|
||||
{
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
|
||||
enum Key : uint8_t
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
struct ButtonInput
|
||||
{
|
||||
std::set<SDL_Keycode> pressed;
|
||||
std::set<SDL_Keycode> just_pressed;
|
||||
std::set<SDL_Keycode> just_released;
|
||||
std::set<Key> pressed;
|
||||
};
|
||||
|
||||
163
src/level.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#include "level.hpp"
|
||||
#include "input.hpp"
|
||||
|
||||
#include <Hall/Hall.h>
|
||||
|
||||
LevelModule::LevelModule(entt::registry& registry)
|
||||
{
|
||||
auto const* texture_assets = ®istry.ctx().get<TextureAssets>();
|
||||
auto const* audio_steams = ®istry.ctx().get<AudioStreams>();
|
||||
auto const* audio_assets = ®istry.ctx().get<AudioAssets>();
|
||||
|
||||
// Hall::SetupStereo(audio_steams->music_stream.id_left,
|
||||
// audio_steams->music_stream.id_right,
|
||||
// audio_assets->background_music.buffer,
|
||||
// audio_assets->background_music.buffer_length / (2 * 2),
|
||||
// 0,
|
||||
// audio_assets->background_music.buffer_length / (2 * 2));
|
||||
|
||||
auto background = registry.create();
|
||||
registry.emplace<Position>(background, Position{.x = 0, .y = 0});
|
||||
registry.emplace<Sprite>(
|
||||
background, Sprite{.texture = &texture_assets->background, .texture_atlas_index = 0});
|
||||
registry.emplace<Size>(background, Size{.w = WINDOW_WIDTH, .h = WINDOW_HEIGHT});
|
||||
registry.emplace<Background>(background);
|
||||
|
||||
auto basket = registry.create();
|
||||
registry.emplace<WorldPosition>(basket);
|
||||
registry.emplace<Position>(basket,
|
||||
Position{.x = WINDOW_WIDTH / 2 - 32, .y = WINDOW_HEIGHT - 32});
|
||||
registry.emplace<Sprite>(basket,
|
||||
Sprite{.texture = &texture_assets->basket, .texture_atlas_index = 0});
|
||||
registry.emplace<Size>(basket, Size{.w = 64, .h = 32});
|
||||
registry.emplace<Basket>(basket);
|
||||
|
||||
auto basket_cb = registry.create();
|
||||
registry.emplace<WorldPosition>(basket_cb);
|
||||
registry.emplace<Position>(basket_cb, Position{.x = 0, .y = 16});
|
||||
registry.emplace<Size>(basket_cb, Size{.w = 64, .h = 16});
|
||||
registry.emplace<CollisionBox>(basket_cb);
|
||||
registry.emplace<Parent>(basket_cb, basket);
|
||||
registry.emplace<BasketCollisionBox>(basket_cb);
|
||||
}
|
||||
|
||||
void LevelModule::MoveBasket(entt::registry& registry)
|
||||
{
|
||||
auto const& input = registry.ctx().get<ButtonInput>();
|
||||
auto basket_view = registry.view<Position, Size const, Sprite const, Basket>();
|
||||
|
||||
for (auto [entity, pos, size, sprite] : basket_view.each())
|
||||
{
|
||||
// if (input.pressed.contains(SDLK_LEFT))
|
||||
// {
|
||||
// pos.x -= 5;
|
||||
// }
|
||||
// if (input.pressed.contains(SDLK_RIGHT))
|
||||
// {
|
||||
// pos.x += 5;
|
||||
// }
|
||||
|
||||
pos.x = pos.x < 0 ? 0 : pos.x;
|
||||
pos.x = pos.x > WINDOW_WIDTH - size.w ? WINDOW_WIDTH - size.w : pos.x;
|
||||
}
|
||||
}
|
||||
|
||||
void LevelModule::SpawnFruits(entt::registry& registry)
|
||||
{
|
||||
auto& game = registry.ctx().get<Game>();
|
||||
auto const& texture_assets = registry.ctx().get<TextureAssets>();
|
||||
|
||||
std::bernoulli_distribution spider_dist(0.25);
|
||||
bool spider = spider_dist(game.random_engine);
|
||||
|
||||
std::binomial_distribution<> velocity_dist(3, 0.5);
|
||||
int vel = velocity_dist(game.random_engine) + 1;
|
||||
|
||||
if ((game.ticks % 50) == 0)
|
||||
{
|
||||
auto item = registry.create();
|
||||
std::uniform_int_distribution<> xpos_dist(32, WINDOW_WIDTH - 32);
|
||||
int xpos = xpos_dist(game.random_engine);
|
||||
if (!spider)
|
||||
{
|
||||
std::uniform_int_distribution<> index_dist(0, 228 - 1);
|
||||
uint16_t index = index_dist(game.random_engine);
|
||||
|
||||
registry.emplace<Fruit>(item);
|
||||
registry.emplace<WorldPosition>(item);
|
||||
registry.emplace<Position>(item, Position{.x = xpos, .y = -16});
|
||||
registry.emplace<Velocity>(item, Velocity{.x = 0, .y = vel});
|
||||
registry.emplace<Sprite>(
|
||||
item, Sprite{.texture = &texture_assets.fruits, .texture_atlas_index = index});
|
||||
registry.emplace<Size>(item, Size{.w = 32, .h = 32});
|
||||
}
|
||||
else
|
||||
{
|
||||
std::uniform_int_distribution<> index_dist(0, 8 - 1);
|
||||
uint16_t index = index_dist(game.random_engine);
|
||||
|
||||
registry.emplace<Spider>(item);
|
||||
registry.emplace<WorldPosition>(item);
|
||||
registry.emplace<Position>(item, Position{.x = xpos, .y = -16});
|
||||
registry.emplace<Velocity>(item, Velocity{.x = 0, .y = vel});
|
||||
registry.emplace<Sprite>(
|
||||
item, Sprite{.texture = &texture_assets.spiders, .texture_atlas_index = index});
|
||||
registry.emplace<Size>(item, Size{.w = 32, .h = 32});
|
||||
}
|
||||
|
||||
auto collision_box = registry.create();
|
||||
registry.emplace<Parent>(collision_box, item);
|
||||
registry.emplace<WorldPosition>(collision_box);
|
||||
registry.emplace<Position>(collision_box, Position{.x = 0, .y = 0});
|
||||
registry.emplace<Size>(collision_box, Size{.w = 32, .h = 32});
|
||||
registry.emplace<CollisionBox>(collision_box, item);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelModule::CollectFruit(entt::registry& registry)
|
||||
{
|
||||
auto& game = registry.ctx().get<Game>();
|
||||
// auto const& audio_streams = registry.ctx().get<AudioStreams>();
|
||||
auto const& audio_assets = registry.ctx().get<AudioAssets>();
|
||||
|
||||
auto view = registry.view<Position, Fruit, Collided>();
|
||||
for (auto [entity, pos] : view.each())
|
||||
{
|
||||
game.score += 10;
|
||||
pos.x += 1000;
|
||||
// registry.destroy(entity);
|
||||
|
||||
// SDL_PutAudioStreamData(audio_streams.sound_stream,
|
||||
// audio_assets.pickup_sound.buffer,
|
||||
// audio_assets.pickup_sound.buffer_length);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelModule::CollectSpider(entt::registry& registry)
|
||||
{
|
||||
auto& game = registry.ctx().get<Game>();
|
||||
// auto const& audio_streams = registry.ctx().get<AudioStreams>();
|
||||
auto const& audio_assets = registry.ctx().get<AudioAssets>();
|
||||
|
||||
auto view = registry.view<Position, Spider, Collided>();
|
||||
for (auto [entity, pos] : view.each())
|
||||
{
|
||||
game.score -= 50;
|
||||
pos.x += 1000;
|
||||
// registry.destroy(entity);
|
||||
|
||||
// SDL_PutAudioStreamData(audio_streams.sound_stream,
|
||||
// audio_assets.hit_sound.buffer,
|
||||
// audio_assets.hit_sound.buffer_length);
|
||||
};
|
||||
}
|
||||
|
||||
void LevelModule::DespawnItems(entt::registry& registry)
|
||||
{
|
||||
auto view = registry.view<WorldPosition const, Item>();
|
||||
for (auto [entity, pos] : view.each())
|
||||
{
|
||||
if (pos.y >= WINDOW_HEIGHT)
|
||||
registry.destroy(entity);
|
||||
}
|
||||
}
|
||||
186
src/level.hpp
@@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "definitions.hpp"
|
||||
#include "input.hpp"
|
||||
#include "physics.hpp"
|
||||
#include "sprite.hpp"
|
||||
|
||||
#include <flecs.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
struct Background
|
||||
{
|
||||
};
|
||||
|
||||
struct Fruit
|
||||
{
|
||||
@@ -24,175 +26,17 @@ struct Basket
|
||||
{
|
||||
};
|
||||
|
||||
struct BasketCollisionBox
|
||||
{
|
||||
};
|
||||
|
||||
struct LevelModule
|
||||
{
|
||||
LevelModule(flecs::world& world)
|
||||
{
|
||||
auto const* texture_assets = world.get<TextureAssets>();
|
||||
LevelModule(entt::registry& registry);
|
||||
|
||||
world.component<Item>();
|
||||
world.component<Fruit>().is_a<Item>();
|
||||
world.component<Spider>().is_a<Item>();
|
||||
|
||||
world.entity("Background")
|
||||
.set<Position>(Position{.x = 0, .y = 0})
|
||||
.set<Sprite>(Sprite{.texture = &texture_assets->background, .texture_atlas_index = 0})
|
||||
.set<Size>(Size{.w = WINDOW_WIDTH, .h = WINDOW_HEIGHT});
|
||||
|
||||
auto basket =
|
||||
world.entity("Basket")
|
||||
.add<WorldPosition>()
|
||||
.set<Position>(Position{.x = WINDOW_WIDTH / 2 - 32, .y = WINDOW_HEIGHT - 32})
|
||||
.set<Sprite>(Sprite{.texture = &texture_assets->basket, .texture_atlas_index = 0})
|
||||
.set<Size>(Size{.w = 64, .h = 32})
|
||||
.add<Basket>();
|
||||
|
||||
world.entity()
|
||||
.child_of(basket)
|
||||
.add<WorldPosition>()
|
||||
.set<Position>(Position{.x = 0, .y = 16})
|
||||
.set<Size>(Size{.w = 64, .h = 16})
|
||||
.add<CollisionBox>();
|
||||
|
||||
world.system<Game, TextureAssets const>("SpawnFruits")
|
||||
.term_at(0)
|
||||
.singleton()
|
||||
.term_at(1)
|
||||
.singleton()
|
||||
.each(
|
||||
[](flecs::iter& it, size_t index, Game& game, TextureAssets const& texture_assets)
|
||||
{
|
||||
std::bernoulli_distribution spider_dist(0.25);
|
||||
bool spider = spider_dist(game.random_engine);
|
||||
|
||||
std::binomial_distribution<> velocity_dist(3, 0.5);
|
||||
int vel = velocity_dist(game.random_engine) + 1;
|
||||
|
||||
if ((game.ticks % 50) == 0)
|
||||
{
|
||||
flecs::entity e;
|
||||
std::uniform_int_distribution<> xpos_dist(32, WINDOW_WIDTH - 32);
|
||||
int xpos = xpos_dist(game.random_engine);
|
||||
if (!spider)
|
||||
{
|
||||
std::uniform_int_distribution<> index_dist(0, 228 - 1);
|
||||
uint16_t index = index_dist(game.random_engine);
|
||||
|
||||
e = it.world()
|
||||
.entity()
|
||||
.add<Fruit>()
|
||||
.add<WorldPosition>()
|
||||
.set<Position>(Position{.x = xpos, .y = -16})
|
||||
.set<Velocity>(Velocity{.x = 0, .y = vel})
|
||||
.set<Sprite>(Sprite{.texture = &texture_assets.fruits,
|
||||
.texture_atlas_index = index})
|
||||
.set<Size>(Size{.w = 32, .h = 32});
|
||||
}
|
||||
else
|
||||
{
|
||||
std::uniform_int_distribution<> index_dist(0, 8 - 1);
|
||||
uint16_t index = index_dist(game.random_engine);
|
||||
|
||||
e = it.world()
|
||||
.entity()
|
||||
.add<Spider>()
|
||||
.add<WorldPosition>()
|
||||
.set<Position>(Position{.x = xpos, .y = -16})
|
||||
.set<Velocity>(Velocity{.x = 0, .y = vel})
|
||||
.set<Sprite>(Sprite{.texture = &texture_assets.spiders,
|
||||
.texture_atlas_index = index})
|
||||
.set<Size>(Size{.w = 32, .h = 32});
|
||||
}
|
||||
it.world()
|
||||
.entity("CollisionBox")
|
||||
.child_of(e)
|
||||
.add<WorldPosition>()
|
||||
.set<Position>(Position{.x = 0, .y = 0})
|
||||
.set<Size>(Size{.w = 32, .h = 32})
|
||||
.add<CollisionBox>();
|
||||
}
|
||||
});
|
||||
|
||||
// world.system<WorldPosition const, Item>("DespawnItems")
|
||||
// .kind(flecs::OnValidate)
|
||||
// .each(
|
||||
// [](flecs::entity e, WorldPosition const& pos, Item)
|
||||
// {
|
||||
// if (pos.y >= WINDOW_HEIGHT)
|
||||
// e.destruct();
|
||||
// });
|
||||
|
||||
world.system<Game, AudioStreams, AudioAssets, Position, Fruit, Collided>("CollectFruit")
|
||||
.term_at(0)
|
||||
.singleton()
|
||||
.term_at(1)
|
||||
.singleton()
|
||||
.term_at(2)
|
||||
.singleton()
|
||||
.each(
|
||||
[](flecs::entity e,
|
||||
Game& game,
|
||||
AudioStreams& audio_streams,
|
||||
AudioAssets& audio_assets,
|
||||
Position& pos,
|
||||
Fruit,
|
||||
Collided)
|
||||
{
|
||||
game.score += 10;
|
||||
pos.x += 1000;
|
||||
// e.destruct();
|
||||
|
||||
SDL_PutAudioStreamData(audio_streams.sound_stream,
|
||||
audio_assets.pickup_sound.buffer,
|
||||
audio_assets.pickup_sound.buffer_length);
|
||||
});
|
||||
|
||||
world.system<Game, AudioStreams, AudioAssets, Position, Spider, Collided>("CollectSpider")
|
||||
.term_at(0)
|
||||
.singleton()
|
||||
.term_at(1)
|
||||
.singleton()
|
||||
.term_at(2)
|
||||
.singleton()
|
||||
.each(
|
||||
[](flecs::entity e,
|
||||
Game& game,
|
||||
AudioStreams& audio_streams,
|
||||
AudioAssets& audio_assets,
|
||||
Position& pos,
|
||||
Spider,
|
||||
Collided)
|
||||
{
|
||||
game.score -= 50;
|
||||
pos.x += 1000;
|
||||
// e.destruct();
|
||||
|
||||
SDL_PutAudioStreamData(audio_streams.sound_stream,
|
||||
audio_assets.hit_sound.buffer,
|
||||
audio_assets.hit_sound.buffer_length);
|
||||
});
|
||||
|
||||
world.system<ButtonInput const, Position, Size const, Sprite const, Basket>("MoveBasket")
|
||||
.term_at(0)
|
||||
.singleton()
|
||||
.each(
|
||||
[](ButtonInput const& input,
|
||||
Position& pos,
|
||||
Size const& size,
|
||||
Sprite const& sprite,
|
||||
Basket)
|
||||
{
|
||||
if (input.pressed.contains(SDLK_LEFT))
|
||||
{
|
||||
pos.x -= 5;
|
||||
}
|
||||
if (input.pressed.contains(SDLK_RIGHT))
|
||||
{
|
||||
pos.x += 5;
|
||||
}
|
||||
|
||||
pos.x = pos.x < 0 ? 0 : pos.x;
|
||||
pos.x = pos.x > WINDOW_WIDTH - size.w ? WINDOW_WIDTH - size.w : pos.x;
|
||||
});
|
||||
}
|
||||
static void MoveBasket(entt::registry& registry);
|
||||
static void SpawnFruits(entt::registry& registry);
|
||||
static void CollectFruit(entt::registry ®istry);
|
||||
static void CollectSpider(entt::registry ®istry);
|
||||
static void DespawnItems(entt::registry ®istry);
|
||||
};
|
||||
|
||||
143
src/main.cpp
@@ -5,114 +5,69 @@
|
||||
#include "physics.hpp"
|
||||
#include "render.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3_ttf/SDL_ttf.h>
|
||||
#include <flecs.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <Hall/Hall.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
void increment_ticks(entt::registry& registry)
|
||||
{
|
||||
auto& game = registry.ctx().get<Game>();
|
||||
game.ticks += 1;
|
||||
|
||||
if (game.ticks % 60 == 0 && game.time > 0)
|
||||
{
|
||||
game.time--;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
spdlog::info("Initialize SDL...");
|
||||
entt::registry registry;
|
||||
|
||||
SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");
|
||||
registry.ctx().emplace<Game>(Game{.ticks = 0, .time = 60, .score = 0, .random_engine = {}});
|
||||
registry.ctx().emplace<ButtonInput>(ButtonInput{});
|
||||
|
||||
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO))
|
||||
{
|
||||
spdlog::critical("Failed to initialize SDL!\nCause: {}", SDL_GetError());
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
TTF_Init();
|
||||
|
||||
auto* window = SDL_CreateWindow("HansTheGatherer", WINDOW_WIDTH, WINDOW_HEIGHT, 0);
|
||||
if (window == nullptr)
|
||||
{
|
||||
spdlog::critical("Failed to create SDL window!\nCause: {}", SDL_GetError());
|
||||
}
|
||||
|
||||
auto* renderer = SDL_CreateRenderer(window, nullptr);
|
||||
if (renderer == nullptr)
|
||||
{
|
||||
spdlog::critical("Failed to create SDL renderer!\nCause: {}", SDL_GetError());
|
||||
}
|
||||
|
||||
auto* text_engine = TTF_CreateRendererTextEngine(renderer);
|
||||
|
||||
flecs::world world;
|
||||
|
||||
world.set<Game>(Game{.ticks = 0, .time = 60, .score = 0, .random_engine = {}});
|
||||
world.set<ButtonInput>(ButtonInput{});
|
||||
world.set<SdlHandles>(
|
||||
SdlHandles{.window = window, .renderer = renderer, .text_engine = text_engine});
|
||||
|
||||
world.import <AssetModule>();
|
||||
world.import <AudioModule>();
|
||||
world.import <RenderModule>();
|
||||
world.import <PhysicsModule>();
|
||||
world.import <LevelModule>();
|
||||
|
||||
world.system<Game, TranslateSystem>("IncrementTicks")
|
||||
.term_at(0)
|
||||
.singleton()
|
||||
.term_at(1)
|
||||
.singleton()
|
||||
.each(
|
||||
[](Game& game, TranslateSystem& translate_system)
|
||||
{
|
||||
game.ticks += 1;
|
||||
|
||||
if (game.ticks % 60 == 0)
|
||||
{
|
||||
game.time = std::max(0, game.time - 1);
|
||||
}
|
||||
|
||||
if (game.time == 0)
|
||||
translate_system.translate_system.disable();
|
||||
});
|
||||
AssetModule asset_module(registry);
|
||||
AudioModule audio_module(registry);
|
||||
RenderModule render_module(registry);
|
||||
PhysicsModule physics_module(registry);
|
||||
LevelModule level_module(registry);
|
||||
|
||||
bool exit_gameloop = false;
|
||||
while (!exit_gameloop)
|
||||
{
|
||||
auto* input = world.get_mut<ButtonInput>();
|
||||
|
||||
// Clear just pressed/released
|
||||
input->just_pressed.clear();
|
||||
input->just_released.clear();
|
||||
|
||||
// Input
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
auto* input = ®istry.ctx().get<ButtonInput>();
|
||||
if (Hall::GetLeft(0))
|
||||
input->pressed.insert(Key::Left);
|
||||
else
|
||||
input->pressed.erase(Key::Left);
|
||||
|
||||
if (Hall::GetRight(0))
|
||||
input->pressed.insert(Key::Right);
|
||||
else
|
||||
input->pressed.erase(Key::Right);
|
||||
|
||||
if (registry.ctx().get<Game>().time != 0)
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_EVENT_QUIT:
|
||||
exit_gameloop = true;
|
||||
break;
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
if (event.key.key == SDLK_ESCAPE)
|
||||
{
|
||||
exit_gameloop = true;
|
||||
}
|
||||
if (input->pressed.insert(event.key.key).second)
|
||||
{
|
||||
input->just_pressed.insert(event.key.key);
|
||||
}
|
||||
break;
|
||||
case SDL_EVENT_KEY_UP:
|
||||
if (input->pressed.erase(event.key.key) != 0)
|
||||
{
|
||||
input->just_released.insert(event.key.key);
|
||||
}
|
||||
break;
|
||||
}
|
||||
increment_ticks(registry);
|
||||
LevelModule::MoveBasket(registry);
|
||||
LevelModule::SpawnFruits(registry);
|
||||
LevelModule::CollectFruit(registry);
|
||||
LevelModule::CollectSpider(registry);
|
||||
// LevelModule::DespawnItems(registry);
|
||||
}
|
||||
|
||||
world.progress();
|
||||
}
|
||||
PhysicsModule::TranslatePhysicsObject(registry);
|
||||
PhysicsModule::PropagatePosition(registry);
|
||||
PhysicsModule::RemoveCollisionMarker(registry);
|
||||
PhysicsModule::CollisionCheck(registry);
|
||||
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
Hall::Clear(0);
|
||||
RenderModule::RenderSprites(registry);
|
||||
RenderModule::RenderScore(registry);
|
||||
Hall::SetCommandSwapBuffers();
|
||||
Hall::GetVSync();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
134
src/physics.cpp
@@ -1,86 +1,68 @@
|
||||
#include "physics.hpp"
|
||||
#include "level.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
PhysicsModule::PhysicsModule(flecs::world& world)
|
||||
void PhysicsModule::TranslatePhysicsObject(entt::registry& registry)
|
||||
{
|
||||
auto translate_system = world.system<Position, Velocity const>("TranslatePhysicsObject")
|
||||
.each(
|
||||
[](Position& pos, Velocity const& vel)
|
||||
{
|
||||
pos.x += vel.x;
|
||||
pos.y += vel.y;
|
||||
});
|
||||
auto view = registry.view<Position, Velocity const>();
|
||||
|
||||
world.set<TranslateSystem>(TranslateSystem{translate_system});
|
||||
for (auto [entity, pos, vel] : view.each())
|
||||
{
|
||||
pos.x += vel.x;
|
||||
pos.y += vel.y;
|
||||
}
|
||||
}
|
||||
|
||||
// Introduce phase that runs after OnUpdate but before OnValidate
|
||||
flecs::entity propagate_phase = world.entity().add(flecs::Phase).depends_on(flecs::OnUpdate);
|
||||
void PhysicsModule::PropagatePosition(entt::registry& registry)
|
||||
{
|
||||
auto root_transform_view = registry.view<Position const, WorldPosition>(entt::exclude<Parent>);
|
||||
auto transform_view = registry.view<Position const, WorldPosition, Parent const>();
|
||||
|
||||
world.system<WorldPosition, Position const>("PropagatePosition")
|
||||
.kind(propagate_phase)
|
||||
.each(
|
||||
[](flecs::entity e, WorldPosition& world_pos, Position const& local_pos)
|
||||
for (auto [entity, pos, world_pos] : root_transform_view.each())
|
||||
{
|
||||
world_pos.x = pos.x;
|
||||
world_pos.y = pos.y;
|
||||
}
|
||||
|
||||
for (auto [entity, pos, world_pos, parent] : transform_view.each())
|
||||
{
|
||||
auto parent_pos = registry.get<WorldPosition const>(parent.parent);
|
||||
|
||||
world_pos.x = parent_pos.x + pos.x;
|
||||
world_pos.y = parent_pos.y + pos.y;
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsModule::RemoveCollisionMarker(entt::registry& registry)
|
||||
{
|
||||
auto view = registry.view<Collided const>();
|
||||
for (auto [entity] : view.each())
|
||||
{
|
||||
registry.remove<Collided>(entity);
|
||||
}
|
||||
}
|
||||
void PhysicsModule::CollisionCheck(entt::registry& registry)
|
||||
{
|
||||
auto view = registry.view<WorldPosition const, Size const, Parent const, CollisionBox>(
|
||||
entt::exclude<BasketCollisionBox>);
|
||||
auto basket_cb_view = registry.view<WorldPosition const, Size const, BasketCollisionBox>();
|
||||
|
||||
for (auto [e, world_pos, size, parent] : view.each())
|
||||
{
|
||||
auto fruit = parent.parent;
|
||||
|
||||
for (auto [basket, basket_world_pos, basket_size] : basket_cb_view.each())
|
||||
{
|
||||
if (basket_world_pos.x + basket_size.w >= world_pos.x &&
|
||||
basket_world_pos.x <= world_pos.x + size.w &&
|
||||
basket_world_pos.y + basket_size.h >= world_pos.y &&
|
||||
basket_world_pos.y <= world_pos.y + size.h)
|
||||
{
|
||||
if (e.parent() != flecs::entity::null() && e.parent().has<WorldPosition>())
|
||||
return;
|
||||
registry.emplace<Collided>(fruit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
world_pos.x = local_pos.x;
|
||||
world_pos.y = local_pos.y;
|
||||
|
||||
std::function<void(flecs::entity, WorldPosition const&)> propagate_to_children;
|
||||
propagate_to_children = [&](flecs::entity parent, WorldPosition const& parent_pos)
|
||||
{
|
||||
parent.children(
|
||||
[=](flecs::entity child)
|
||||
{
|
||||
auto local_pos = child.get<Position>();
|
||||
auto world_pos = child.get_mut<WorldPosition>();
|
||||
|
||||
world_pos->x = parent_pos.x + local_pos->x;
|
||||
world_pos->y = parent_pos.y + local_pos->y;
|
||||
|
||||
propagate_to_children(child, *world_pos);
|
||||
});
|
||||
};
|
||||
|
||||
propagate_to_children(e, world_pos);
|
||||
});
|
||||
|
||||
auto basket_query = world.query<Basket>();
|
||||
|
||||
world.system<Collided>("RemoveCollisionMarker")
|
||||
.kind(flecs::PreUpdate)
|
||||
.each([](flecs::entity e, Collided) { e.remove<Collided>(); });
|
||||
|
||||
world.system<WorldPosition const, Size const, CollisionBox>("CollisionCheck")
|
||||
.kind(flecs::OnValidate)
|
||||
.each(
|
||||
[basket_query](
|
||||
flecs::entity e, WorldPosition const& world_pos, Size const& size, CollisionBox)
|
||||
{
|
||||
if (e.parent().has<Basket>())
|
||||
return;
|
||||
|
||||
auto fruit = e.parent();
|
||||
auto basket = basket_query.first();
|
||||
basket.children(
|
||||
[fruit, world_pos, size](flecs::entity basket_child)
|
||||
{
|
||||
if (!basket_child.has<CollisionBox>())
|
||||
return;
|
||||
|
||||
auto basket_child_pos = basket_child.get<WorldPosition>();
|
||||
auto basket_child_size = basket_child.get<Size>();
|
||||
|
||||
if (basket_child_pos->x + basket_child_size->w >= world_pos.x &&
|
||||
basket_child_pos->x <= world_pos.x + size.w &&
|
||||
basket_child_pos->y + basket_child_size->h >= world_pos.y &&
|
||||
basket_child_pos->y <= world_pos.y + size.h)
|
||||
{
|
||||
fruit.add<Collided>();
|
||||
}
|
||||
});
|
||||
});
|
||||
PhysicsModule::PhysicsModule(entt::registry& registry)
|
||||
{
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <flecs.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
struct WorldPosition
|
||||
{
|
||||
@@ -26,6 +26,16 @@ struct Size
|
||||
int h;
|
||||
};
|
||||
|
||||
struct Parent
|
||||
{
|
||||
entt::entity parent;
|
||||
};
|
||||
|
||||
struct Children
|
||||
{
|
||||
std::vector<entt::entity> children;
|
||||
};
|
||||
|
||||
struct CollisionBox
|
||||
{
|
||||
};
|
||||
@@ -34,12 +44,12 @@ struct Collided
|
||||
{
|
||||
};
|
||||
|
||||
struct TranslateSystem
|
||||
{
|
||||
flecs::system translate_system;
|
||||
};
|
||||
|
||||
struct PhysicsModule
|
||||
{
|
||||
PhysicsModule(flecs::world& world);
|
||||
PhysicsModule(entt::registry& registry);
|
||||
|
||||
static void TranslatePhysicsObject(entt::registry& registry);
|
||||
static void PropagatePosition(entt::registry& registry);
|
||||
static void RemoveCollisionMarker(entt::registry& registry);
|
||||
static void CollisionCheck(entt::registry& registry);
|
||||
};
|
||||
|
||||
111
src/render.cpp
@@ -1,73 +1,58 @@
|
||||
#include "render.hpp"
|
||||
|
||||
#include "definitions.hpp"
|
||||
#include "level.hpp"
|
||||
#include "physics.hpp"
|
||||
#include "sprite.hpp"
|
||||
|
||||
#include <Hall/Hall.h>
|
||||
|
||||
#include <format>
|
||||
|
||||
RenderModule::RenderModule(flecs::world& world)
|
||||
RenderModule::RenderModule(entt::registry& registry)
|
||||
{
|
||||
world.system<SdlHandles>("RenderClear")
|
||||
.term_at(0)
|
||||
.singleton()
|
||||
.kind(flecs::PreStore)
|
||||
.each([](SdlHandles& sdl_handles) { SDL_RenderClear(sdl_handles.renderer); });
|
||||
|
||||
flecs::entity render_present_phase =
|
||||
world.entity().add(flecs::Phase).depends_on(flecs::OnStore);
|
||||
|
||||
world.system<SdlHandles>("RenderPresent")
|
||||
.term_at(0)
|
||||
.singleton()
|
||||
.kind(render_present_phase)
|
||||
.each([](SdlHandles& sdl_handles) { SDL_RenderPresent(sdl_handles.renderer); });
|
||||
|
||||
world.system<SdlHandles const, Position const, Size const, Sprite const>("RenderSprites")
|
||||
.kind(flecs::OnStore)
|
||||
.term_at(0)
|
||||
.singleton()
|
||||
.each(
|
||||
[](SdlHandles const& sdl_handles,
|
||||
Position const& pos,
|
||||
Size const& size,
|
||||
Sprite const& sprite)
|
||||
{
|
||||
TextureAtlasLayout layout = sprite.texture->texture_atlas_layout;
|
||||
uint8_t row = sprite.texture_atlas_index / layout.columns;
|
||||
uint8_t column = sprite.texture_atlas_index % layout.columns;
|
||||
SDL_FRect srcrect{static_cast<float>(column * layout.width),
|
||||
static_cast<float>(row * layout.height),
|
||||
static_cast<float>(layout.width),
|
||||
static_cast<float>(layout.height)};
|
||||
|
||||
SDL_FRect dstrect{static_cast<float>(pos.x),
|
||||
static_cast<float>(pos.y),
|
||||
static_cast<float>(size.w),
|
||||
static_cast<float>(size.h)};
|
||||
|
||||
SDL_RenderTexture(
|
||||
sdl_handles.renderer, sprite.texture->sdl_texture, &srcrect, &dstrect);
|
||||
});
|
||||
|
||||
world.system<SdlHandles const, Game const, FontAssets const>("RenderScore")
|
||||
.kind(flecs::OnStore)
|
||||
.term_at(0)
|
||||
.singleton()
|
||||
.term_at(1)
|
||||
.singleton()
|
||||
.term_at(2)
|
||||
.singleton()
|
||||
.each(
|
||||
[](SdlHandles const& sdl_handles, Game const& game, FontAssets const& font_assets)
|
||||
{
|
||||
auto score_string = std::format("Score: {}\nTime: {}", game.score, game.time);
|
||||
auto text = TTF_CreateText(sdl_handles.text_engine,
|
||||
font_assets.default_font.font,
|
||||
score_string.c_str(),
|
||||
score_string.length());
|
||||
TTF_DrawRendererText(text, 0.0, 0.0);
|
||||
|
||||
TTF_DestroyText(text);
|
||||
});
|
||||
}
|
||||
|
||||
void RenderModule::RenderSprites(entt::registry& registry)
|
||||
{
|
||||
auto const& game = registry.ctx().get<Game>();
|
||||
auto sprites_view =
|
||||
registry.view<Position const, Size const, Sprite const>(entt::exclude<Background>);
|
||||
auto background_view = registry.view<Position const, Size const, Sprite const, Background>();
|
||||
|
||||
auto render_sprite =
|
||||
[](entt::entity entity, Position const& pos, Size const& size, Sprite const& sprite)
|
||||
{
|
||||
TextureAtlasLayout layout = sprite.texture->texture_atlas_layout;
|
||||
uint8_t row = sprite.texture_atlas_index / layout.columns;
|
||||
uint8_t column = sprite.texture_atlas_index % layout.columns;
|
||||
// Problemchen: Wir können die Sprites nicht strecken... hat keiner Interpolation
|
||||
// implementiert?
|
||||
Hall::Draw(reinterpret_cast<unsigned short const*>(sprite.texture->data), // Das ist 100% UB
|
||||
column * layout.width,
|
||||
row * layout.height,
|
||||
pos.x,
|
||||
pos.y,
|
||||
layout.width,
|
||||
layout.height,
|
||||
sprite.texture->data_length);
|
||||
};
|
||||
|
||||
background_view.each(render_sprite);
|
||||
sprites_view.each(render_sprite);
|
||||
}
|
||||
|
||||
void RenderModule::RenderScore(entt::registry& registry)
|
||||
{
|
||||
// auto const& sdl_handles = registry.ctx().get<SdlHandles>();
|
||||
auto const& game = registry.ctx().get<Game>();
|
||||
// auto const& font_assets = registry.ctx().get<FontAssets>();
|
||||
|
||||
auto score_string = std::format("Score: {}\nTime: {}", game.score, game.time);
|
||||
// auto text = TTF_CreateText(sdl_handles.text_engine,
|
||||
// font_assets.default_font.font,
|
||||
// score_string.c_str(),
|
||||
// score_string.length());
|
||||
// TTF_DrawRendererText(text, 0.0, 0.0);
|
||||
// TTF_DestroyText(text);
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <flecs.h>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
struct RenderModule
|
||||
{
|
||||
RenderModule(flecs::world& world);
|
||||
RenderModule(entt::registry& registry);
|
||||
|
||||
static void RenderSprites(entt::registry& registry);
|
||||
static void RenderScore(entt::registry& registry);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "assets.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <cstdint>
|
||||
|
||||
struct Sprite
|
||||
|
||||
11
wuehans/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
add_library(WueHans STATIC start.S syscall.c)
|
||||
|
||||
target_include_directories(WueHans PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(WueHans PRIVATE RISCV_Options)
|
||||
|
||||
target_link_options(WueHans PUBLIC
|
||||
-T ${CMAKE_CURRENT_SOURCE_DIR}/wuehans.ld
|
||||
)
|
||||
54
wuehans/start.S
Normal file
@@ -0,0 +1,54 @@
|
||||
.section .text.startSection
|
||||
.global _Z4mainv
|
||||
.global _start
|
||||
|
||||
_start:
|
||||
/* zero-initialize all registers */
|
||||
addi x1, zero, 0
|
||||
addi x2, zero, 0
|
||||
addi x3, zero, 0
|
||||
addi x4, zero, 0
|
||||
addi x5, zero, 0
|
||||
addi x6, zero, 0
|
||||
addi x7, zero, 0
|
||||
addi x8, zero, 0
|
||||
addi x9, zero, 0
|
||||
addi x10, zero, 0
|
||||
addi x11, zero, 0
|
||||
addi x12, zero, 0
|
||||
addi x13, zero, 0
|
||||
addi x14, zero, 0
|
||||
addi x15, zero, 0
|
||||
addi x16, zero, 0
|
||||
addi x17, zero, 0
|
||||
addi x18, zero, 0
|
||||
addi x19, zero, 0
|
||||
addi x20, zero, 0
|
||||
addi x21, zero, 0
|
||||
addi x22, zero, 0
|
||||
addi x23, zero, 0
|
||||
addi x24, zero, 0
|
||||
addi x25, zero, 0
|
||||
addi x26, zero, 0
|
||||
addi x27, zero, 0
|
||||
addi x28, zero, 0
|
||||
addi x29, zero, 0
|
||||
addi x30, zero, 0
|
||||
addi x31, zero, 0
|
||||
|
||||
/* set stack pointer */
|
||||
.equ STACK_START, 0x02000000
|
||||
lui sp, %hi(STACK_START)
|
||||
addi sp, sp, %lo(STACK_START)
|
||||
|
||||
/* push zeros on the stack for argc and argv */
|
||||
/* (stack is aligned to 16 bytes in riscv calling convention) */
|
||||
addi sp,sp,-16
|
||||
sw zero,0(sp)
|
||||
sw zero,4(sp)
|
||||
sw zero,8(sp)
|
||||
sw zero,12(sp)
|
||||
|
||||
/* jump to libc init */
|
||||
// j _Z4mainv
|
||||
j main
|
||||
186
wuehans/syscall.c
Normal file
@@ -0,0 +1,186 @@
|
||||
// #include <fatfs/ff.h>
|
||||
#include <wuehans_config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
/* #include <DebugHelper.h> */
|
||||
|
||||
void *__dso_handle = 0;
|
||||
|
||||
// const TCHAR STDOUT[30] = "stdout.txt";
|
||||
// const TCHAR STDERR[30] = "stderr.txt";
|
||||
|
||||
// FIL fp = {0};
|
||||
// FATFS FatFs = {0};
|
||||
// BYTE is_mounted = 0;
|
||||
|
||||
// struct FD_Data {
|
||||
// FIL fp;
|
||||
// BYTE mode;
|
||||
// BYTE is_open;
|
||||
// } FD_Data_default = {NULL, FA_READ, 0};
|
||||
// typedef struct FD_Data FD_Data;
|
||||
|
||||
// #define FILE_AMOUNT 4
|
||||
// static FD_Data fd_data[FILE_AMOUNT];
|
||||
|
||||
// int _write(int fd, char *ptr, int len) {
|
||||
// if (is_mounted == 0) {
|
||||
// f_mount(&FatFs, "", 0);
|
||||
// is_mounted = 1;
|
||||
// }
|
||||
// // stdout
|
||||
// if (fd == 1) {
|
||||
|
||||
// FIL write_file;
|
||||
// FRESULT fr = f_open(&write_file, STDOUT, FA_OPEN_APPEND | FA_WRITE);
|
||||
// if (fr != 0) {
|
||||
// return fr;
|
||||
// }
|
||||
|
||||
// UINT written = 0;
|
||||
|
||||
// fr = f_write(&write_file, ptr, len, &written);
|
||||
// if (fr != 0) {
|
||||
// // TODO: Set errno
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
// f_close(&write_file);
|
||||
|
||||
// // HACK: Hackermann
|
||||
// volatile int* x = (int*) 0x80000000;
|
||||
// int b = *x;
|
||||
// // HACK: Hackermann Ende
|
||||
|
||||
// return written;
|
||||
// } else if (fd > 2 && (fd-3) < FILE_AMOUNT && fd_data[fd-3].is_open) {
|
||||
// UINT bw = 0;
|
||||
// f_write(&fd_data[fd-3].fp, ptr, len, &bw);
|
||||
|
||||
// return bw;
|
||||
// }
|
||||
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
// int _read(int fd, char *ptr, int len) {
|
||||
// if (fd > 2 && (fd-3) < FILE_AMOUNT && fd_data[fd-3].is_open) {
|
||||
// UINT bytesRead = 0;
|
||||
// FRESULT result = f_read(&fd_data[fd-3].fp, ptr, len, &bytesRead);
|
||||
// /* ScreenPrint("_read"); */
|
||||
// return bytesRead;
|
||||
// }
|
||||
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
// void *_sbrk(int incr) {
|
||||
// extern int heap_begin;
|
||||
// static unsigned char *heap = NULL;
|
||||
// unsigned char *prev_heap;
|
||||
|
||||
// if (heap == NULL) {
|
||||
// heap = (unsigned char *)&heap_begin;
|
||||
// }
|
||||
// prev_heap = heap;
|
||||
|
||||
// if ((int)heap + incr < heap_begin + HEAP_SIZE) {
|
||||
// heap += incr;
|
||||
// }
|
||||
|
||||
// /* ScreenPrint("_sbrk"); */
|
||||
// return prev_heap;
|
||||
// }
|
||||
|
||||
// int _fstat(int fd, struct stat *st) {
|
||||
// st->st_mode = S_IFREG;
|
||||
// /* ScreenPrint("_fstat"); */
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// int _lseek(int fd, int offset, int whence) {
|
||||
// // Invalid lseek call
|
||||
// if (fd <= 2 || (fd-3) >= FILE_AMOUNT || !fd_data[fd-3].is_open) {
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
// // Calculate the correct offset for f_lseek()
|
||||
// FSIZE_t ofs = 0;
|
||||
// switch (whence) {
|
||||
// // Set to offset directly
|
||||
// case SEEK_SET:
|
||||
// ofs = offset;
|
||||
// break;
|
||||
|
||||
// // Increment by offset
|
||||
// case SEEK_CUR:
|
||||
// ofs = f_tell(&fd_data[fd-3].fp) + offset;
|
||||
// break;
|
||||
|
||||
// // Append offset to EOF
|
||||
// case SEEK_END:
|
||||
// ofs = f_size(&fd_data[fd-3].fp) + offset;
|
||||
// break;
|
||||
// default:
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
// FRESULT result = f_lseek(&fd_data[fd-3].fp, ofs);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// int _open(const char *name, int flags, int mode) {
|
||||
// if (is_mounted == 0) {
|
||||
// f_mount(&FatFs, "", 0);
|
||||
// is_mounted = 1;
|
||||
// }
|
||||
|
||||
// int i;
|
||||
// for (i = 0; i < FILE_AMOUNT; i++) {
|
||||
// if (fd_data[i].is_open == 1) {
|
||||
// // Entry already in use
|
||||
// continue;
|
||||
// }
|
||||
// mode = FA_READ;
|
||||
// FRESULT fr = f_open(&fd_data[i].fp, name, mode);
|
||||
// if (fr != FR_OK) {
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
// fd_data[i].mode = mode;
|
||||
// fd_data[i].is_open = 1;
|
||||
// // Exclude stdout, stderr, stdin
|
||||
// return i+3;
|
||||
// }
|
||||
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
// int _close(int fd) {
|
||||
// if (fd > 2 && (fd-3) < FILE_AMOUNT) {
|
||||
// fd_data[fd-3].is_open = 0;
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
int _isatty(int fd)
|
||||
{
|
||||
errno = ENOTTY;
|
||||
/* ScreenPrint("isatty"); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _exit(int status) {
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
||||
int _kill(int pid, int sig) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _getpid() { return -1; }
|
||||
207
wuehans/wuehans.ld
Normal file
@@ -0,0 +1,207 @@
|
||||
|
||||
/* ---- Original Script: /opt/riscv32i/riscv32-unknown-elf/lib/ldscripts/elf32lriscv.x ---- */
|
||||
/* Default linker script, for normal executables */
|
||||
/* Copyright (C) 2014-2017 Free Software Foundation, Inc.
|
||||
Copying and distribution of this script, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. */
|
||||
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
|
||||
"elf32-littleriscv")
|
||||
OUTPUT_ARCH(riscv)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x00000000;
|
||||
|
||||
.startSection :
|
||||
{
|
||||
KEEP(*(.text.startSection))
|
||||
}
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||
*(.text.exit .text.exit.*)
|
||||
*(.text.startup .text.startup.*)
|
||||
*(.text.hot .text.hot.*)
|
||||
*(.stub .text.* .gnu.linkonce.t.*)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
}
|
||||
.init :
|
||||
{
|
||||
KEEP (*(SORT_NONE(.init)))
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.iplt : { *(.iplt) }
|
||||
.fini :
|
||||
{
|
||||
KEEP (*(SORT_NONE(.fini)))
|
||||
}
|
||||
PROVIDE (__etext = .);
|
||||
PROVIDE (_etext = .);
|
||||
PROVIDE (etext = .);
|
||||
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.sdata2 :
|
||||
{
|
||||
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
|
||||
}
|
||||
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
|
||||
.gcc_except_table.*) }
|
||||
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
|
||||
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
|
||||
.exception_ranges*) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||
/* Exception handling */
|
||||
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
|
||||
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
|
||||
/* Thread Local Storage sections */
|
||||
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
|
||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||
.preinit_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
}
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
}
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
}
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*crtbegin?.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*crtbegin?.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
}
|
||||
.jcr : { KEEP (*(.jcr)) }
|
||||
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
. = DATA_SEGMENT_RELRO_END (0, .);
|
||||
.data :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata :
|
||||
{
|
||||
__global_pointer$ = . + 0x800;
|
||||
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||
}
|
||||
_edata = .; PROVIDE (edata = .);
|
||||
. = .;
|
||||
__bss_start = .;
|
||||
.sbss :
|
||||
{
|
||||
*(.dynsbss)
|
||||
*(.sbss .sbss.* .gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
}
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
PROVIDE(_bss_end = .);
|
||||
/* Align here to ensure that the .bss section occupies space up to
|
||||
_end. Align after .bss to ensure correct alignment even if the
|
||||
.bss section disappears because there are no input sections. FIXME: Why do we need it? When there is no .bss section, we don't
|
||||
pad the .data section. */
|
||||
. = ALIGN(. != 0 ? 32 / 8 : 1);
|
||||
}
|
||||
. = ALIGN(32 / 8);
|
||||
. = SEGMENT_START("ldata-segment", .);
|
||||
. = ALIGN(32 / 8);
|
||||
_end = .; PROVIDE (end = .);
|
||||
. = DATA_SEGMENT_END (.);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
/* DWARF 3 */
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
/* DWARF Extension. */
|
||||
.debug_macro 0 : { *(.debug_macro) }
|
||||
.debug_addr 0 : { *(.debug_addr) }
|
||||
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
|
||||
PROVIDE(heap_begin = .);
|
||||
}
|
||||
7
wuehans/wuehans_config.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef WUEHANS_CONFIG_H
|
||||
#define WUEHANS_CONFIG_H
|
||||
|
||||
// Heap Size in Bytes
|
||||
#define HEAP_SIZE 0x800000
|
||||
|
||||
#endif
|
||||