gears scene working with the sheer power of iman

This commit is contained in:
Furkan Mudanyali 2023-05-28 05:36:53 +03:00
parent 5a90c96615
commit 524dcab7be
14 changed files with 802 additions and 152 deletions

View File

@ -11,7 +11,8 @@ Diagnostics:
modernize-avoid-c-arrays,
readability-magic-numbers,
readability-implicit-bool-conversion,
readability-identifier-length
readability-identifier-length,
bugprone-easily-swappable-parameters
]
Completion:

View File

@ -67,11 +67,11 @@ SET(CMAKE_CXX_FLAGS
SET(SOURCE_FILES
src/game/game.cpp
src/graphics/opengl/opengl.cpp
src/graphics/graphics.cpp
src/input/input.cpp
src/scene/example/example.cpp
src/scene/gears/gears.cpp
src/window/window.cpp
@ -114,8 +114,8 @@ ENDIF()
TARGET_LINK_LIBRARIES(HomdEngine
sdl2
glew32
opengl32
glew32
${win32_link}
)

View File

@ -4,14 +4,14 @@
*/
#include <game/game.h>
#include <scene/example/example.h>
#include <graphics/opengl/opengl.h>
#include <graphics/graphics.h>
#include <scene/gears/gears.h>
Game::Game() {
this->pWindow = new Window(this);
this->pRenderer = new OpenGL(this);
this->pRenderer = new Graphics(this);
this->pInput = new Input(this);
this->scenes.push(new Example(this));
this->scenes.push(new GearsScene(this));
}
void Game::loop() {

178
src/graphics/graphics.cpp Normal file
View File

@ -0,0 +1,178 @@
/**
* Copyright (c) 2023, Furkan Mudanyali <fmudanyali@icloud.com>
* All rights reserved
*/
#include <GLES3/gl3.h>
#include <GL/glew.h>
#include <SDL2/SDL_video.h>
#include <game/game.h>
#include <graphics/graphics.h>
#include <window/window.h>
#include <iostream>
#include <string>
void GLAPIENTRY MessageCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam) {
fprintf(stderr,
"GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type,
severity, message);
}
Graphics::Graphics(Game* game) {
this->pGame = game;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetSwapInterval(0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
this->context = SDL_GL_CreateContext(this->pGame->pWindow->window);
glewExperimental = GL_TRUE;
glewInit();
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(MessageCallback, nullptr);
}
void Graphics::storeVertexBufObj(GLuint& dest, GLsizeiptr size, int* target) {
// Store the vertices in a vertex buffer object
glGenBuffers(1, &dest);
glBindBuffer(GL_ARRAY_BUFFER, dest);
glBufferData(GL_ARRAY_BUFFER, size, target, GL_STATIC_DRAW);
}
void Graphics::multiply4x4Matrices(GLfloat* m, const GLfloat* n) {
GLfloat tmp[16];
const GLfloat* row;
const GLfloat* column;
div_t d;
for (int i = 0; i < 16; i++) {
tmp[i] = 0;
d = div(i, 4);
row = n + d.quot * 4;
column = m + d.rem;
for (int j = 0; j < 4; j++) {
tmp[i] += row[j] * column[j * 4];
}
}
memcpy(m, &tmp, sizeof tmp);
}
void Graphics::rotate4x4Matrix(GLfloat* m,
GLfloat angle,
GLfloat x,
GLfloat y,
GLfloat z) {
double sin;
double cos;
sincos(angle, &sin, &cos);
GLfloat r[16] = {(GLfloat)(x * x * (1 - cos) + cos),
(GLfloat)(y * x * (1 - cos) + z * sin),
(GLfloat)(x * z * (1 - cos) - y * sin),
0,
(GLfloat)(x * y * (1 - cos) - z * sin),
(GLfloat)(y * y * (1 - cos) + cos),
(GLfloat)(y * z * (1 - cos) + x * sin),
0,
(GLfloat)(x * z * (1 - cos) + y * sin),
(GLfloat)(y * z * (1 - cos) - x * sin),
(GLfloat)(z * z * (1 - cos) + cos),
0,
0,
0,
0,
1};
multiply4x4Matrices(m, r);
}
void Graphics::translate4x4Matrix(GLfloat* m, GLfloat x, GLfloat y, GLfloat z) {
GLfloat t[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1};
multiply4x4Matrices(m, t);
}
void Graphics::create4x4IdentityMatrix(GLfloat* m) {
GLfloat t[16] = {
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
};
memcpy(m, t, sizeof(t));
}
void Graphics::transpose4x4Matrix(GLfloat* m) {
GLfloat t[16] = {m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13],
m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]};
memcpy(m, t, sizeof(t));
}
void Graphics::invert4x4Matrix(GLfloat* m) {
GLfloat t[16];
create4x4IdentityMatrix(t);
// Extract and invert the translation part 't'. The inverse of a
// translation matrix can be calculated by negating the translation
// coordinates.
t[12] = -m[12];
t[13] = -m[13];
t[14] = -m[14];
// Invert the rotation part 'r'. The inverse of a rotation matrix is
// equal to its transpose.
m[12] = m[13] = m[14] = 0;
transpose4x4Matrix(m);
// inv(m) = inv(r) * inv(t)
multiply4x4Matrices(m, t);
}
void Graphics::calcPerspectiveProjectTransformation(GLfloat* m,
GLfloat yFOV,
GLfloat aspect,
GLfloat zNear,
GLfloat zFar) {
GLfloat tmp[16];
create4x4IdentityMatrix(tmp);
double sine;
double cosine;
double cotangent;
double deltaZ;
GLfloat radians = yFOV / 2.0F * (float)M_PI / 180.0F;
deltaZ = zFar - zNear;
sincos(radians, &sine, &cosine);
if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
return;
}
cotangent = cosine / sine;
tmp[0] = (float)cotangent / aspect;
tmp[5] = (float)cotangent;
tmp[10] = -(zFar + zNear) / (float)deltaZ;
tmp[11] = -1;
tmp[14] = -2 * zNear * zFar / (float)deltaZ;
tmp[15] = 0;
memcpy(m, tmp, sizeof(tmp));
}
void Graphics::draw() {
SDL_GL_SwapWindow(this->pGame->pWindow->window);
}

View File

@ -3,17 +3,98 @@
* All rights reserved
*/
#ifndef _HOMD_GRAPHICS
#define _HOMD_GRAPHICS
#ifndef _HOMD_GRAPHICS_GL
#define _HOMD_GRAPHICS_GL
#define GLEW_STATIC
#include <GLES3/gl3.h>
#include <GL/glew.h>
#include <SDL2/SDL_video.h>
class Game;
class Window;
class Graphics {
Game* pGame;
SDL_GLContext context = nullptr;
public:
Game* game;
Graphics() = default;
virtual ~Graphics() = default;
virtual void drawSomething() = 0;
Graphics(Game*);
~Graphics() = default;
void setGLContext();
void draw();
static void storeVertexBufObj(GLuint&, GLsizeiptr, int*);
/**
* Multiplies two 4x4 matrices
*
* The result is stored in matrix m.
*
* @param m first matrix
* @param n second matrix
*/
static void multiply4x4Matrices(GLfloat*, const GLfloat*);
/**
* Rotates a 4x4 matrix
*
* @param[in,out] m the matrix to rotate
* @param angle the angle to rotate
* @param x the x component of the direction to rotate to
* @param y the y component of the direction to rotate to
* @param z the z component of the direction to rotate to
*/
static void rotate4x4Matrix(GLfloat*, GLfloat, GLfloat, GLfloat, GLfloat);
/**
* Translates a 4x4 matrix
*
* @param[in,out] m the matrix to translate
* @param x the x component of the direction to translate to
* @param y the y component of the direction to translate to
* @param z the z component of the direction to translate to
*/
static void translate4x4Matrix(GLfloat*, GLfloat, GLfloat, GLfloat);
/**
* Creates a 4x4 identity matrix
*
* @param m the matrix to convert to an identity matrix
*/
static void create4x4IdentityMatrix(GLfloat*);
/**
* Transposes a 4x4 matrix.
*
* @param m the matrix to transpose
*/
static void transpose4x4Matrix(GLfloat*);
/**
* Inverts a 4x4 matrix.
*
* @param m the matrix to invert
*/
static void invert4x4Matrix(GLfloat*);
/**
* Calculate a perspective projection transformation.
*
* @param m the matrix to save the transformation in
* @param yFOV the field of view in the y direction
* @param aspect the view aspect ratio
* @param zNear the near clipping plane
* @param zFar the far clipping plane
*/
static void calcPerspectiveProjectTransformation(GLfloat*,
GLfloat,
GLfloat,
GLfloat,
GLfloat);
};
#endif

View File

@ -1,82 +0,0 @@
/**
* Copyright (c) 2023, Furkan Mudanyali <fmudanyali@icloud.com>
* All rights reserved
*/
#include <GLES3/gl3.h>
#define GLEW_STATIC
#include <SDL2/SDL_video.h>
#include <GL/glew.h>
#include <graphics/opengl/opengl.h>
#include <game/game.h>
#include <window/window.h>
#include <string>
#include <iostream>
static const GLchar* vertexShaderSrc = R"(
attribute vec4 position;
void main() {
gl_Position = vec4(position.xyz, 1.0);
}
)";
static const GLchar* fragmentShaderSrc = R"(
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
)";
static GLfloat vertices[] = {0.0, 0.8, -0.8, -0.8, 0.8, -0.8};
OpenGL::OpenGL(Game* pGame) {
glewExperimental = GL_TRUE;
this->game = pGame;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetSwapInterval(0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
this->context = SDL_GL_CreateContext(this->game->pWindow->window);
GLenum err = glewInit();
std::cout << glewGetErrorString(err);
GLuint vertexArrObj;
glGenVertexArrays(1, &vertexArrObj);
glBindVertexArray(vertexArrObj);
GLuint vertexBufObj;
glGenBuffers(1, &vertexBufObj);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufObj);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSrc, nullptr);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSrc, nullptr);
glCompileShader(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
GLint posAttribute = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttribute);
glVertexAttribPointer(posAttribute, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
}
void OpenGL::drawSomething() {
glClearColor(0.0F, 0.0F, 0.0F, 1.0F);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
SDL_GL_SwapWindow(this->game->pWindow->window);
}

View File

@ -1,25 +0,0 @@
/**
* Copyright (c) 2023, Furkan Mudanyali <fmudanyali@icloud.com>
* All rights reserved
*/
#ifndef _HOMD_GRAPHICS_GL
#define _HOMD_GRAPHICS_GL
#include <SDL2/SDL_video.h>
#include <graphics/graphics.h>
class Window;
class OpenGL : public Graphics {
SDL_GLContext context = nullptr;
public:
OpenGL(Game*);
~OpenGL() override = default;
void setGLContext();
void drawSomething() override;
};
#endif

View File

@ -3,8 +3,8 @@
* All rights reserved
*/
#include <input/input.h>
#include <game/game.h>
#include <input/input.h>
Input::Input(Game* pGame) {
this->game = pGame;

View File

@ -1,16 +0,0 @@
/**
* Copyright (c) 2023, Furkan Mudanyali <fmudanyali@icloud.com>
* All rights reserved
*/
#include <game/game.h>
#include <graphics/graphics.h>
#include <scene/example/example.h>
Example::Example(Game* pGame) {
this->game = pGame;
}
void Example::draw() {
this->game->pRenderer->drawSomething();
}

View File

@ -1,12 +0,0 @@
/**
* Copyright (c) 2023, Furkan Mudanyali <fmudanyali@icloud.com>
* All rights reserved
*/
#include <scene/scene.h>
class Example : public Scene {
public:
Example(Game*);
void draw() override;
};

411
src/scene/gears/gears.cpp Normal file
View File

@ -0,0 +1,411 @@
/**
* Copyright (c) 2023, Furkan Mudanyali <fmudanyali@icloud.com>
* All rights reserved
*/
#include <GLES3/gl3.h>
#include <GL/glew.h>
#include <game/game.h>
#include <graphics/graphics.h>
#include <scene/gears/gears.h>
#include <cstddef>
#include <iostream>
#include <cassert>
static const char* vertexShader = R"(
attribute vec3 position;
attribute vec3 normal;
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 NormalMatrix;
uniform vec4 LightSourcePosition;
uniform vec4 MaterialColor;
varying vec4 Color;
void main(void) {
// Transform the normal to eye coordinates
vec3 N = normalize(vec3(NormalMatrix * vec4(normal, 1.0)));
// The LightSourcePosition is the direction for directional light
vec3 L = normalize(LightSourcePosition.xyz);
float diffuse = max(dot(N, L), 0.0);
float ambient = 0.2;
// Multiply the diffuse value by the vertex color
// to get the actual color that will be used to draw the vertex with
// Color = diffuse * MaterialColor;
Color = vec4((ambient + diffuse) * MaterialColor.xyz, MaterialColor.a);
gl_Position = ModelViewProjectionMatrix * vec4(position, 1.0);
}
)";
static const char* fragmentShader = R"(
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 Color;
void main(void) {
gl_FragColor = Color;
}
)";
GearsScene::GearsScene(Game* pGame) {
this->pGame = pGame;
char msg[512];
const char* p;
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
GLuint vertex;
GLuint fragment;
GLuint program;
p = vertexShader;
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &p, nullptr);
glCompileShader(vertex);
glGetShaderInfoLog(vertex, sizeof msg, nullptr, msg);
std::cout << "Vertex shader info: " << msg << "\n";
p = fragmentShader;
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &p, nullptr);
glCompileShader(fragment);
glGetShaderInfoLog(fragment, sizeof msg, nullptr, msg);
std::cout << "Fragment shader info: " << msg << "\n";
program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glBindAttribLocation(program, 0, "position");
glBindAttribLocation(program, 1, "normal");
glLinkProgram(program);
glGetProgramInfoLog(program, sizeof msg, nullptr, msg);
std::cout << "Program info: " << msg << "\n";
glUseProgram(program);
this->modelViewProjectionMatrixLoc =
glGetUniformLocation(program, "ModelViewProjectionMatrix");
this->normalMatrixLoc = glGetUniformLocation(program, "NormalMatrix");
this->lightSrcPosLoc = glGetUniformLocation(program, "LightSourcePosition");
this->materialColorLoc = glGetUniformLocation(program, "MaterialColor");
glUniform4fv((GLint)this->lightSrcPosLoc, 1, lightSourcePos);
gears[0] = createGear(1.0, 4.0, 1.0, 20, 0.7);
gears[1] = createGear(0.5, 2.0, 2.0, 10, 0.7);
gears[2] = createGear(1.3, 2.0, 0.5, 10, 0.7);
}
GearVertex* GearsScene::fillGearVertex(GearVertex* gearVertex,
GLfloat x,
GLfloat y,
GLfloat z,
const GLfloat n[3]) {
gearVertex[0][0] = x;
gearVertex[0][1] = y;
gearVertex[0][2] = z;
gearVertex[0][3] = n[0];
gearVertex[0][4] = n[1];
gearVertex[0][5] = n[2];
return gearVertex + 1;
}
Gear* GearsScene::createGear(GLfloat innerRad,
GLfloat outerRad,
GLfloat width,
GLfloat teeth,
GLfloat toothDepth) {
GLfloat rad0;
GLfloat rad1;
GLfloat rad2;
GLfloat diameter;
GearVertex* vertex;
Gear* gear;
double sinArr[5];
double cosArr[5];
GLfloat normal[3];
int currentStrip = 0;
gear = (Gear*)malloc(sizeof *gear);
// Calculate the radii used in the gear
rad0 = innerRad;
rad1 = outerRad - toothDepth / 2.0F;
rad2 = outerRad + toothDepth / 2.0F;
diameter = 2.0F * (float)M_PI / teeth / 4.0F;
// Allocate triangle strip information
gear->nStrips = STRIPS_PER_TOOTH * teeth;
gear->strips = (VertexStrip*)calloc(gear->nStrips, sizeof(*gear->vertices));
// Allocate the vertices
gear->vertices = (GearVertex*)calloc(VERTICES_PER_TOOTH * teeth,
sizeof(*gear->vertices));
vertex = gear->vertices;
// Calculate needed sin/cos for various angles
for (int i = 0; i < (int)teeth; ++i) {
sincos((float)i * 2.0F * M_PI / teeth, &sinArr[0], &cosArr[0]);
sincos((float)i * 2.0F * M_PI / teeth + diameter, &sinArr[1],
&cosArr[1]);
sincos((float)i * 2.0F * M_PI / teeth + diameter * 2, &sinArr[2],
&cosArr[2]);
sincos((float)i * 2.0F * M_PI / teeth + diameter * 3, &sinArr[3],
&cosArr[3]);
sincos((float)i * 2.0F * M_PI / teeth + diameter * 4, &sinArr[4],
&cosArr[4]);
// Macros that do shit idk
#define GEAR_POINT(r, da) \
{ (float)((r)*cosArr[(da)]), (float)((r)*sinArr[(da)]) }
#define SET_NORMAL(x, y, z) \
do { \
normal[0] = (x); \
normal[1] = (y); \
normal[2] = (z); \
} while (0)
#define GEAR_VERT(v, point, sign) \
fillGearVertex((v), points[(point)].x, points[(point)].y, \
(sign)*width * 0.5, normal)
#define START_STRIP \
do { \
gear->strips[currentStrip].first = vertex - gear->vertices; \
} while (0);
#define END_STRIP \
do { \
int _tmp = (vertex - gear->vertices); \
gear->strips[currentStrip].count = \
_tmp - gear->strips[currentStrip].first; \
currentStrip++; \
} while (0)
#define QUAD_WITH_NORMAL(p1, p2) \
do { \
SET_NORMAL((points[(p1)].y - points[(p2)].y), \
-(points[(p1)].x - points[(p2)].x), 0); \
vertex = GEAR_VERT(vertex, (p1), -1); \
vertex = GEAR_VERT(vertex, (p1), 1); \
vertex = GEAR_VERT(vertex, (p2), -1); \
vertex = GEAR_VERT(vertex, (p2), 1); \
} while (0)
using Point = struct {
GLfloat x;
GLfloat y;
};
// Create 7 points (x,y coords) that make up a tooth
Point points[7] = {
GEAR_POINT(rad2, 1), GEAR_POINT(rad2, 2), GEAR_POINT(rad1, 0),
GEAR_POINT(rad1, 3), GEAR_POINT(rad0, 0), GEAR_POINT(rad1, 4),
GEAR_POINT(rad0, 4),
};
// Front face
START_STRIP;
SET_NORMAL(0, 0, 1.0);
vertex = GEAR_VERT(vertex, 0, +1);
vertex = GEAR_VERT(vertex, 1, +1);
vertex = GEAR_VERT(vertex, 2, +1);
vertex = GEAR_VERT(vertex, 3, +1);
vertex = GEAR_VERT(vertex, 4, +1);
vertex = GEAR_VERT(vertex, 5, +1);
vertex = GEAR_VERT(vertex, 6, +1);
END_STRIP;
// Inner face
START_STRIP;
QUAD_WITH_NORMAL(4, 6);
END_STRIP;
// Back face
START_STRIP;
SET_NORMAL(0, 0, -1.0);
vertex = GEAR_VERT(vertex, 6, -1);
vertex = GEAR_VERT(vertex, 5, -1);
vertex = GEAR_VERT(vertex, 4, -1);
vertex = GEAR_VERT(vertex, 3, -1);
vertex = GEAR_VERT(vertex, 2, -1);
vertex = GEAR_VERT(vertex, 1, -1);
vertex = GEAR_VERT(vertex, 0, -1);
END_STRIP;
// Outer face
START_STRIP;
QUAD_WITH_NORMAL(0, 2);
END_STRIP;
START_STRIP;
QUAD_WITH_NORMAL(1, 0);
END_STRIP;
START_STRIP;
QUAD_WITH_NORMAL(3, 1);
END_STRIP;
START_STRIP;
QUAD_WITH_NORMAL(5, 3);
END_STRIP;
}
gear->nVertices = (int)(vertex - gear->vertices);
glGenBuffers(1, &gear->vertexBufObj);
glBindBuffer(GL_ARRAY_BUFFER, gear->vertexBufObj);
glBufferData(GL_ARRAY_BUFFER,
(GLsizeiptr)(gear->nVertices * sizeof(GearVertex)),
gear->vertices, GL_STATIC_DRAW);
return gear;
}
void GearsScene::drawGear(Gear* gear,
GLfloat* transform,
GLfloat x,
GLfloat y,
GLfloat angle,
const GLfloat color[4]) {
GLfloat modelView[16];
GLfloat normalMatrix[16];
GLfloat modelViewProjection[16];
// Translate and rotate the gear
memcpy(modelView, transform, sizeof(modelView));
Graphics::translate4x4Matrix(modelView, x, y, 0);
Graphics::rotate4x4Matrix(modelView, 2.0F * (float)M_PI * angle / 360.0F, 0,
0, 1);
/* Create and set the ModelViewProjectionMatrix */
memcpy(modelViewProjection, this->projectionMatrix,
sizeof(modelViewProjection));
Graphics::multiply4x4Matrices(modelViewProjection, modelView);
glUniformMatrix4fv((GLint)this->modelViewProjectionMatrixLoc, 1, GL_FALSE,
modelViewProjection);
/*
* Create and set the NormalMatrix. It's the inverse transpose of the
* ModelView matrix.
*/
memcpy(normalMatrix, modelView, sizeof(normalMatrix));
Graphics::invert4x4Matrix(normalMatrix);
Graphics::transpose4x4Matrix(normalMatrix);
glUniformMatrix4fv((GLint)this->normalMatrixLoc, 1, GL_FALSE, normalMatrix);
/* Set the gear color */
glUniform4fv((GLint)this->materialColorLoc, 1, color);
/* Set the vertex buffer object to use */
glBindBuffer(GL_ARRAY_BUFFER, gear->vertexBufObj);
/* Set up the position of the attributes in the vertex buffer object */
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat),
nullptr);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat),
(GLfloat*)(sizeof(GLfloat) * 3));
/* Enable the attributes */
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
/* Draw the triangle strips that comprise the gear */
glDrawArrays(GL_TRIANGLE_STRIP, 0, gear->nVertices);
/* Disable the attributes */
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
}
void GearsScene::reshape() {
if (this->width != this->pGame->pWindow->getWidth() ||
this->height != this->pGame->pWindow->getHeight()) {
this->width = this->pGame->pWindow->getWidth();
this->height = this->pGame->pWindow->getHeight();
Graphics::calcPerspectiveProjectTransformation(
this->projectionMatrix, 60.0,
(float)this->width / (float)this->height, 1.0, 1024.0);
glViewport(0, 0, (GLint)this->width, (GLint)this->height);
}
}
void GearsScene::idle() {
static int frames = 0;
static double tRot0 = -1.0;
static double tRate0 = -1.0;
double dt;
double t = SDL_GetTicks() / 1000.0;
if (tRot0 < 0.0) {
tRot0 = t;
}
dt = t - tRot0;
tRot0 = t;
/* advance rotation for next frame */
this->currentAngle += 70.0 * dt; /* 70 degrees per second */
if (this->currentAngle > 3600.0) {
this->currentAngle -= 3600.0;
}
this->pGame->pRenderer->draw();
frames++;
if (tRate0 < 0.0) {
tRate0 = t;
}
if (t - tRate0 >= 5.0) {
GLfloat seconds = t - tRate0;
GLfloat fps = frames / seconds;
printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
fps);
tRate0 = t;
frames = 0;
}
}
void GearsScene::draw() {
const static GLfloat red[4] = {0.8, 0.1, 0.0, 1.0};
const static GLfloat green[4] = {0.0, 0.8, 0.2, 1.0};
const static GLfloat blue[4] = {0.2, 0.2, 1.0, 1.0};
GLfloat transform[16];
Graphics::create4x4IdentityMatrix(transform);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Translate and rotate the view */
Graphics::translate4x4Matrix(transform, 0, 0, -20);
Graphics::rotate4x4Matrix(
transform, 2.0F * (float)M_PI * viewRotation[0] / 360.0F, 1, 0, 0);
Graphics::rotate4x4Matrix(
transform, 2.0F * (float)M_PI * viewRotation[1] / 360.0F, 0, 1, 0);
Graphics::rotate4x4Matrix(
transform, 2.0F * (float)M_PI * viewRotation[2] / 360.0F, 0, 0, 1);
/* Draw the gears */
drawGear(gears[0], transform, -3.0, -2.0, currentAngle, red);
drawGear(gears[1], transform, 3.1, -2.0, (float)-2 * currentAngle - 9.0F,
green);
drawGear(gears[2], transform, -3.1, 4.2, (float)-2 * currentAngle - 25.0F,
blue);
reshape();
idle();
}

114
src/scene/gears/gears.h Normal file
View File

@ -0,0 +1,114 @@
/**
* Copyright (c) 2023, Furkan Mudanyali <fmudanyali@icloud.com>
* All rights reserved
*/
#include <GLES3/gl3.h>
#include <GL/glew.h>
#include <scene/scene.h>
#define STRIPS_PER_TOOTH 7
#define VERTICES_PER_TOOTH 35
#define GEAR_VERTEX_STRIDE 6
// Class describing the vertices in triangle strip
using VertexStrip = struct {
// First vertex in the strip
GLint first;
// Number of consecutive verices in the strip after the first
GLint count;
};
// Each vertex consists of GEAR_VERTEX_STRIDE GLfloat attributes
using GearVertex = GLfloat[GEAR_VERTEX_STRIDE];
// Class representing a gear
using Gear = struct {
// Array of vertices comprising the gear
GearVertex* vertices;
// Number of vertices comprising the gear
int nVertices;
// Array of triangle strips comprising the gear
VertexStrip* strips;
// Number of triangle strips comprising the gear
int nStrips;
// Vertex buffer object holding the vertices in the GPU
GLuint vertexBufObj;
};
class GearsScene : public Scene {
// The view rotation [x, y, z]
GLfloat viewRotation[3] = {20.0, 30.0, 0.0};
// The gears
Gear* gears[3];
// The current gear rotation angle
GLfloat currentAngle = 0.0;
// The location of the shader uniforms
GLuint modelViewProjectionMatrixLoc;
GLuint normalMatrixLoc;
GLuint lightSrcPosLoc;
GLuint materialColorLoc;
// The projection matrix
GLfloat projectionMatrix[16];
int width;
int height;
void idle();
void reshape();
// The direction of the directional light for the scene
const GLfloat lightSourcePos[4] = {5.0, 5.0, 10.0, 1.0};
/**
* Fills a gear vertex.
*
* @param gearVertex the vertex to fill
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @param n pointer to the normal table
*
* @return the operation error code
*/
static GearVertex* fillGearVertex(GearVertex* gearVertex,
GLfloat x,
GLfloat y,
GLfloat z,
const GLfloat n[3]);
/**
* Create a gear wheel.
*
* @param innerRad radius of the hole at the center
* @param outerRad radius at the center of the teth
* @param width width of the gear
* @param teeth the number of teeth
* @param toothDepth the depth of the teeth
*
* @return the pointer to the constructed gear struct
*/
static Gear* createGear(GLfloat innerRad,
GLfloat outerRad,
GLfloat width,
GLfloat teeth,
GLfloat toothDepth);
/**
* Draws a gear
*
* @param gear the gear to draw
* @param transform the current transformation matrix
* @param x the x pos to draw the gear at
* @param y the y pos to draw the gear at
* @param angle the rotation angle of the gear
* @param color the color of the gear
*/
void drawGear(Gear*, GLfloat*, GLfloat, GLfloat, GLfloat, const GLfloat[4]);
// Draws all gears
void drawAllGears();
public:
GearsScene(Game*);
void draw() override;
};

View File

@ -10,7 +10,7 @@ class Game;
class Scene {
public:
Game* game;
Game* pGame;
bool destroy = false;
Scene() = default;