Compare commits

...

2 commits

Author SHA1 Message Date
23dd7ace18 Parse a cube .obj file to display.
Right now the implementation is extremely unoptimized and draw call heavy as I just copy and pasted that from the docs for tiny obj loader but added gl calls.
2024-03-13 21:49:35 -07:00
3822973d6a Create an abstracted engine class for the programs. 2024-03-13 12:53:37 -07:00
14 changed files with 491 additions and 159 deletions

58
.vscode/launch.json vendored
View file

@ -28,6 +28,64 @@
], ],
"avoidWindowsConsoleRedirection": false, "avoidWindowsConsoleRedirection": false,
"internalConsoleOptions": "openOnSessionStart" "internalConsoleOptions": "openOnSessionStart"
},
{
"name": "(gdb) Launch cube.elf",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/cube.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": "/usr/bin/flycast",
"debugServerArgs": "${workspaceFolder}/build/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 cube.elf",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/cube.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/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"
} }
] ]
} }

145
cube.cc Normal file
View file

@ -0,0 +1,145 @@
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glkos.h>
#include <GL/glu.h>
#include <stb_image/stb_image.h>
#include <tiny_obj_loader.h>
#include <cstdio>
#include "engine.hh"
class Cube : public Engine {
unsigned int texture;
tinyobj::ObjReader reader;
bool parseObj(std::string objFile, tinyobj::ObjReader& reader);
void cube();
void displayStuff();
void gameLoop() override { displayStuff(); }
void initScreen() override;
void model();
};
void Cube::model() {
const tinyobj::attrib_t& attrib = reader.GetAttrib();
auto& shapes = reader.GetShapes();
angle += 1.0f;
glRotatef(angle, 1.0f, 0.0f, 1.0f);
int drawCalls = 0;
for (size_t s = 0; s < shapes.size(); s++) {
// Loop over faces(polygon)
size_t index_offset = 0;
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);
// Loop over vertices in the face.
for (size_t v = 0; v < fv; v++) {
// access to vertex
tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];
tinyobj::real_t vx =
attrib.vertices[3 * size_t(idx.vertex_index) + 0];
tinyobj::real_t vy =
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;
// Check if `normal_index` is zero or positive. negative = no
// normal data
if (idx.normal_index >= 0) {
tinyobj::real_t nx =
attrib.normals[3 * size_t(idx.normal_index) + 0];
tinyobj::real_t ny =
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;
}
// Check if `texcoord_index` is zero or positive. negative = no
// texcoord data
if (idx.texcoord_index >= 0) {
tinyobj::real_t tx =
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;
}
}
index_offset += fv;
glEnd();
}
}
printf("Draw Calls: %i\n", drawCalls);
drawCalls = 0;
// glDrawArrays(GL_QUADS, 0, susSize);
}
bool Cube::parseObj(std::string objFile, tinyobj::ObjReader& reader) {
tinyobj::ObjReaderConfig readerConfig;
readerConfig.mtl_search_path = "./";
if (!reader.ParseFromFile(objFile, readerConfig)) {
if (!reader.Error().empty()) {
printf("TinyOBJReader: %s\n", reader.Error().c_str());
return false;
}
}
return true;
}
void Cube::displayStuff() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -5.0f);
glRotatef(90, 0.0f, 1.0f, 0.5f);
model();
glKosSwapBuffers();
}
void Cube::initScreen() {
glKosInit();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, 640.0f / 480.0f, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glFrontFace(GL_CW);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
int width, height, nr_channels;
unsigned char* data =
stbi_load("/rd/sanic.png", &width, &height, &nr_channels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
} else {
printf("Texture failed to load.\n");
}
stbi_image_free(data);
if (!parseObj("/rd/cube.obj", reader)) return;
}
int main() {
Cube engine;
engine.initializeEngine();
engine.initializeGameLoop();
}

73
engine.cc Normal file
View file

@ -0,0 +1,73 @@
#define TINYOBJLOADER_IMPLEMENTATION
#include "engine.hh"
#include <GL/gl.h>
#include <GL/glkos.h>
#include <cstdio>
#include <functional>
void Engine::initScreen() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glViewport(0, 0, 640, 480);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glOrtho(0, 640, 0, 480, -100, 100);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}
void Engine::printSystemInformation() {
printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR));
printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
printf("GL_VERSION: %s\n", glGetString(GL_VERSION));
printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
}
void Engine::initializeEngine() {
glKosInit();
initScreen();
printSystemInformation();
}
template <typename T>
void Engine::deltaTimeLoop(T&& callback, struct timeval& beginningOfFrame,
struct timeval& endOfFrame) {
gettimeofday(&beginningOfFrame, 0);
(this->*callback)();
gettimeofday(&endOfFrame, 0);
float time = ((float)(endOfFrame.tv_usec) * microSecond) -
((float)(beginningOfFrame.tv_usec) * microSecond);
if (time > 0.0f) {
deltaTime = time;
}
}
void Engine::initializeGameLoop() {
struct timeval beginningOfFrame, endOfFrame;
while (1) {
deltaTimeLoop(&Engine::gameLoop, beginningOfFrame, endOfFrame);
}
}
void Engine::pressButton(cont_state_t* controller_state, int button,
std::function<void()> callback) {
if (controller_state->buttons & button) {
if (!(buttonsPressed & button)) {
buttonsPressed |= button;
callback();
}
} else if ((buttonsPressed & button) &&
~(controller_state->buttons & button)) {
buttonsPressed &= ~button;
}
}
void Engine::glVertex3fNormalized(float x, float y, float z) {
constexpr int xSize = 640, ySize = 480;
glVertex3f(x * xSize, y * ySize, z);
}

36
engine.hh Normal file
View file

@ -0,0 +1,36 @@
#ifndef ENGINE_HH
#define ENGINE_HH
#include <kos.h>
#include <sys/time.h>
#include <functional>
class Engine {
protected:
static constexpr float microSecond = 0.000001f;
float angle = 0;
float deltaTime = 1.0 / 60.0;
float speed = 5.0f;
bool thirtyfps;
unsigned int buttonsPressed;
virtual void initScreen();
void printSystemInformation();
virtual void gameLoop(){};
void pressButton(cont_state_t* controller_state, int button,
std::function<void()> callback);
void glVertex3fNormalized(float x, float y, float z);
private:
template <typename T>
void deltaTimeLoop(T&& callback, struct timeval& beginningOfFrame,
struct timeval& endOfFrame);
public:
void initializeEngine();
void initializeGameLoop();
};
#endif

98
gl.cc
View file

@ -1,53 +1,22 @@
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glkos.h> #include <GL/glkos.h>
#include <kos.h>
#include <sys/time.h>
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
const float microSecond = 0.000001f; #include "engine.hh"
float angle = 0; class Glcc : public Engine {
float deltaTime = 1.0 / 60.0; void process_input();
float speed = 5.0f; void displayStuff();
bool thirtyfps; void gameLoop() override {
uint32 buttonsPressed; process_input();
displayStuff();
template <typename T>
void pressButton(cont_state_t* controller_state, int button, T&& callback) {
if (controller_state->buttons & button) {
if (!(buttonsPressed & button)) {
buttonsPressed |= button;
callback();
} }
} else if ((buttonsPressed & button) && };
~(controller_state->buttons & button)) {
buttonsPressed &= ~button;
}
}
void initScreen() { void Glcc::displayStuff() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glViewport(0, 0, 640, 480);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glOrtho(0, 640, 0, 480, -100, 100);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}
void glVertex3fNormalized(float x, float y, float z) {
int xSize, ySize;
xSize = 640;
ySize = 480;
glVertex3f(x * xSize, y * ySize, z);
}
void displayStuff() {
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
// clang-format off // clang-format off
@ -78,7 +47,7 @@ void displayStuff() {
glKosSwapBuffers(); glKosSwapBuffers();
} }
void process_input() { void Glcc::process_input() {
maple_device_t* controller; maple_device_t* controller;
cont_state_t* controller_state; cont_state_t* controller_state;
@ -89,12 +58,15 @@ void process_input() {
if (!controller_state) { if (!controller_state) {
printf( printf(
"An error has occured while trying to read the controller.\n"); "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_LEFT, [&]() { speed -= 1.0f; });
pressButton(controller_state, CONT_DPAD_RIGHT, []() { speed += 1.0f; }); pressButton(controller_state, CONT_DPAD_RIGHT,
pressButton(controller_state, CONT_A, []() { thirtyfps = !thirtyfps; }); [&]() { 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);
@ -102,38 +74,8 @@ void process_input() {
} }
} }
void printSystemInformation() {
printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR));
printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
printf("GL_VERSION: %s\n", glGetString(GL_VERSION));
printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
}
template <typename T>
void deltaTimeLoop(T&& callback, struct timeval& beginningOfFrame,
struct timeval& endOfFrame) {
gettimeofday(&beginningOfFrame, 0);
callback();
gettimeofday(&endOfFrame, 0);
float time = ((float)(endOfFrame.tv_usec) * microSecond) -
((float)(beginningOfFrame.tv_usec) * microSecond);
if (time > 0.0f) {
deltaTime = time;
}
}
void gameLoop() {
process_input();
displayStuff();
}
int main() { int main() {
glKosInit(); Glcc* engine = new Glcc;
initScreen(); engine->initializeEngine();
printSystemInformation(); engine->initializeGameLoop();
struct timeval beginningOfFrame, endOfFrame;
while (1) {
deltaTimeLoop(gameLoop, beginningOfFrame, endOfFrame);
}
} }

50
hello.c
View file

@ -1,50 +0,0 @@
#include <kos.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glkos.h>
void triangle() {
// glClearColor(1.0f, 1.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
glEnd();
}
int main(int argc, char *argv[]) {
maple_device_t *controller;
glKosInit();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
// gluPerspective(45.0f, 640.0f/480.0f, 0.1f, 100.0f);
// glMatrixMode(GL_MODELVIEW);
// glEnable(GL_TEXTURE_2D);
// glEnable(GL_DEPTH_TEST);
// glFrontFace(GL_CW);
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0.3f, 0.4f, 0.5f, 1.0f);
while (1) {
// glLoadIdentity();
// glTranslatef(-5.0f, 0.0f, 0.0f);
// glEnable(GL_CULL_FACE);
triangle();
glKosSwapBuffers();
}
return 0;
}

34
hello.cc Normal file
View file

@ -0,0 +1,34 @@
#include <GL/gl.h>
#include <GL/glkos.h>
#include "engine.hh"
class Hello : public Engine {
void triangle();
void gameLoop() override {
triangle();
glKosSwapBuffers();
}
};
void Hello::triangle() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3fNormalized(-1.0f, -1.0f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3fNormalized(0.0f, 1.0f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3fNormalized(1.0f, -1.0f, 0.0f);
glEnd();
}
int main(int argc, char *argv[]) {
Hello* engine = new Hello;
engine->initializeEngine();
engine->initializeGameLoop();
}

View file

@ -9,12 +9,18 @@ kosportsinc = include_directories('/opt/toolchains/dc/kos-ports/include')
GL = cc.find_library('GL', required: true) GL = cc.find_library('GL', required: true)
math = cc.find_library('m', 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) # pcx = cc.find_library('pcx', required: true)
# kosutils = cc.find_library('kosutils', required: true) # kosutils = cc.find_library('kosutils', required: true)
deps = [ deps = [
GL, GL,
math math,
stb_image,
tinyobjloader_dep
] ]
incdirs = [ incdirs = [
@ -24,5 +30,11 @@ incdirs = [
kosportsinc kosportsinc
] ]
executable('hello.elf', ['hello.c'], dependencies: deps, include_directories: incdirs) 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('gl.elf', ['gl.cc'], dependencies: deps, include_directories: incdirs)
executable('cube.elf', ['cube.cc', romdsk_o], dependencies: deps, include_directories: incdirs)

2
romdisk/cube.mtl Normal file
View file

@ -0,0 +1,2 @@
# Blender 4.0.2 MTL File: 'None'
# www.blender.org

45
romdisk/cube.obj Normal file
View file

@ -0,0 +1,45 @@
# Blender 4.0.2
# www.blender.org
mtllib cube.mtl
o Cube
v -1.000000 -1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.625000 0.000000
vt 0.375000 0.250000
vt 0.375000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.500000
vt 0.625000 0.500000
vt 0.375000 0.750000
vt 0.625000 0.750000
vt 0.375000 1.000000
vt 0.125000 0.750000
vt 0.125000 0.500000
vt 0.875000 0.500000
vt 0.625000 1.000000
vt 0.875000 0.750000
s 0
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
f 6/8/4 1/9/4 5/7/4
f 7/5/5 1/10/5 3/11/5
f 4/12/6 6/8/6 8/6/6
f 2/1/1 4/4/1 3/2/1
f 4/4/2 8/6/2 7/5/2
f 8/6/3 6/8/3 5/7/3
f 6/8/4 2/13/4 1/9/4
f 7/5/5 5/7/5 1/10/5
f 4/12/6 2/14/6 6/8/6

24
romdisk/meson.build Normal file
View file

@ -0,0 +1,24 @@
romdiskcomp = find_program('/opt/toolchains/dc/kos/utils/genromfs/genromfs')
bin2o = find_program('/opt/toolchains/dc/kos/utils/bin2o/bin2o')
cc = find_program('/opt/toolchains/dc/sh-elf/bin/sh-elf-gcc')
kos_libs =['-L/opt/toolchains/dc/kos/lib/dreamcast','-L/opt/toolchains/dc/kos/addons/lib/dreamcast','-L/opt/toolchains/dc/kos/../kos-ports/lib']
romdisk_path = join_paths(meson.current_source_dir())
romdisk_img = custom_target('romdisk.img',
output : 'romdisk.img',
build_always_stale: true,
command: [
romdiskcomp, '-f', '@OUTPUT@', '-d', romdisk_path, '-v', '-x', '.svn', '-x', '.keepme', '-x', 'meson.build'
])
romdsk = custom_target('romdisk_tmp.o',
output : 'romdisk_tmp.o',
input: [romdisk_img],
command: [
bin2o, '@INPUT@', 'romdisk', '@OUTPUT@'
])
romdsk_o = custom_target('romdisk.o', output: 'romdisk.o', input: [romdsk], command: [
cc, '-o', '@OUTPUT@', '-r', '@INPUT@', '-Wl,--whole-archive', kos_libs, '-lromdiskbase'
])

BIN
romdisk/sanic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

3
subprojects/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*
!*.wrap
!.gitignore

View file

@ -0,0 +1,8 @@
[wrap-git]
url = https://github.com/tinyobjloader/tinyobjloader
revision = cab4ad7254cbf7eaaafdb73d272f99e92f166df8
depth = 1
method = cmake
[provide]
tinyobjloader = tinyobjloader_dep