From 8f303eec6adb4b8d428c64743fd8343e736bb823 Mon Sep 17 00:00:00 2001 From: Fries Date: Thu, 14 Mar 2024 23:19:39 -0700 Subject: [PATCH] Try to abstract out the engine to make it more cross-platform. This means you maybe can run it on linux, which is the goal for profiling and debugging purposes and it makes it easier to do that (even if the cpu is faster, i can still see expensive functions). Currently only hello.elf works on linux and hello.elf and cube.elf on the dreamcast. gl.elf is broken on both because of controller stuff. --- .vscode/launch.json | 89 ++++++++++++++++++-- meson.build | 37 +------- romdisk/cube.mtl | 10 +++ romdisk/cube.obj | 1 + cube.cc => src/cube.cc | 55 +++++++++--- src/engine/controller/controller.hh | 24 ++++++ src/engine/controller/dreamcastController.cc | 54 ++++++++++++ src/engine/controller/dreamcastController.hh | 18 ++++ src/engine/controller/linuxController.cc | 48 +++++++++++ src/engine/controller/linuxController.hh | 17 ++++ src/engine/controller/meson.build | 12 +++ src/engine/dreamcastEngine.cc | 24 ++++++ src/engine/dreamcastEngine.hh | 10 +++ engine.cc => src/engine/engine.cc | 39 ++++++--- engine.hh => src/engine/engine.hh | 17 +++- src/engine/linuxEngine.cc | 44 ++++++++++ src/engine/linuxEngine.hh | 13 +++ src/engine/meson.build | 14 +++ src/engine/nativeEngine.cc | 0 src/engine/nativeEngine.hh | 11 +++ gl.cc => src/gl.cc | 42 ++++----- hello.cc => src/hello.cc | 9 +- src/meson.build | 54 ++++++++++++ 23 files changed, 547 insertions(+), 95 deletions(-) rename cube.cc => src/cube.cc (71%) create mode 100644 src/engine/controller/controller.hh create mode 100644 src/engine/controller/dreamcastController.cc create mode 100644 src/engine/controller/dreamcastController.hh create mode 100644 src/engine/controller/linuxController.cc create mode 100644 src/engine/controller/linuxController.hh create mode 100644 src/engine/controller/meson.build create mode 100644 src/engine/dreamcastEngine.cc create mode 100644 src/engine/dreamcastEngine.hh rename engine.cc => src/engine/engine.cc (71%) rename engine.hh => src/engine/engine.hh (65%) create mode 100644 src/engine/linuxEngine.cc create mode 100644 src/engine/linuxEngine.hh create mode 100644 src/engine/meson.build create mode 100644 src/engine/nativeEngine.cc create mode 100644 src/engine/nativeEngine.hh rename gl.cc => src/gl.cc (57%) rename hello.cc => src/hello.cc (84%) create mode 100644 src/meson.build diff --git a/.vscode/launch.json b/.vscode/launch.json index 7e005d7..1b6bf0a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,10 +1,58 @@ { "configurations": [ + { + "name": "(gdb, Linux) Launch hello.elf", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/src/hello.elf", + "args": [], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ] + }, + { + "name": "(gdb, Linux) Launch gl.elf", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/src/gl.elf", + "args": [], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ] + }, { "name": "(gdb) Launch gl.elf", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build/gl.elf", + "program": "${workspaceFolder}/build/src/gl.elf", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -14,7 +62,7 @@ "miDebuggerPath": "/opt/toolchains/dc/sh-elf/bin/sh-elf-gdb", "miDebuggerServerAddress": "localhost:3263", "debugServerPath": "/usr/bin/flycast", - "debugServerArgs": "${workspaceFolder}/build/gl.elf", + "debugServerArgs": "${workspaceFolder}/build/src/gl.elf", "setupCommands": [ { "description": "Enable pretty-printing for gdb", @@ -33,7 +81,7 @@ "name": "(gdb) Launch cube.elf", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build/cube.elf", + "program": "${workspaceFolder}/build/src/cube.elf", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -43,7 +91,7 @@ "miDebuggerPath": "/opt/toolchains/dc/sh-elf/bin/sh-elf-gdb", "miDebuggerServerAddress": "localhost:3263", "debugServerPath": "/usr/bin/flycast", - "debugServerArgs": "${workspaceFolder}/build/cube.elf", + "debugServerArgs": "${workspaceFolder}/build/src/cube.elf", "setupCommands": [ { "description": "Enable pretty-printing for gdb", @@ -62,7 +110,7 @@ "name": "(gdb, lxdream-nitro) Launch cube.elf", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build/cube.elf", + "program": "${workspaceFolder}/build/src/cube.elf", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -72,7 +120,36 @@ "miDebuggerPath": "/opt/toolchains/dc/sh-elf/bin/sh-elf-gdb", "miDebuggerServerAddress": "localhost:3263", "debugServerPath": "/home/user/Downloads/lxdream-nitro/builddir/lxdream-nitro", - "debugServerArgs": "-d -g 3263 -e ${workspaceFolder}/build/cube.elf", + "debugServerArgs": "-d -g 3263 -e ${workspaceFolder}/build/src/cube.elf", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set SuperH architechture", + "text": "set architecture sh4" + } + ], + "avoidWindowsConsoleRedirection": false, + "internalConsoleOptions": "openOnSessionStart" + }, + { + "name": "(gdb, lxdream-nitro) Launch gl.elf", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/src/gl.elf", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "/opt/toolchains/dc/sh-elf/bin/sh-elf-gdb", + "miDebuggerServerAddress": "localhost:3263", + "debugServerPath": "/home/user/Downloads/lxdream-nitro/builddir/lxdream-nitro", + "debugServerArgs": "-d -g 3263 -e ${workspaceFolder}/build/src/gl.elf", "setupCommands": [ { "description": "Enable pretty-printing for gdb", diff --git a/meson.build b/meson.build index a79a5f4..40af1cc 100644 --- a/meson.build +++ b/meson.build @@ -1,40 +1,5 @@ project('dreamcast-opengl', 'c', 'cpp', default_options: ['cpp_std=c++20']) -cc = meson.get_compiler('c') -kosinc = include_directories('/opt/toolchains/dc/kos/include') -koskernelinc = include_directories('/opt/toolchains/dc/kos/kernel/arch/dreamcast/include') -kosaddonsinc = include_directories('/opt/toolchains/dc/kos/addons/include') -kosportsinc = include_directories('/opt/toolchains/dc/kos-ports/include') - -GL = cc.find_library('GL', required: true) -math = cc.find_library('m', required: true) -stb_image = cc.find_library('stb_image', required: true) subdir('romdisk') -tinyobjloader = subproject('tinyobjloader') -tinyobjloader_dep = tinyobjloader.get_variable('tinyobjloader_dep') -# pcx = cc.find_library('pcx', required: true) -# kosutils = cc.find_library('kosutils', required: true) - -deps = [ - GL, - math, - stb_image, - tinyobjloader_dep -] - -incdirs = [ - kosinc, - koskernelinc, - kosaddonsinc, - kosportsinc -] - -engine = static_library('engine', ['engine.cc'], dependencies: deps, include_directories: incdirs) -engine_dep = declare_dependency(link_with: engine, include_directories: incdirs) - -deps += [engine_dep] - -executable('hello.elf', ['hello.cc'], dependencies: deps, include_directories: incdirs) -executable('gl.elf', ['gl.cc'], dependencies: deps, include_directories: incdirs) -executable('cube.elf', ['cube.cc', romdsk_o], dependencies: deps, include_directories: incdirs) +subdir('src') diff --git a/romdisk/cube.mtl b/romdisk/cube.mtl index 763e0ab..7b389ea 100644 --- a/romdisk/cube.mtl +++ b/romdisk/cube.mtl @@ -1,2 +1,12 @@ # Blender 4.0.2 MTL File: 'None' # www.blender.org + +newmtl Material.002 +Ns 250.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.033988 0.604769 0.801009 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 diff --git a/romdisk/cube.obj b/romdisk/cube.obj index ba883db..953ec95 100644 --- a/romdisk/cube.obj +++ b/romdisk/cube.obj @@ -31,6 +31,7 @@ vt 0.875000 0.500000 vt 0.625000 1.000000 vt 0.875000 0.750000 s 0 +usemtl Material.002 f 2/1/1 3/2/1 1/3/1 f 4/4/2 7/5/2 3/2/2 f 8/6/3 5/7/3 7/5/3 diff --git a/cube.cc b/src/cube.cc similarity index 71% rename from cube.cc rename to src/cube.cc index 1064663..961fcef 100644 --- a/cube.cc +++ b/src/cube.cc @@ -1,12 +1,21 @@ +#ifdef _arch_dreamcast #include #include #include #include #include +#else +#define STB_IMAGE_IMPLEMENTATION +#include +#include +#include +#endif + #include #include -#include "engine.hh" +#include +#include "engine/engine.hh" class Cube : public Engine { unsigned int texture; @@ -31,10 +40,14 @@ void Cube::model() { for (size_t s = 0; s < shapes.size(); s++) { // Loop over faces(polygon) size_t index_offset = 0; + std::vector vertexes {}; + std::vector normals {}; + std::vector textureCoords {}; + for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) { size_t fv = size_t(shapes[s].mesh.num_face_vertices[f]); - glBegin(GL_TRIANGLES); + // glBegin(GL_TRIANGLES); // Loop over vertices in the face. for (size_t v = 0; v < fv; v++) { // access to vertex @@ -45,8 +58,10 @@ void Cube::model() { attrib.vertices[3 * size_t(idx.vertex_index) + 1]; tinyobj::real_t vz = attrib.vertices[3 * size_t(idx.vertex_index) + 2]; - glVertex3f(vx, vy, vz); - drawCalls += 1; + Vector3 vertex = {vx, vy, vz}; + vertexes.push_back(vertex); + // glVertex3f(vx, vy, vz); + // drawCalls += 1; // Check if `normal_index` is zero or positive. negative = no @@ -58,8 +73,12 @@ void Cube::model() { attrib.normals[3 * size_t(idx.normal_index) + 1]; tinyobj::real_t nz = attrib.normals[3 * size_t(idx.normal_index) + 2]; - glNormal3f(nx, ny, nz); - drawCalls += 1; + Vector3 normal = {nx, ny, nz}; + normals.push_back(normal); + // glNormal3f(nx, ny, nz); + // drawCalls += 1; + } else { + normals.push_back(Engine::Vector3::zero()); } // Check if `texcoord_index` is zero or positive. negative = no @@ -69,14 +88,27 @@ void Cube::model() { attrib.texcoords[2 * size_t(idx.texcoord_index) + 0]; tinyobj::real_t ty = attrib.texcoords[2 * size_t(idx.texcoord_index) + 1]; - glTexCoord2f(tx, ty); - drawCalls += 1; + Vector3 textureCoord = {tx, ty, 0}; + textureCoords.push_back(textureCoord); + // glTexCoord2f(tx, ty); + // drawCalls += 1; + } else { + textureCoords.push_back(Vector3::zero()); } } index_offset += fv; - glEnd(); + // glEnd(); } + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, &vertexes[0]); + glNormalPointer(GL_FLOAT, 0, &normals[0]); + glTexCoordPointer(2, GL_FLOAT, 0, &textureCoords[0]); + glDrawArrays(GL_TRIANGLES, 0, vertexes.size()); + // glDrawElements(GL_TRIANGLES, shapes[s].mesh.indices.size(), GL_UNSIGNED_INT, &shapes[s].mesh.indices[0]); + drawCalls += 1; } printf("Draw Calls: %i\n", drawCalls); drawCalls = 0; @@ -102,11 +134,10 @@ void Cube::displayStuff() { glTranslatef(0.0f, 0.0f, -5.0f); glRotatef(90, 0.0f, 1.0f, 0.5f); model(); - glKosSwapBuffers(); + SwapBuffers(); } void Cube::initScreen() { - glKosInit(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -128,7 +159,9 @@ void Cube::initScreen() { if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + #ifdef _arch_dreamcast glGenerateMipmap(GL_TEXTURE_2D); + #endif } else { printf("Texture failed to load.\n"); } diff --git a/src/engine/controller/controller.hh b/src/engine/controller/controller.hh new file mode 100644 index 0000000..7a5bbda --- /dev/null +++ b/src/engine/controller/controller.hh @@ -0,0 +1,24 @@ +#ifndef CONTROLLER_HH +#define CONTROLLER_HH +class Controller { + public: + enum Button { + A = (1 << 0), + B = (1 << 1), + X = (1 << 2), + Y = (1 << 3), + DPAD_UP = (1 << 4), + DPAD_DOWN = (1 << 5), + DPAD_LEFT = (1 << 6), + DPAD_RIGHT = (1 << 7) + }; + virtual bool InitializeController() { return false; }; + virtual void PollController(){}; + virtual bool IsButtonPressed(Button button) { return 0; }; + virtual float GetLeftJoystickXAxis() { return 0.0; }; + virtual float GetLeftJoystickYAxis() { return 0.0; }; + + protected: + virtual int GetButtonMask(Button button) { return 0; } +}; +#endif diff --git a/src/engine/controller/dreamcastController.cc b/src/engine/controller/dreamcastController.cc new file mode 100644 index 0000000..c8393b1 --- /dev/null +++ b/src/engine/controller/dreamcastController.cc @@ -0,0 +1,54 @@ +#include "dreamcastController.hh" +#include "controller.hh" + +DreamcastController::DreamcastController() { +} + +bool DreamcastController::InitializeController() { + controller = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + if (this->controller) { + controller_state = (cont_state_t*)maple_dev_status(controller); + return true; + } else { + controller = nullptr; + return false; + } +} + +void DreamcastController::PollController() { + controller_state = (cont_state_t*)maple_dev_status(controller); +} + +bool DreamcastController::IsButtonPressed(Button button) { + return controller_state->buttons & GetButtonMask(button); +} + +float DreamcastController::GetLeftJoystickXAxis() { + return (controller_state->joyx / 127.0f); +} + +float DreamcastController::GetLeftJoystickYAxis() { + return (controller_state->joyy / 127.0f); +} + +int DreamcastController::GetButtonMask(Button button) { + switch (button) { + case Button::A: + return CONT_A; + case Button::B: + return CONT_B; + case Button::X: + return CONT_X; + case Button::Y: + return CONT_Y; + case Button::DPAD_UP: + return CONT_DPAD_UP; + case Button::DPAD_DOWN: + return CONT_DPAD_DOWN; + case Button::DPAD_LEFT: + return CONT_DPAD_LEFT; + case Button::DPAD_RIGHT: + return CONT_DPAD_RIGHT; + } + return 0; +} diff --git a/src/engine/controller/dreamcastController.hh b/src/engine/controller/dreamcastController.hh new file mode 100644 index 0000000..e8c47a0 --- /dev/null +++ b/src/engine/controller/dreamcastController.hh @@ -0,0 +1,18 @@ +#ifndef DREAMCAST_CONTROLLER_HH +#define DREAMCAST_CONTROLLER_HH +#include + +#include "controller.hh" +class DreamcastController : public Controller { + public: + DreamcastController(); + bool InitializeController() override; + void PollController() override; + bool IsButtonPressed(Button button) override; + float GetLeftJoystickXAxis() override; + float GetLeftJoystickYAxis() override; + int GetButtonMask(Button button) override; + maple_device_t* controller = nullptr; + cont_state_t* controller_state = nullptr; +}; +#endif diff --git a/src/engine/controller/linuxController.cc b/src/engine/controller/linuxController.cc new file mode 100644 index 0000000..bffd309 --- /dev/null +++ b/src/engine/controller/linuxController.cc @@ -0,0 +1,48 @@ +#include "linuxController.hh" + +#include + +bool LinuxController::InitializeController() { + if (glfwJoystickIsGamepad(GLFW_JOYSTICK_1)) { + glfwGetGamepadState(GLFW_JOYSTICK_1, &controllerState); + return true; + } + return false; +} + +void LinuxController::PollController() { + glfwGetGamepadState(GLFW_JOYSTICK_1, &controllerState); +} + +bool LinuxController::IsButtonPressed(Button button) { + return controllerState.buttons[GetButtonMask(button)]; +} + +float LinuxController::GetLeftJoystickXAxis() { + return controllerState.axes[GLFW_GAMEPAD_AXIS_LEFT_X]; +} + +float LinuxController::GetLeftJoystickYAxis() { + return controllerState.axes[GLFW_GAMEPAD_AXIS_LEFT_Y]; +} + +int LinuxController::GetButtonMask(Button button) { + switch (button) { + case Button::A: + return GLFW_GAMEPAD_BUTTON_A; + case Button::B: + return GLFW_GAMEPAD_BUTTON_B; + case Button::X: + return GLFW_GAMEPAD_BUTTON_X; + case Button::Y: + return GLFW_GAMEPAD_BUTTON_Y; + case Button::DPAD_UP: + return GLFW_GAMEPAD_BUTTON_DPAD_UP; + case Button::DPAD_DOWN: + return GLFW_GAMEPAD_BUTTON_DPAD_DOWN; + case Button::DPAD_LEFT: + return GLFW_GAMEPAD_BUTTON_DPAD_LEFT; + case Button::DPAD_RIGHT: + return GLFW_GAMEPAD_BUTTON_DPAD_RIGHT; + } +} diff --git a/src/engine/controller/linuxController.hh b/src/engine/controller/linuxController.hh new file mode 100644 index 0000000..49f55d9 --- /dev/null +++ b/src/engine/controller/linuxController.hh @@ -0,0 +1,17 @@ +#ifndef LINUX_CONTROLLER_HH +#define LINUX_CONTROLLER_HH +#include "controller.hh" +#include + +class LinuxController : public Controller { + public: + bool InitializeController() override; + void PollController() override; + bool IsButtonPressed(Button button) override; + float GetLeftJoystickXAxis() override; + float GetLeftJoystickYAxis() override; + int GetButtonMask(Button button) override; + GLFWgamepadstate controllerState; +}; + +#endif diff --git a/src/engine/controller/meson.build b/src/engine/controller/meson.build new file mode 100644 index 0000000..ba0762d --- /dev/null +++ b/src/engine/controller/meson.build @@ -0,0 +1,12 @@ +sources = [] +incdirs = include_directories('.') + +if host_machine.system() == 'dreamcast' + sources += 'dreamcastController.cc' +endif + +if host_machine.system() == 'linux' + sources += 'linuxController.cc' +endif + +controller = static_library('controller', sources) diff --git a/src/engine/dreamcastEngine.cc b/src/engine/dreamcastEngine.cc new file mode 100644 index 0000000..194e18a --- /dev/null +++ b/src/engine/dreamcastEngine.cc @@ -0,0 +1,24 @@ +#ifdef _arch_dreamcast +#include "dreamcastEngine.hh" +#include +#include +#include "controller/dreamcastController.hh" + +void DreamcastEngine::initializeEngine() { + glKosInit(); + // printSystemInformation(); +} + +void DreamcastEngine::initializeController() { + DreamcastController* dreamCont = new DreamcastController; + if (dreamCont->InitializeController()) { + controller = dreamCont; + } else { + throw std::runtime_error("Can't initialize the controller."); + } +} + +void DreamcastEngine::SwapBuffers() { + glKosSwapBuffers(); +} +#endif diff --git a/src/engine/dreamcastEngine.hh b/src/engine/dreamcastEngine.hh new file mode 100644 index 0000000..9a1830e --- /dev/null +++ b/src/engine/dreamcastEngine.hh @@ -0,0 +1,10 @@ +#ifndef DREAMCAST_ENGINE_HH +#define DREAMCAST_ENGINE_HH +#include "nativeEngine.hh" + +class DreamcastEngine : public NativeEngine { + void initializeController() override; + void initializeEngine() override; + void SwapBuffers() override; +}; +#endif diff --git a/engine.cc b/src/engine/engine.cc similarity index 71% rename from engine.cc rename to src/engine/engine.cc index 1eab9c3..46379ff 100644 --- a/engine.cc +++ b/src/engine/engine.cc @@ -2,12 +2,34 @@ #include "engine.hh" +#ifdef _arch_dreamcast #include -#include +#include "dreamcastEngine.hh" +#else +#include "linuxEngine.hh" +#endif #include #include +void Engine::initializeEngine() { + #ifdef _arch_dreamcast + engine = new DreamcastEngine; + #else + engine = new LinuxEngine; + #endif + engine->initializeEngine(); + initScreen(); + controller = engine->controller; +} + +void Engine::initializeController() { + engine->initializeController(); +} +void Engine::SwapBuffers() { + engine->SwapBuffers(); +} + void Engine::initScreen() { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glViewport(0, 0, 640, 480); @@ -25,12 +47,6 @@ void Engine::printSystemInformation() { printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS)); } -void Engine::initializeEngine() { - glKosInit(); - initScreen(); - printSystemInformation(); -} - template void Engine::deltaTimeLoop(T&& callback, struct timeval& beginningOfFrame, struct timeval& endOfFrame) { @@ -52,16 +68,15 @@ void Engine::initializeGameLoop() { } } -void Engine::pressButton(cont_state_t* controller_state, int button, - std::function callback) { - if (controller_state->buttons & button) { +void Engine::pressButton(Controller::Button button, std::function callback) { + if (controller->IsButtonPressed(button)) { if (!(buttonsPressed & button)) { buttonsPressed |= button; callback(); } } else if ((buttonsPressed & button) && - ~(controller_state->buttons & button)) { + !controller->IsButtonPressed(button)) { buttonsPressed &= ~button; } } @@ -71,3 +86,5 @@ void Engine::glVertex3fNormalized(float x, float y, float z) { glVertex3f(x * xSize, y * ySize, z); } + +Engine::Vector3 Engine::Vector3::zero() { return {0, 0, 0}; } diff --git a/engine.hh b/src/engine/engine.hh similarity index 65% rename from engine.hh rename to src/engine/engine.hh index 9533bba..55dc8b8 100644 --- a/engine.hh +++ b/src/engine/engine.hh @@ -1,11 +1,13 @@ #ifndef ENGINE_HH #define ENGINE_HH -#include #include #include +#include "controller/controller.hh" +#include "nativeEngine.hh" + class Engine { protected: static constexpr float microSecond = 0.000001f; @@ -20,17 +22,26 @@ class Engine { virtual void initScreen(); void printSystemInformation(); virtual void gameLoop(){}; - void pressButton(cont_state_t* controller_state, int button, - std::function callback); + void pressButton(Controller::Button button, std::function callback); void glVertex3fNormalized(float x, float y, float z); + void SwapBuffers(); + Controller* controller = nullptr; private: template void deltaTimeLoop(T&& callback, struct timeval& beginningOfFrame, struct timeval& endOfFrame); + NativeEngine* engine = nullptr; public: + void initializeController(); void initializeEngine(); void initializeGameLoop(); + struct Vector3 { + static Vector3 zero(); + float x; + float y; + float z; + }; }; #endif diff --git a/src/engine/linuxEngine.cc b/src/engine/linuxEngine.cc new file mode 100644 index 0000000..0c7d231 --- /dev/null +++ b/src/engine/linuxEngine.cc @@ -0,0 +1,44 @@ +#ifdef __linux__ + +#include "linuxEngine.hh" + +#include +#include + +#include "linuxController.hh" + +void LinuxEngine::initializeEngine() { + glfwInit(); + // Set OpenGL version to 1.2. + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + + // Create a GLFW window. + window = glfwCreateWindow(640, 480, "DC Engine", nullptr, nullptr); + + // Fail if the window has failed to create. + if (window == nullptr) { + const char* description; + glfwGetError(&description); + std::cout << "Failed to create GLFW window.\n" + << description << std::endl; + } + + glfwMakeContextCurrent(window); + // printSystemInformation(); +} + +void LinuxEngine::initializeController() { + LinuxController* linuxCont = new LinuxController; + if (linuxCont->InitializeController()) { + controller = linuxCont; + } else { + throw std::runtime_error("No controller detected"); + } +} + +void LinuxEngine::SwapBuffers() { + glfwSwapBuffers(window); + glfwPollEvents(); +} +#endif diff --git a/src/engine/linuxEngine.hh b/src/engine/linuxEngine.hh new file mode 100644 index 0000000..ab1e734 --- /dev/null +++ b/src/engine/linuxEngine.hh @@ -0,0 +1,13 @@ +#ifndef LINUX_ENGINE_HH +#define LINUX_ENGINE_HH +#include "nativeEngine.hh" +#include +#include + +class LinuxEngine : public NativeEngine { + void initializeController() override; + void initializeEngine() override; + void SwapBuffers() override; + GLFWwindow* window = nullptr; +}; +#endif diff --git a/src/engine/meson.build b/src/engine/meson.build new file mode 100644 index 0000000..41d29a6 --- /dev/null +++ b/src/engine/meson.build @@ -0,0 +1,14 @@ +engine_deps = [ + GL, + math, +] + +if host_machine.system() == 'linux' + engine_deps += dependency('glfw3') + engine_deps += dependency('epoxy') +endif + +subdir('controller') + +engine = static_library('engine', ['dreamcastEngine.cc', 'linuxEngine.cc', 'engine.cc'], dependencies: engine_deps, include_directories: incdirs) +engine_dep = declare_dependency(link_with: [engine, controller], include_directories: incdirs) diff --git a/src/engine/nativeEngine.cc b/src/engine/nativeEngine.cc new file mode 100644 index 0000000..e69de29 diff --git a/src/engine/nativeEngine.hh b/src/engine/nativeEngine.hh new file mode 100644 index 0000000..e252618 --- /dev/null +++ b/src/engine/nativeEngine.hh @@ -0,0 +1,11 @@ +#ifndef NATIVE_ENGINE_HH +#define NATIVE_ENGINE_HH +#include "controller/controller.hh" +class NativeEngine { + public: + virtual void initializeController(){}; + virtual void initializeEngine(){}; + virtual void SwapBuffers(){}; + Controller* controller = nullptr; +}; +#endif diff --git a/gl.cc b/src/gl.cc similarity index 57% rename from gl.cc rename to src/gl.cc index 8d480c4..a640c4f 100644 --- a/gl.cc +++ b/src/gl.cc @@ -1,10 +1,14 @@ +#ifdef _arch_dreamcast #include #include - +#include +#else +#include +#endif #include #include -#include "engine.hh" +#include "engine/engine.hh" class Glcc : public Engine { void process_input(); @@ -39,43 +43,31 @@ void Glcc::displayStuff() { glPopMatrix(); // clang-format on + + #ifdef _arch_dreamcast if (thirtyfps) { vid_waitvbl(); vid_waitvbl(); } + #endif - glKosSwapBuffers(); + SwapBuffers(); } void Glcc::process_input() { - maple_device_t* controller; - cont_state_t* controller_state; + pressButton(Controller::Button::DPAD_LEFT, [&]() { speed -= 1.0f; }); + pressButton(Controller::Button::DPAD_RIGHT, [&]() { speed += 1.0f; }); + pressButton(Controller::Button::A, [&]() { thirtyfps = !thirtyfps; }); - controller = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + speed = std::clamp(speed, 1.0f, 10.0f); - if (controller) { - controller_state = (cont_state_t*)maple_dev_status(controller); - - if (!controller_state) { - printf( - "An error has occured while trying to read the " - "controller.\n"); - } - - pressButton(controller_state, CONT_DPAD_LEFT, [&]() { speed -= 1.0f; }); - pressButton(controller_state, CONT_DPAD_RIGHT, - [&]() { speed += 1.0f; }); - pressButton(controller_state, CONT_A, - [&]() { thirtyfps = !thirtyfps; }); - - speed = std::clamp(speed, 1.0f, 10.0f); - - angle += (controller_state->joyx / 127.0f) * deltaTime * speed; - } + angle += controller->GetLeftJoystickXAxis() * deltaTime * speed; + printf("%f\n", speed); } int main() { Glcc* engine = new Glcc; engine->initializeEngine(); + engine->initializeController(); engine->initializeGameLoop(); } diff --git a/hello.cc b/src/hello.cc similarity index 84% rename from hello.cc rename to src/hello.cc index 5ef55ab..dfb3b44 100644 --- a/hello.cc +++ b/src/hello.cc @@ -1,13 +1,16 @@ +#ifdef _arch_dreamcast #include -#include -#include "engine.hh" +#else +#include +#endif +#include "engine/engine.hh" class Hello : public Engine { void triangle(); void gameLoop() override { triangle(); - glKosSwapBuffers(); + SwapBuffers(); } }; diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..176598a --- /dev/null +++ b/src/meson.build @@ -0,0 +1,54 @@ +cc = meson.get_compiler('c') + +kosinc = include_directories('/opt/toolchains/dc/kos/include') +koskernelinc = include_directories('/opt/toolchains/dc/kos/kernel/arch/dreamcast/include') +kosaddonsinc = include_directories('/opt/toolchains/dc/kos/addons/include') +kosportsinc = include_directories('/opt/toolchains/dc/kos-ports/include') + +GL = cc.find_library('GL', required: true) +math = cc.find_library('m', required: true) +# pcx = cc.find_library('pcx', required: true) +# kosutils = cc.find_library('kosutils', required: true) + +tinyobjloader = subproject('tinyobjloader') +tinyobjloader_dep = tinyobjloader.get_variable('tinyobjloader_dep') + +deps = [ + GL, + math, + tinyobjloader_dep +] + +incdirs = [] + +if host_machine.system() == 'dreamcast' + stb_image = cc.find_library('stb_image', required: true) + deps += stb_image + incdirs += [ + kosinc, + koskernelinc, + kosaddonsinc, + kosportsinc + ] +endif + +if host_machine.system() == 'linux' + deps += dependency('glfw3') + deps += dependency('glu') +endif + +subdir('engine') + +deps += [engine_dep] + +cube_sources = [ + 'cube.cc' +] + +if host_machine.system() == 'dreamcast' + cube_sources += romdsk_o +endif + +executable('hello.elf', ['hello.cc'], dependencies: deps, include_directories: incdirs) +executable('gl.elf', ['gl.cc'], dependencies: deps, include_directories: incdirs) +executable('cube.elf', cube_sources, dependencies: deps, include_directories: incdirs)