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.
This commit is contained in:
Fries 2024-03-14 23:19:39 -07:00
parent 23dd7ace18
commit 8f303eec6a
23 changed files with 547 additions and 95 deletions

89
.vscode/launch.json vendored
View file

@ -1,10 +1,58 @@
{ {
"configurations": [ "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", "name": "(gdb) Launch gl.elf",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/build/gl.elf", "program": "${workspaceFolder}/build/src/gl.elf",
"args": [], "args": [],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
@ -14,7 +62,7 @@
"miDebuggerPath": "/opt/toolchains/dc/sh-elf/bin/sh-elf-gdb", "miDebuggerPath": "/opt/toolchains/dc/sh-elf/bin/sh-elf-gdb",
"miDebuggerServerAddress": "localhost:3263", "miDebuggerServerAddress": "localhost:3263",
"debugServerPath": "/usr/bin/flycast", "debugServerPath": "/usr/bin/flycast",
"debugServerArgs": "${workspaceFolder}/build/gl.elf", "debugServerArgs": "${workspaceFolder}/build/src/gl.elf",
"setupCommands": [ "setupCommands": [
{ {
"description": "Enable pretty-printing for gdb", "description": "Enable pretty-printing for gdb",
@ -33,7 +81,7 @@
"name": "(gdb) Launch cube.elf", "name": "(gdb) Launch cube.elf",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/build/cube.elf", "program": "${workspaceFolder}/build/src/cube.elf",
"args": [], "args": [],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
@ -43,7 +91,7 @@
"miDebuggerPath": "/opt/toolchains/dc/sh-elf/bin/sh-elf-gdb", "miDebuggerPath": "/opt/toolchains/dc/sh-elf/bin/sh-elf-gdb",
"miDebuggerServerAddress": "localhost:3263", "miDebuggerServerAddress": "localhost:3263",
"debugServerPath": "/usr/bin/flycast", "debugServerPath": "/usr/bin/flycast",
"debugServerArgs": "${workspaceFolder}/build/cube.elf", "debugServerArgs": "${workspaceFolder}/build/src/cube.elf",
"setupCommands": [ "setupCommands": [
{ {
"description": "Enable pretty-printing for gdb", "description": "Enable pretty-printing for gdb",
@ -62,7 +110,7 @@
"name": "(gdb, lxdream-nitro) Launch cube.elf", "name": "(gdb, lxdream-nitro) Launch cube.elf",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/build/cube.elf", "program": "${workspaceFolder}/build/src/cube.elf",
"args": [], "args": [],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
@ -72,7 +120,36 @@
"miDebuggerPath": "/opt/toolchains/dc/sh-elf/bin/sh-elf-gdb", "miDebuggerPath": "/opt/toolchains/dc/sh-elf/bin/sh-elf-gdb",
"miDebuggerServerAddress": "localhost:3263", "miDebuggerServerAddress": "localhost:3263",
"debugServerPath": "/home/user/Downloads/lxdream-nitro/builddir/lxdream-nitro", "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": [ "setupCommands": [
{ {
"description": "Enable pretty-printing for gdb", "description": "Enable pretty-printing for gdb",

View file

@ -1,40 +1,5 @@
project('dreamcast-opengl', 'c', 'cpp', default_options: ['cpp_std=c++20']) 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') subdir('romdisk')
tinyobjloader = subproject('tinyobjloader') subdir('src')
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)

View file

@ -1,2 +1,12 @@
# Blender 4.0.2 MTL File: 'None' # Blender 4.0.2 MTL File: 'None'
# www.blender.org # 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

View file

@ -31,6 +31,7 @@ vt 0.875000 0.500000
vt 0.625000 1.000000 vt 0.625000 1.000000
vt 0.875000 0.750000 vt 0.875000 0.750000
s 0 s 0
usemtl Material.002
f 2/1/1 3/2/1 1/3/1 f 2/1/1 3/2/1 1/3/1
f 4/4/2 7/5/2 3/2/2 f 4/4/2 7/5/2 3/2/2
f 8/6/3 5/7/3 7/5/3 f 8/6/3 5/7/3 7/5/3

View file

@ -1,12 +1,21 @@
#ifdef _arch_dreamcast
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glext.h> #include <GL/glext.h>
#include <GL/glkos.h> #include <GL/glkos.h>
#include <GL/glu.h> #include <GL/glu.h>
#include <stb_image/stb_image.h> #include <stb_image/stb_image.h>
#else
#define STB_IMAGE_IMPLEMENTATION
#include <GLFW/glfw3.h>
#include <GL/glu.h>
#include <stb/stb_image.h>
#endif
#include <tiny_obj_loader.h> #include <tiny_obj_loader.h>
#include <cstdio> #include <cstdio>
#include "engine.hh" #include <vector>
#include "engine/engine.hh"
class Cube : public Engine { class Cube : public Engine {
unsigned int texture; unsigned int texture;
@ -31,10 +40,14 @@ void Cube::model() {
for (size_t s = 0; s < shapes.size(); s++) { for (size_t s = 0; s < shapes.size(); s++) {
// Loop over faces(polygon) // Loop over faces(polygon)
size_t index_offset = 0; size_t index_offset = 0;
std::vector<Vector3> vertexes {};
std::vector<Vector3> normals {};
std::vector<Vector3> textureCoords {};
for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) { 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]); size_t fv = size_t(shapes[s].mesh.num_face_vertices[f]);
glBegin(GL_TRIANGLES); // glBegin(GL_TRIANGLES);
// Loop over vertices in the face. // Loop over vertices in the face.
for (size_t v = 0; v < fv; v++) { for (size_t v = 0; v < fv; v++) {
// access to vertex // access to vertex
@ -45,8 +58,10 @@ void Cube::model() {
attrib.vertices[3 * size_t(idx.vertex_index) + 1]; attrib.vertices[3 * size_t(idx.vertex_index) + 1];
tinyobj::real_t vz = tinyobj::real_t vz =
attrib.vertices[3 * size_t(idx.vertex_index) + 2]; attrib.vertices[3 * size_t(idx.vertex_index) + 2];
glVertex3f(vx, vy, vz); Vector3 vertex = {vx, vy, vz};
drawCalls += 1; vertexes.push_back(vertex);
// glVertex3f(vx, vy, vz);
// drawCalls += 1;
// Check if `normal_index` is zero or positive. negative = no // 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]; attrib.normals[3 * size_t(idx.normal_index) + 1];
tinyobj::real_t nz = tinyobj::real_t nz =
attrib.normals[3 * size_t(idx.normal_index) + 2]; attrib.normals[3 * size_t(idx.normal_index) + 2];
glNormal3f(nx, ny, nz); Vector3 normal = {nx, ny, nz};
drawCalls += 1; 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 // 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]; attrib.texcoords[2 * size_t(idx.texcoord_index) + 0];
tinyobj::real_t ty = tinyobj::real_t ty =
attrib.texcoords[2 * size_t(idx.texcoord_index) + 1]; attrib.texcoords[2 * size_t(idx.texcoord_index) + 1];
glTexCoord2f(tx, ty); Vector3 textureCoord = {tx, ty, 0};
drawCalls += 1; textureCoords.push_back(textureCoord);
// glTexCoord2f(tx, ty);
// drawCalls += 1;
} else {
textureCoords.push_back(Vector3::zero());
} }
} }
index_offset += fv; 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); printf("Draw Calls: %i\n", drawCalls);
drawCalls = 0; drawCalls = 0;
@ -102,11 +134,10 @@ void Cube::displayStuff() {
glTranslatef(0.0f, 0.0f, -5.0f); glTranslatef(0.0f, 0.0f, -5.0f);
glRotatef(90, 0.0f, 1.0f, 0.5f); glRotatef(90, 0.0f, 1.0f, 0.5f);
model(); model();
glKosSwapBuffers(); SwapBuffers();
} }
void Cube::initScreen() { void Cube::initScreen() {
glKosInit();
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
@ -128,7 +159,9 @@ void Cube::initScreen() {
if (data) { if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, data); GL_UNSIGNED_BYTE, data);
#ifdef _arch_dreamcast
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
#endif
} else { } else {
printf("Texture failed to load.\n"); printf("Texture failed to load.\n");
} }

View file

@ -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

View file

@ -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;
}

View file

@ -0,0 +1,18 @@
#ifndef DREAMCAST_CONTROLLER_HH
#define DREAMCAST_CONTROLLER_HH
#include <kos.h>
#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

View file

@ -0,0 +1,48 @@
#include "linuxController.hh"
#include <GLFW/glfw3.h>
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;
}
}

View file

@ -0,0 +1,17 @@
#ifndef LINUX_CONTROLLER_HH
#define LINUX_CONTROLLER_HH
#include "controller.hh"
#include <GLFW/glfw3.h>
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

View file

@ -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)

View file

@ -0,0 +1,24 @@
#ifdef _arch_dreamcast
#include "dreamcastEngine.hh"
#include <stdexcept>
#include <GL/glkos.h>
#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

View file

@ -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

View file

@ -2,12 +2,34 @@
#include "engine.hh" #include "engine.hh"
#ifdef _arch_dreamcast
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glkos.h> #include "dreamcastEngine.hh"
#else
#include "linuxEngine.hh"
#endif
#include <cstdio> #include <cstdio>
#include <functional> #include <functional>
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() { void Engine::initScreen() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glViewport(0, 0, 640, 480); glViewport(0, 0, 640, 480);
@ -25,12 +47,6 @@ void Engine::printSystemInformation() {
printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS)); printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
} }
void Engine::initializeEngine() {
glKosInit();
initScreen();
printSystemInformation();
}
template <typename T> template <typename T>
void Engine::deltaTimeLoop(T&& callback, struct timeval& beginningOfFrame, void Engine::deltaTimeLoop(T&& callback, struct timeval& beginningOfFrame,
struct timeval& endOfFrame) { struct timeval& endOfFrame) {
@ -52,16 +68,15 @@ void Engine::initializeGameLoop() {
} }
} }
void Engine::pressButton(cont_state_t* controller_state, int button, void Engine::pressButton(Controller::Button button, std::function<void()> callback) {
std::function<void()> callback) { if (controller->IsButtonPressed(button)) {
if (controller_state->buttons & button) {
if (!(buttonsPressed & button)) { if (!(buttonsPressed & button)) {
buttonsPressed |= button; buttonsPressed |= button;
callback(); callback();
} }
} else if ((buttonsPressed & button) && } else if ((buttonsPressed & button) &&
~(controller_state->buttons & button)) { !controller->IsButtonPressed(button)) {
buttonsPressed &= ~button; buttonsPressed &= ~button;
} }
} }
@ -71,3 +86,5 @@ void Engine::glVertex3fNormalized(float x, float y, float z) {
glVertex3f(x * xSize, y * ySize, z); glVertex3f(x * xSize, y * ySize, z);
} }
Engine::Vector3 Engine::Vector3::zero() { return {0, 0, 0}; }

View file

@ -1,11 +1,13 @@
#ifndef ENGINE_HH #ifndef ENGINE_HH
#define ENGINE_HH #define ENGINE_HH
#include <kos.h>
#include <sys/time.h> #include <sys/time.h>
#include <functional> #include <functional>
#include "controller/controller.hh"
#include "nativeEngine.hh"
class Engine { class Engine {
protected: protected:
static constexpr float microSecond = 0.000001f; static constexpr float microSecond = 0.000001f;
@ -20,17 +22,26 @@ class Engine {
virtual void initScreen(); virtual void initScreen();
void printSystemInformation(); void printSystemInformation();
virtual void gameLoop(){}; virtual void gameLoop(){};
void pressButton(cont_state_t* controller_state, int button, void pressButton(Controller::Button button, std::function<void()> callback);
std::function<void()> callback);
void glVertex3fNormalized(float x, float y, float z); void glVertex3fNormalized(float x, float y, float z);
void SwapBuffers();
Controller* controller = nullptr;
private: private:
template <typename T> template <typename T>
void deltaTimeLoop(T&& callback, struct timeval& beginningOfFrame, void deltaTimeLoop(T&& callback, struct timeval& beginningOfFrame,
struct timeval& endOfFrame); struct timeval& endOfFrame);
NativeEngine* engine = nullptr;
public: public:
void initializeController();
void initializeEngine(); void initializeEngine();
void initializeGameLoop(); void initializeGameLoop();
struct Vector3 {
static Vector3 zero();
float x;
float y;
float z;
};
}; };
#endif #endif

44
src/engine/linuxEngine.cc Normal file
View file

@ -0,0 +1,44 @@
#ifdef __linux__
#include "linuxEngine.hh"
#include <iostream>
#include <stdexcept>
#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

13
src/engine/linuxEngine.hh Normal file
View file

@ -0,0 +1,13 @@
#ifndef LINUX_ENGINE_HH
#define LINUX_ENGINE_HH
#include "nativeEngine.hh"
#include <epoxy/gl.h>
#include <GLFW/glfw3.h>
class LinuxEngine : public NativeEngine {
void initializeController() override;
void initializeEngine() override;
void SwapBuffers() override;
GLFWwindow* window = nullptr;
};
#endif

14
src/engine/meson.build Normal file
View file

@ -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)

View file

View file

@ -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

View file

@ -1,10 +1,14 @@
#ifdef _arch_dreamcast
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glkos.h> #include <GL/glkos.h>
#include <kos.h>
#else
#include <GLFW/glfw3.h>
#endif
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
#include "engine.hh" #include "engine/engine.hh"
class Glcc : public Engine { class Glcc : public Engine {
void process_input(); void process_input();
@ -39,43 +43,31 @@ void Glcc::displayStuff() {
glPopMatrix(); glPopMatrix();
// clang-format on // clang-format on
#ifdef _arch_dreamcast
if (thirtyfps) { if (thirtyfps) {
vid_waitvbl(); vid_waitvbl();
vid_waitvbl(); vid_waitvbl();
} }
#endif
glKosSwapBuffers(); SwapBuffers();
} }
void Glcc::process_input() { void Glcc::process_input() {
maple_device_t* controller; pressButton(Controller::Button::DPAD_LEFT, [&]() { speed -= 1.0f; });
cont_state_t* controller_state; pressButton(Controller::Button::DPAD_RIGHT, [&]() { speed += 1.0f; });
pressButton(Controller::Button::A, [&]() { thirtyfps = !thirtyfps; });
controller = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
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); 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() { int main() {
Glcc* engine = new Glcc; Glcc* engine = new Glcc;
engine->initializeEngine(); engine->initializeEngine();
engine->initializeController();
engine->initializeGameLoop(); engine->initializeGameLoop();
} }

View file

@ -1,13 +1,16 @@
#ifdef _arch_dreamcast
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glkos.h> #else
#include "engine.hh" #include <GLFW/glfw3.h>
#endif
#include "engine/engine.hh"
class Hello : public Engine { class Hello : public Engine {
void triangle(); void triangle();
void gameLoop() override { void gameLoop() override {
triangle(); triangle();
glKosSwapBuffers(); SwapBuffers();
} }
}; };

54
src/meson.build Normal file
View file

@ -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)