Driver program using custom 3D game engine [closed]

I am working on a custom game engine and have been fleshing out the various submodules (meshes, physics, shading, etc.)

Here is a sandbox program that exercises the newly finished camera system. After much testing, the camera system will be integrated into the rest of the engine.

This program loads three wireframe worlds and places the camera in them where the user may take control and move freely, viewing from the camera's perspective.

The code relies on other parts of the engine which I am not releasing yet. Therefore this code, while it does compile on my machine, is technically incomplete.

Camera3D.h

#ifndef Camera3D_H
#define Camera3D_H

#include <Evector.h>
#include <Vmath.h>
#include <SpatialObject.h>

class Camera3D: public gen::SpatialObject {
private:
// A point in 3D space where the camera is currently focused on
gen::Vector look;

// A vector pointing in the "above" direction from the camera's
// perspective
gen::Vector up;

inline void setLook(gen::Vector aim)
{
look = pos + aim;
}

public:
double maxSpeed;
double lookMax;

// Set the camera in a new position.
//
// Input: Vector pointing to the new position
//
void set(gen::Vector newPosition);

// Translate the camera by some amount.
//
// Input: Triplet forming the displacement to translate by
//
void translate(double dx, double dy, double dz);

// Move the camera along the "forward" direction by some amount,
// either positively or negatively.
//
// Input: One-dimensional displacement to move along the "forward"
// direction by
//
void walk(double velocity);

// Set the azimuthal angle.
//
void setAzi(double newAzimuth);

// Set the zenith angle.
//
void setZen(double newZenith);

// Rotate about the Y axis. On the X-Z plane, positive rotations
// are counterclockwise.
//
// Input: The angular displacement to change the azimuth by
//
// @todo This method seems to be slow. Optimize later.
//
void turn(double deltaAngle);

//
//
void aim(double x, double y, double z);

// Rotate about the "side" axis. The "side" axis points "east".
//
void pivot(double deltaAngle);

// Roll the camera by some amount.
//
void roll(double deltaAngle);

// Set the camera to a new elevation.
//
void hang(double newElev);

// Raise the camera in elevation by some amount.
//
void raise(double deltaElev);

inline gen::Vector getPosition() const {return pos;}

inline gen::Vector getLook() const {return look;}

inline gen::Vector getUp() const {return up;}

inline gen::Vector getAim() const
{
return gen::displacement(getPosition(), getLook());
}

Camera3D(const double lookScale):
gen::SpatialObject(),
lookMax(lookScale)
{
//
// Forward  = +Z
// Up       = +Y
//
look = gen::Vector(0, 0, lookMax);
up = gen::Vector(0, 1, 0);

maxSpeed = 0;
}
};

#endif



Camera3D.cpp

#include <Camera3D.h>
#include <Evector.h>
#include <Vmath.h>
#include <Globals.h>

extern const double PI;

// Set the camera in a new position.
//
// Input: Vector pointing to the new position
//
void Camera3D::set(gen::Vector newPosition)
{
// We're not changing the direction the camera is looking,
// just the position. Restore the aim after the move.
gen::Vector oldAim = getAim();
pos = newPosition;
setLook(oldAim);
}

// Translate the camera by some amount.
//
// Input: Triplet forming the displacement to translate by
//
void Camera3D::translate(double dx, double dy, double dz)
{
set(pos + gen::Vector(dx, dy, dz));
}

// Move the camera along the "forward" direction by some amount,
// either positively or negatively.
//
// Input: One-dimensional displacement to move along the "forward"
// direction by
//
void Camera3D::walk(double velocity)
{
// Here, we're just stepping some distance either forward or back.
gen::Vector step = getAim();
gen::resize(step, velocity);
set(pos + step);
}

// Set the azimuthal angle.
//
void Camera3D::setAzi(double newAzimuth)
{

}

// Set the zenith angle.
//
void Camera3D::setZen(double newZenith)
{

}

// Rotate about the Y axis. On the X-Z plane, positive rotations
// are counterclockwise.
//
// Input: The angular displacement to change the azimuth by
//
// @todo This method seems to be slow. Optimize later.
//
void Camera3D::turn(double deltaAngle)
{
// Camera position does not change when turning, only the "forward"
// vector.
gen::Vector newAim = getAim();
gen::rotate(newAim, deltaAngle, 2);
setLook(newAim);
}

//
//
void Camera3D::aim(double x, double y, double z)
{

}

// Rotate about the "side" axis. The "side" axis points "east".
//
void Camera3D::pivot(double deltaAngle)
{
// Get the "side" vector which is perpendicular to the "forward" and "up"
// vectors.
gen::Vector currentAim = getAim();
double currentPhi = getPhi(currentAim);

// If the caller is trying to look further than "down", do nothing.
if((currentPhi + deltaAngle) > PI) {
gen::Vector straightDown(gen::Vector(0, -lookMax, 0));
setLook(straightDown);
}

// If the caller is trying to look past zero radians, do nothing.
else if((currentPhi + deltaAngle) < 0) {
gen::Vector straightUp(gen::Vector(0, lookMax, 0));
setLook(straightUp);
}
else {
gen::Vector axis = gen::cross(up, currentAim);
gen::Vector newAim = currentAim;
gen::rotateArb(newAim, deltaAngle, axis);
setLook(newAim);
}
}

// Roll the camera by some amount.
//
void Camera3D::roll(double deltaAngle)
{
gen::rotateArb(up, deltaAngle, getAim());
}

// Set the camera to a new elevation.
//
void Camera3D::hang(double newElev)
{
gen::Vector newPosition = pos;
newPosition.y = newElev;
set(newPosition);
}

// Raise the camera in elevation by some amount.
//
void Camera3D::raise(double deltaElev)
{
translate(0, deltaElev, 0);
}



Cam3D.h

/*
File: Cam3D.h
Date: Sunday, September 29, 2019
*/

#ifndef Cam3D_H
#define Cam3D_H

#include <AllegApp.h>
#include <Camera3D.h>
#include <InputHandler.h>
#include <Mesh3D.h>
#include <allegro5/allegro.h>

class Cam3D: public lat::AllegApp {
private:
meshx::Mesh3D plane1;
meshx::Mesh3D plane2;
meshx::Mesh3D plane3;
Camera3D camera;

InputHandler inputHandler;
ALLEGRO_TRANSFORM transform;
ALLEGRO_TRANSFORM camTrans;

ALLEGRO_EVENT event;

int doUpdate();
int draw();

protected:
virtual int update() override;

public:
void init() override;
Cam3D(int width, int height);
~Cam3D();
};

#endif



Cam3D.cpp

/*
File: Cam3D.cpp
Date: Sunday, September 29, 2019
*/

#include <Cam3D.h>
#include <Camera3D.h>
#include <AllegApp.h>
#include <Mesh3D.h>
#include <HardRenderer.h>
#include <MeshOps.h>
#include <ColorsA5.h>
#include <InputHandler.h>
#include <Globals.h>

#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_color.h>

#include <string>

const double PI = 3.141592654;
const double RADIANS_PER_DEGREE = PI / 180.0;

const double FOV = (90 * RADIANS_PER_DEGREE / 2.0);

// Window aspect ratio
double ASPECT_RATIO;

// Camera zoom factor
const double ZOOM = 1.0;

// Frame rate limit (in quarters of 60fps)
const int FRAME_RATE_LIMIT = 4;

const double TERRAIN_SCALE = 1000000;

const double DEPTH = 5000000;
const double CAMERA_LOOK_DEPTH = 1000000;

// Starting camera elevation percentage
const double INITIAL_ELEV_FACTOR = 0.1;

//
const double SPACE_FABRIC_CONSTANT = 1.0 / 128;

inline double degToRad(double deg) {return PI * deg / 180.0;}

Cam3D::Cam3D(int width, int height):
AllegApp(width, height),
camera(CAMERA_LOOK_DEPTH)
{
}

Cam3D::~Cam3D()
{
}

void Cam3D::init()
{
AllegApp::init();

ASPECT_RATIO = ((double)getWindowHeight()) / getWindowWidth();

// setDisplayFullscreen();
setWindowTitle("Cam3D");
setFrameRateFrac(FRAME_RATE_LIMIT);
flLockFrameRate = true;
flAllowQuitOnEscape = true;

// Monitor the movement keys.

inputHandler.monitorKey(ALLEGRO_KEY_LEFT);
inputHandler.monitorKey(ALLEGRO_KEY_RIGHT);
inputHandler.monitorKey(ALLEGRO_KEY_DOWN);
inputHandler.monitorKey(ALLEGRO_KEY_UP);

inputHandler.monitorKey(ALLEGRO_KEY_A);
inputHandler.monitorKey(ALLEGRO_KEY_D);
inputHandler.monitorKey(ALLEGRO_KEY_S);
inputHandler.monitorKey(ALLEGRO_KEY_W);

inputHandler.monitorKey(ALLEGRO_KEY_SPACE);

meshx::scaleMesh(plane1, TERRAIN_SCALE);

meshx::scaleMesh(plane2, TERRAIN_SCALE / 10.0);
plane2.offset.y = 100000;

meshx::scaleMesh(plane3, TERRAIN_SCALE / 100.0);
plane3.offset.y = 200000;

// Set up the camera.
camera.hang(TERRAIN_SCALE * INITIAL_ELEV_FACTOR);
}

int Cam3D::update()
{
int result = doUpdate();
draw();
return result;
}

int Cam3D::doUpdate()
{
double deltaTheta = 0;
double deltaPhi = 0;
int result = 0;

camera.maxSpeed = SPACE_FABRIC_CONSTANT * TERRAIN_SCALE * 0.01;

inputHandler.getKeyboardInput();

// ------------------------[ROTATION]------------------------

// Counterclockwise on the X-Z plane

camera.turn(deltaTheta);
}

// Clockwise on the X-Z plane

camera.turn(deltaTheta);
}

// Look down

camera.pivot(deltaPhi);
}

// Look up

camera.pivot(deltaPhi);
}

// ------------------------[TRANSLATION]------------------------

// Speed up

if(inputHandler.getKeyFlagByCode(ALLEGRO_KEY_SPACE)) {
camera.maxSpeed = SPACE_FABRIC_CONSTANT * TERRAIN_SCALE * 0.1;
}

// Forward

if(inputHandler.getKeyFlagByCode(ALLEGRO_KEY_W)) {
camera.walk(+camera.maxSpeed);
}

// Backward

else if(inputHandler.getKeyFlagByCode(ALLEGRO_KEY_S)) {
camera.walk(-camera.maxSpeed);
}

// Translate left

if(inputHandler.getKeyFlagByCode(ALLEGRO_KEY_LEFT)) {
camera.translate(-camera.maxSpeed, 0, 0);
}

// Translate right

if(inputHandler.getKeyFlagByCode(ALLEGRO_KEY_RIGHT)) {
camera.translate(+camera.maxSpeed, 0, 0);
}

// Translate down

if(inputHandler.getKeyFlagByCode(ALLEGRO_KEY_DOWN)) {
camera.translate(0, 0, -camera.maxSpeed);
}

// Translate up

if(inputHandler.getKeyFlagByCode(ALLEGRO_KEY_UP)) {
camera.translate(0, 0, +camera.maxSpeed);
}

return result;
}

int Cam3D::draw()
{
// Clear the screen.
al_clear_to_color(BLACK);

// Used to restore the previous transform
ALLEGRO_TRANSFORM old = *al_get_current_projection_transform();

al_identity_transform(&transform);

// Set up the perspective projection matrix.
// Left, Top, Near, Right, Bottom, Far
al_perspective_transform(&transform,
(-1.0 / ZOOM), (-ASPECT_RATIO / ZOOM),
(+1.0 / FOV),
(+1.0 / ZOOM), (+ASPECT_RATIO / ZOOM),
DEPTH);

// Flip the X and Y axes.
al_scale_transform_3d(&transform, -1, -1, +1);

al_use_projection_transform(&transform);

// Set up a matrix to transform from world coordinates to camera
// coordinates.
al_build_camera_transform(&camTrans,
camera.getPosition().x,
camera.getPosition().y,
camera.getPosition().z,
camera.getLook().x,
camera.getLook().y,
camera.getLook().z,
camera.getUp().x,
camera.getUp().y,
camera.getUp().z);

al_use_transform(&camTrans);

al_set_render_state(ALLEGRO_DEPTH_TEST, 1);
al_clear_depth_buffer(1);

// Draw the planes.
drawMeshWire3D(plane1, GREEN);
drawMeshWire3D(plane2, CYAN);
drawMeshWire3D(plane3, MAGENTA);

// Reset the projection transforms.
al_identity_transform(&camTrans);
al_use_transform(&camTrans);

al_use_projection_transform(&old);

al_set_render_state(ALLEGRO_DEPTH_TEST, 0);

al_draw_textf(getSystemFont(), ICEBERG, 0,  0, 0, "%f", getFrameRate());

al_draw_textf(getSystemFont(), ICEBERG, 0, 10, 0, "%f",
camera.getPosition().y);

return 0;
}



main.cpp

/*
File: main.cpp
Date: Sunday, September 29, 2019
*/

#include <AllegApp.h>
#include <Cam3D.h>

int main(int argc, char** argv)
{
lat::AllegApp* x = new Cam3D(16 * 75, 9 * 75);
x->init();
x->run();
delete x;
x = 0;
return 0;
}



Globals.h

#ifndef Globals_H
#define Globals_H

extern const double PI;

#endif


• Welcome to Code Review! Oct 11, 2019 at 10:29
• While we appreciate your need to keep some code private, there are classes used here that are not defined. This makes the question off-topic. Nov 10, 2019 at 15:37
• @pacmaninbw Thank you for the advice. Yes, there are many classes used here, however, if I included those class definitions, then the code wouldn't be private anymore. Nov 11, 2019 at 18:28
• You're correct, it wouldn't be private anymore. The code you have posted has now become public domain. Suggestion because I won't be answering this question, in Camera3D.cpp you already include the Globals header, you don't need extern const double PI; in the code again. Nov 11, 2019 at 18:32