Convert the Cube program to use entities.

This commit is contained in:
Fries 2024-03-31 12:01:57 -07:00
parent c94fd602e8
commit ecdeaf0b94
11 changed files with 225 additions and 190 deletions

View file

@ -1,184 +1,4 @@
#ifdef _arch_dreamcast #include "cube/Cube.hh"
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glkos.h>
#include <GL/glu.h>
#include <stb_image/stb_image.h>
#define SANIC_LOCATION "/rd/sanic.png"
#define CUBE_LOCATION "/rd/cube.obj"
#else
#define STB_IMAGE_IMPLEMENTATION
#include <GL/glu.h>
#include <GLFW/glfw3.h>
#include <stb/stb_image.h>
#define SANIC_LOCATION "./sanic.png"
#define CUBE_LOCATION "./cube.obj"
#endif
#include <tiny_obj_loader.h>
#include <cstdio>
#include <stdexcept>
#include <vector>
#include "engine/engine.hh"
class Cube : public Engine {
unsigned int texture;
tinyobj::ObjReader reader;
bool parseObj(std::string objFile, tinyobj::ObjReader& reader,
char* message);
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;
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++) {
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];
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
// 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];
Vector3 normal = {nx, ny, nz};
normals.push_back(normal);
// glNormal3f(nx, ny, nz);
// drawCalls += 1;
} else {
normals.push_back(Vector3::zero);
}
// 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];
Vector3 textureCoord = {tx, ty, 0};
textureCoords.push_back(textureCoord);
// glTexCoord2f(tx, ty);
// drawCalls += 1;
} else {
textureCoords.push_back(Vector3::zero);
}
}
index_offset += fv;
// 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;
// glDrawArrays(GL_QUADS, 0, susSize);
}
bool Cube::parseObj(std::string objFile, tinyobj::ObjReader& reader,
char* message) {
tinyobj::ObjReaderConfig readerConfig;
readerConfig.mtl_search_path = "./";
if (!reader.ParseFromFile(objFile, readerConfig)) {
if (!reader.Error().empty()) {
sprintf(message, "TinyOBJReader: %s", 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();
SwapBuffers();
}
void Cube::initScreen() {
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(SANIC_LOCATION, &width, &height, &nr_channels, 0);
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");
}
stbi_image_free(data);
char* message = new char;
if (!parseObj(CUBE_LOCATION, reader, message))
throw std::runtime_error(message);
}
int main() { int main() {
Cube engine; Cube engine;

60
src/cube/Cube.cc Normal file
View file

@ -0,0 +1,60 @@
#include "Cube.hh"
#include "CubeEntity.hh"
#include <GL/glu.h>
#ifdef _arch_dreamcast
#define SANIC_LOCATION "/rd/sanic.png"
#define CUBE_LOCATION "/rd/cube.obj"
#include <stb_image/stb_image.h>
#include <GL/glext.h>
#else
#define STB_IMAGE_IMPLEMENTATION
#define SANIC_LOCATION "./sanic.png"
#define CUBE_LOCATION "./cube.obj"
#include <stb/stb_image.h>
#endif
Cube::Cube() {
entity = new CubeEntity(this, nullptr);
}
void Cube::initScreen() {
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(SANIC_LOCATION, &width, &height, &nr_channels, 0);
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");
}
stbi_image_free(data);
}
void Cube::gameLoop() {
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);
Entity::drawEntity(entity);
SwapBuffers();
}

13
src/cube/Cube.hh Normal file
View file

@ -0,0 +1,13 @@
#ifndef CUBE_HH
#define CUBE_HH
#include <engine/engine.hh>
#include "CubeEntity.hh"
class Cube : public Engine {
public:
CubeEntity* entity;
void gameLoop() override;
void initScreen() override;
Cube();
unsigned int texture;
};
#endif

119
src/cube/CubeEntity.cc Normal file
View file

@ -0,0 +1,119 @@
#include "CubeEntity.hh"
#include <engine/entity.hh>
#include <stdexcept>
#ifdef _arch_dreamcast
#define SANIC_LOCATION "/rd/sanic.png"
#define CUBE_LOCATION "/rd/cube.obj"
#else
#define STB_IMAGE_IMPLEMENTATION
#define SANIC_LOCATION "./sanic.png"
#define CUBE_LOCATION "./cube.obj"
#endif
CubeEntity::CubeEntity(Engine* engine, Entity* parent) : Entity(engine, parent) {
char* message = new char;
if (!parseObj(CUBE_LOCATION, reader, message))
throw std::runtime_error(message);
}
void CubeEntity::draw() {
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;
std::vector<Engine::Vector3> vertexes{};
std::vector<Engine::Vector3> normals{};
std::vector<Engine::Vector3> 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);
// 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];
Engine::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
// 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];
Engine::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
// 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];
Engine::Vector3 textureCoord = {tx, ty, 0};
textureCoords.push_back(textureCoord);
// glTexCoord2f(tx, ty);
// drawCalls += 1;
} else {
textureCoords.push_back(Engine::Vector3::zero);
}
}
index_offset += fv;
// 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;
// glDrawArrays(GL_QUADS, 0, susSize);
}
bool CubeEntity::parseObj(std::string objFile, tinyobj::ObjReader& reader,
char* message) {
tinyobj::ObjReaderConfig readerConfig;
readerConfig.mtl_search_path = "./";
if (!reader.ParseFromFile(objFile, readerConfig)) {
if (!reader.Error().empty()) {
sprintf(message, "TinyOBJReader: %s", reader.Error().c_str());
return false;
}
}
return true;
}

16
src/cube/CubeEntity.hh Normal file
View file

@ -0,0 +1,16 @@
#ifndef CUBE_ENTITY_HH
#define CUBE_ENTITY_HH
#include <engine/entity.hh>
#include <tiny_obj_loader.h>
class CubeEntity : public Entity {
void draw() override;
tinyobj::ObjReader reader;
bool parseObj(std::string objFile, tinyobj::ObjReader& reader,
char* message);
float angle;
public:
CubeEntity(Engine* engine, Entity* parent);
};
#endif

7
src/cube/meson.build Normal file
View file

@ -0,0 +1,7 @@
cubed_sources = [
'Cube.cc',
'CubeEntity.cc'
]
cube = static_library('cube', cubed_sources, dependencies: deps, include_directories: incdirs)
cube_dep = declare_dependency(link_with: [cube], include_directories: incdirs)

View file

@ -14,7 +14,7 @@ bool DesktopController::InitializeController() {
glfwUpdateGamepadMappings(mappings.str().c_str()); glfwUpdateGamepadMappings(mappings.str().c_str());
} }
if (glfwJoystickIsGamepad(GLFW_JOYSTICK_1)) { if (glfwJoystickIsGamepad(GLFW_JOYSTICK_1)) {
glfwGetGamepadState(GLFW_JOYSTICK_1, &controllerState); PollController();
return true; return true;
} }
return false; return false;

View file

@ -5,8 +5,7 @@ DreamcastController::DreamcastController() {
} }
bool DreamcastController::InitializeController() { bool DreamcastController::InitializeController() {
maple_device_t* cont = nullptr; maple_device_t* cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if (cont->valid) { if (cont->valid) {
this->controller = cont; this->controller = cont;
this->controller_state = (cont_state_t*)maple_dev_status(controller); this->controller_state = (cont_state_t*)maple_dev_status(controller);

View file

@ -88,9 +88,9 @@ void Engine::pressButton(Controller::Button button,
} }
} }
const Engine::Vector3 Engine::Vector3::zero = {0, 0, 0}; constexpr Engine::Vector3 Engine::Vector3::zero = {0, 0, 0};
Engine::Vector3 Engine::Vector3::operator/(float amount) { Engine::Vector3 Engine::Vector3::operator/(float amount) const {
return {this->x / amount, this->y / amount, this->z / amount}; return {this->x / amount, this->y / amount, this->z / amount};
} }
@ -101,6 +101,6 @@ void Engine::Vector3::operator/=(float amount) {
float Engine::getDeltaTime() const { return deltaTime; } float Engine::getDeltaTime() const { return deltaTime; }
Engine::Vector3 Engine::Vector3::operator+(Engine::Vector3 vector) { Engine::Vector3 Engine::Vector3::operator+(Engine::Vector3 vector) const {
return {this->x + vector.x, this->y + vector.y, this->z + vector.z}; return {this->x + vector.x, this->y + vector.y, this->z + vector.z};
} }

View file

@ -50,9 +50,9 @@ class Engine {
virtual ~Engine(); virtual ~Engine();
Controller* controller = nullptr; Controller* controller = nullptr;
struct Vector3 { struct Vector3 {
Vector3 operator/(float amount); Vector3 operator/(float amount) const;
void operator/=(float amount); void operator/=(float amount);
Vector3 operator+(Vector3 vector); Vector3 operator+(Vector3 vector) const;
float x; float x;
float y; float y;
float z; float z;

View file

@ -62,11 +62,12 @@ incdirs += [srcinc]
subdir('hello') subdir('hello')
subdir('gl') subdir('gl')
subdir('cube')
subdir('flappyBird') subdir('flappyBird')
executable('hello.elf', ['hello.cc'], dependencies: [deps] + [hello_dep], include_directories: incdirs) executable('hello.elf', ['hello.cc'], dependencies: [deps] + [hello_dep], include_directories: incdirs)
executable('gl.elf', ['gl.cc'], dependencies: [deps] + [glcc_dep], include_directories: incdirs) executable('gl.elf', ['gl.cc'], dependencies: [deps] + [glcc_dep], include_directories: incdirs)
if host_machine.system() != 'windows' if host_machine.system() != 'windows'
executable('cube.elf', cube_sources, dependencies: deps, include_directories: incdirs) executable('cube.elf', cube_sources, dependencies: [deps] + [cube_dep], include_directories: incdirs)
endif endif
executable('flappyBird.elf', ['flappyBird.cc'], dependencies: [deps] + [flappy_dep], include_directories: incdirs) executable('flappyBird.elf', ['flappyBird.cc'], dependencies: [deps] + [flappy_dep], include_directories: incdirs)