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.
This commit is contained in:
Fries 2024-03-13 21:49:35 -07:00
parent 3822973d6a
commit 23dd7ace18
11 changed files with 334 additions and 37 deletions

116
.vscode/launch.json vendored
View file

@ -1,33 +1,91 @@
{ {
"configurations": [ "configurations": [
{ {
"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/gl.elf",
"args": [], "args": [],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"environment": [], "environment": [],
"externalConsole": false, "externalConsole": false,
"MIMode": "gdb", "MIMode": "gdb",
"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/gl.elf",
"setupCommands": [ "setupCommands": [
{ {
"description": "Enable pretty-printing for gdb", "description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing", "text": "-enable-pretty-printing",
"ignoreFailures": true "ignoreFailures": true
}, },
{ {
"description": "Set SuperH architechture", "description": "Set SuperH architechture",
"text": "set architecture sh4" "text": "set architecture sh4"
} }
], ],
"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();
}

View file

@ -1,3 +1,5 @@
#define TINYOBJLOADER_IMPLEMENTATION
#include "engine.hh" #include "engine.hh"
#include <GL/gl.h> #include <GL/gl.h>
@ -65,9 +67,7 @@ void Engine::pressButton(cont_state_t* controller_state, int button,
} }
void Engine::glVertex3fNormalized(float x, float y, float z) { void Engine::glVertex3fNormalized(float x, float y, float z) {
int xSize, ySize; constexpr int xSize = 640, ySize = 480;
xSize = 640;
ySize = 480;
glVertex3f(x * xSize, y * ySize, z); glVertex3f(x * xSize, y * ySize, z);
} }

View file

@ -8,7 +8,7 @@
class Engine { class Engine {
protected: protected:
const float microSecond = 0.000001f; static constexpr float microSecond = 0.000001f;
float angle = 0; float angle = 0;
float deltaTime = 1.0 / 60.0; float deltaTime = 1.0 / 60.0;
@ -17,7 +17,7 @@ class Engine {
bool thirtyfps; bool thirtyfps;
unsigned int buttonsPressed; unsigned int buttonsPressed;
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(cont_state_t* controller_state, int button,

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.cc', 'engine.cc'], dependencies: deps, include_directories: incdirs) engine = static_library('engine', ['engine.cc'], dependencies: deps, include_directories: incdirs)
executable('gl.elf', ['gl.cc', '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)

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