Turbo-Hybrid Game Engine

thumbnail
  • C++
  • SDL2
  • bgfx

Details

The Turbo Hybrid Game Engine is a custom 3D game framework built using a structure-of-arrays ECS system, SDL2, JSON serialization, and bgfx rendering. It was developed over 15 weeks as part of a Champlain College course on game engine architecture.

Overview

This game engine project focused on building a custom engine from scratch, including core systems like game object management, component handling, and rendering pipelines. We supported cross-platform builds using Emscripten and implemented 3D rendering with bgfx.

I collaborated with Steven Annunziato to implement a 3D rendering system. We prioritized shader flexibility and chose bgfx for its abstraction of backend graphics APIs and strong documentation.

Technical Highlights

  • Created windowing and input systems using SDL2
  • Designed a structure-of-arrays ECS model for game objects and components
  • Used JSON for data-driven configuration of game objects
  • Integrated bgfx for efficient GPU rendering and shader pipeline support
  • Supported build targets for both Windows and Web (via Emscripten)

Rendering System

Implemented a cube rendering component with MVP matrix support. Each object can define its own shader, and the engine is built to be extensible for future rendering features.

Sample GameObject JSON

Components: TRAN (Transform), CUBE (Cube Renderer), PLRC (Player Controller)

{ "GameObjects" : [ { "TRAN" : [0, 0,5 ], "CUBE" : { "Color": [1, 1, 1, 1] }, "PLRC" : { "Speed" : [0.1] } }, { "TRAN" : [4, 0, 0], "CUBE" : { "Color": [1, 0, 1, 1] } } ] }

Main Render Function

/* Set up view projection matrix */ // Look at the first gameObject const glm::vec3 at = gameObjects[0]-> GetTransform()-> GetLocation(). Vec3(); // location of the eye/camera const glm::vec3 eye = { 0.0f, 0.0f, -5.0f }; // reference for up vector const glm::vec3 up = { 0.0f, 1.0f, 0.0f }; // view matrix is created glm::mat4x4 view = glm::lookAt(eye, at, up); // create projection matrix using a perspective projection glm::mat4x4 proj = glm::perspective (80.0f, //FOV float(WIDTH) / float(HEIGHT), //Aspect Ratio 0.1f, //Near Clipping plane 100.0f); //Far Clipping plane // set view and projection matrix bgfx::setViewTransform(0, &view, &proj); /* Render Cube components */ TurboHybrid::ComponentSystem::GetComponentSystem()-> renderCubes(engine->frame); /* Render next frame */ bgfx::frame();

Cube Renderer Loop

void TurboHybrid::CubeRenderer::render(const float& deltatime) { assert(m_vbh.idx != 0 || m_ibh.idx != 0 || m_program.idx != 0); //set up render state for object uint64_t state = 0 | (BGFX_STATE_WRITE_R) | (BGFX_STATE_WRITE_G) | (BGFX_STATE_WRITE_B) | (BGFX_STATE_WRITE_A) | BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_CULL_CW | BGFX_STATE_MSAA | UINT64_C(0) ; // init with no translation glm::mat4x4 model = glm::mat4(1.0f); // Set Position to the transform component position Vector3 pos3 = gameObject->GetTransform()->GetLocation(); glm::vec3 pos = glm::vec3(pos3.x, pos3.y, pos3.z); model = glm::translate(model, pos); // Set rotation float rotationDirection = 100.0f; if (gameObject->GetPlayerController() != nullptr) { rotationDirection *= -1; // If player controlled invert rotation } model = glm::rotate( model, //Matrix deltatime / rotationDirection, //Rotation amount glm::vec3(1.0f, 1.0f, 0.0f)); //axis of rotation bgfx::setTransform(&model); // Set Color uniform to pass information to the shader float color[4] = { m_color.r, m_color.g, m_color.b, m_color.a }; bgfx::setUniform(m_uniform, color); // Set Vertex and Index Buffers bgfx::setVertexBuffer(0, m_vbh); bgfx::setIndexBuffer(m_ibh); // Set render states. bgfx::setState(state); //Each object has unique state //Submit program for rendering bgfx::submit(0, m_program); }

Conclusion

Building this engine gave me a deeper appreciation for the systems that power 3D games. The project helped reinforce fundamentals of rendering, data design, and low-level graphics integration.