instancing of particles, no movement
parent
d66eed3a42
commit
686c966a77
|
@ -19,7 +19,15 @@ set(CMAKE_CXX_STANDARD 17)
|
||||||
# I like absolute directories since I think relative file paths are ugly and hard to read
|
# I like absolute directories since I think relative file paths are ugly and hard to read
|
||||||
include_directories(include)
|
include_directories(include)
|
||||||
include_directories(${CMAKE_BINARY_DIR}/include/)
|
include_directories(${CMAKE_BINARY_DIR}/include/)
|
||||||
file(GLOB_RECURSE SRC_FILES "src/*.cpp")
|
#file(GLOB_RECURSE SRC_FILES "src/*.cpp")
|
||||||
|
|
||||||
|
# don't try to build other mode's files as we will use the same names of functions to make it easier
|
||||||
|
# we have to do this because GL
|
||||||
|
if (${EXTRAS})
|
||||||
|
file(GLOB SRC_FILES "src/*.cpp" "src/high_perf/*.cpp")
|
||||||
|
else ()
|
||||||
|
file(GLOB SRC_FILES "src/*.cpp" "src/basic/*.cpp")
|
||||||
|
endif ()
|
||||||
|
|
||||||
# Include my utility library
|
# Include my utility library
|
||||||
add_subdirectory(libs/BLT)
|
add_subdirectory(libs/BLT)
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
#ifndef ASSIGN3_CAMERA_H
|
#ifndef ASSIGN3_CAMERA_H
|
||||||
#define ASSIGN3_CAMERA_H
|
#define ASSIGN3_CAMERA_H
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <blt/math/vectors.h>
|
|
||||||
#include <GL/glut.h>
|
#include <GL/glut.h>
|
||||||
#include <GL/freeglut.h>
|
#include <GL/freeglut.h>
|
||||||
|
#include <cmath>
|
||||||
|
#include <blt/math/vectors.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
#include "blt/std/logging.h"
|
#include "blt/std/logging.h"
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ class camera {
|
||||||
|
|
||||||
const float MAX_SPEED = 100;
|
const float MAX_SPEED = 100;
|
||||||
const float DEFAULT_SPEED = 50;
|
const float DEFAULT_SPEED = 50;
|
||||||
|
const float MIN_SPEED = 1;
|
||||||
const float ROTATION_SPEED = 3;
|
const float ROTATION_SPEED = 3;
|
||||||
|
|
||||||
float cur_speed = DEFAULT_SPEED;
|
float cur_speed = DEFAULT_SPEED;
|
||||||
|
@ -106,7 +107,14 @@ class camera {
|
||||||
rotation[2] += (-(float) horzSpeed * delta * ROTATION_SPEED);
|
rotation[2] += (-(float) horzSpeed * delta * ROTATION_SPEED);
|
||||||
else if (specialState[GLUT_KEY_RIGHT])
|
else if (specialState[GLUT_KEY_RIGHT])
|
||||||
rotation[2] += ((float) horzSpeed * delta * ROTATION_SPEED);
|
rotation[2] += ((float) horzSpeed * delta * ROTATION_SPEED);
|
||||||
|
|
||||||
|
if (specialState[GLUT_KEY_F1])
|
||||||
|
cur_speed = DEFAULT_SPEED;
|
||||||
|
if (specialState[GLUT_KEY_F2])
|
||||||
|
cur_speed = MIN_SPEED;
|
||||||
|
if (specialState[GLUT_KEY_F3])
|
||||||
|
cur_speed = MAX_SPEED;
|
||||||
|
|
||||||
if (rotation[2] > 360)
|
if (rotation[2] > 360)
|
||||||
rotation[2] = 0;
|
rotation[2] = 0;
|
||||||
if (rotation[2] < 0)
|
if (rotation[2] < 0)
|
||||||
|
|
|
@ -3033,7 +3033,7 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
* modes type definitions
|
* basic type definitions
|
||||||
*-----------------------------------------------------------------------*/
|
*-----------------------------------------------------------------------*/
|
||||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Created by Brett on 31/03/23.
|
||||||
|
* Licensed under GNU General Public License V3.0
|
||||||
|
* See LICENSE file for license detail
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ASSIGN3_GL_UTIL_H
|
||||||
|
#define ASSIGN3_GL_UTIL_H
|
||||||
|
|
||||||
|
#include <glad/gl.h>
|
||||||
|
#include <blt/math/math.h>
|
||||||
|
#include <blt/std/string.h>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: This is taken from my final project,
|
||||||
|
* https://github.com/Tri11Paragon/COSC-3P98-Final-Project/blob/main/include/render/gl.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
class shader {
|
||||||
|
private:
|
||||||
|
struct IntDefaultedToMinusOne {
|
||||||
|
GLint i = -1;
|
||||||
|
};
|
||||||
|
// we can have shaders of many types in OpenGL
|
||||||
|
unsigned int programID = 0;
|
||||||
|
// but we will only make use of these two for now
|
||||||
|
unsigned int vertexShaderID = 0;
|
||||||
|
unsigned int fragmentShaderID = 0;
|
||||||
|
// while these will remain unused. (Webgl2 apparently doesn't support them despite being based on GL4.3? that's a TODO!)
|
||||||
|
unsigned int geometryShaderID = 0;
|
||||||
|
// this would be very useful however it is highly unlikely webgl will support it
|
||||||
|
// im leaving some of this stuff in here because I might expand the native application to use some of it.
|
||||||
|
// im trying to keep the web and native versions the same though
|
||||||
|
unsigned int tessellationShaderID = 0;
|
||||||
|
std::unordered_map<std::string, IntDefaultedToMinusOne> uniformVars;
|
||||||
|
|
||||||
|
static unsigned int createShader(const std::string& source, int type);
|
||||||
|
|
||||||
|
inline GLint getUniformLocation(const std::string &name) {
|
||||||
|
if (uniformVars[name].i != -1)
|
||||||
|
return uniformVars[name].i;
|
||||||
|
// caching the result is a lot faster since it won't change after the shader is created.
|
||||||
|
// TODO: look into this: https://webglfundamentals.org/webgl/lessons/webgl-qna-how-can-i-get-all-the-uniforms-and-uniformblocks.html
|
||||||
|
int loc = glGetUniformLocation(programID, name.c_str());
|
||||||
|
uniformVars[name].i = loc;
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline std::string removeEmptyFirstLines(const std::string& string){
|
||||||
|
auto lines = blt::string::split(string, "\n");
|
||||||
|
std::string new_source_string;
|
||||||
|
for (const auto& line : lines) {
|
||||||
|
if (!line.empty() && !blt::string::contains(line, "\"")) {
|
||||||
|
new_source_string += line;
|
||||||
|
new_source_string += "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new_source_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates a shader
|
||||||
|
* @param vertex vertex shader source or file
|
||||||
|
* @param fragment fragment shader source or file
|
||||||
|
* @param geometry geometry shader source or file (optional)
|
||||||
|
* @param load_as_string load the shader as a string (true) or use the string to load the shader as a file (false)
|
||||||
|
*/
|
||||||
|
shader(const std::string &vertex, const std::string &fragment, const std::string &geometry = "", bool load_as_string = true);
|
||||||
|
|
||||||
|
shader(shader&& move) noexcept;
|
||||||
|
|
||||||
|
// used to set the location of VAOs to the in variables in opengl shaders.
|
||||||
|
void bindAttribute(int attribute, const std::string &name) const;
|
||||||
|
|
||||||
|
// used to set location of shared UBOs like the perspective and view matrix
|
||||||
|
void setUniformBlockLocation(const std::string &name, int location) const;
|
||||||
|
|
||||||
|
// set various data-types.
|
||||||
|
inline void setBool(const std::string &name, bool value) {
|
||||||
|
glUniform1i(getUniformLocation(name), (int) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setInt(const std::string &name, int value) {
|
||||||
|
glUniform1i(getUniformLocation(name), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setFloat(const std::string &name, float value) {
|
||||||
|
glUniform1f(getUniformLocation(name), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setMatrix(const std::string &name, blt::mat4x4 &matrix) {
|
||||||
|
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, matrix.ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setVec3(const std::string &name, const blt::vec3 &vec) {
|
||||||
|
glUniform3f(getUniformLocation(name), vec.x(), vec.y(), vec.z());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setVec4(const std::string &name, const blt::vec4 &vec) {
|
||||||
|
// TODO: edit BLT to include a w component
|
||||||
|
glUniform4f(getUniformLocation(name), vec.x(), vec.y(), vec.z(), vec[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setVec2(const std::string &name, float x, float y) {
|
||||||
|
glUniform2f(getUniformLocation(name), x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setVec3(const std::string &name, float x, float y, float z) {
|
||||||
|
glUniform3f(getUniformLocation(name), x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setVec4(const std::string &name, float x, float y, float z, float w) {
|
||||||
|
glUniform4f(getUniformLocation(name), x, y, z, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void bind() const {
|
||||||
|
glUseProgram(programID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateProjectionMatrix(const blt::mat4x4& projectionMatrix);
|
||||||
|
static void updateOrthographicMatrix(const blt::mat4x4& orthoMatrix);
|
||||||
|
static void updateViewMatrix(const blt::mat4x4& viewMatrix);
|
||||||
|
// returns the perspective view matrix which is calculated per frame. (This is for optimization)
|
||||||
|
static const blt::mat4x4& getPVM();
|
||||||
|
|
||||||
|
~shader();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //ASSIGN3_GL_UTIL_H
|
|
@ -4,17 +4,20 @@
|
||||||
* See LICENSE file for license detail
|
* See LICENSE file for license detail
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ASSIGN3_ADVANCED_H
|
#ifndef ASSIGN3_HIGH_PERF_H
|
||||||
#define ASSIGN3_ADVANCED_H
|
#define ASSIGN3_HIGH_PERF_H
|
||||||
|
|
||||||
#include <glad/gl.h>
|
#include <glad/gl.h>
|
||||||
#include <camera.h>
|
#include <camera.h>
|
||||||
#include <particle_system.h>
|
#include <particle_system.h>
|
||||||
|
|
||||||
extern particle_system* fountain;
|
#ifdef EXTRAS
|
||||||
|
|
||||||
extern int WINDOW_WIDTH;
|
extern int WINDOW_WIDTH;
|
||||||
extern int WINDOW_HEIGHT;
|
extern int WINDOW_HEIGHT;
|
||||||
|
extern particle_system* fountain;
|
||||||
extern camera cam;
|
extern camera cam;
|
||||||
|
extern const unsigned int particle_count;
|
||||||
|
|
||||||
void window_resize(int width, int height);
|
void window_resize(int width, int height);
|
||||||
|
|
||||||
|
@ -26,4 +29,6 @@ void init();
|
||||||
|
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
#endif //ASSIGN3_ADVANCED_H
|
#endif
|
||||||
|
|
||||||
|
#endif //ASSIGN3_HIGH_PERF_H
|
|
@ -92,6 +92,7 @@ class particle_system {
|
||||||
particle_system(
|
particle_system(
|
||||||
const blt::vec3& position, const blt::vec3& direction, float spread, int pps
|
const blt::vec3& position, const blt::vec3& direction, float spread, int pps
|
||||||
): position(position), direction(direction), spread(spread), pps(pps) {
|
): position(position), direction(direction), spread(spread), pps(pps) {
|
||||||
|
#ifndef EXTRAS
|
||||||
quad = glGenLists(1);
|
quad = glGenLists(1);
|
||||||
glNewList(quad, GL_COMPILE);
|
glNewList(quad, GL_COMPILE);
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
|
@ -105,6 +106,7 @@ class particle_system {
|
||||||
glVertex3f(s, s, 0);
|
glVertex3f(s, s, 0);
|
||||||
glEnd();
|
glEnd();
|
||||||
glEndList();
|
glEndList();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(camera& cam, float bnx, float bnz, float bpx, float bpz) {
|
void update(camera& cam, float bnx, float bnz, float bpx, float bpz) {
|
||||||
|
@ -173,6 +175,7 @@ class particle_system {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void applyBillboard() {
|
inline static void applyBillboard() {
|
||||||
|
#ifndef EXTRAS
|
||||||
GLfloat m[16];
|
GLfloat m[16];
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glGetFloatv(GL_MODELVIEW_MATRIX, m);
|
glGetFloatv(GL_MODELVIEW_MATRIX, m);
|
||||||
|
@ -187,9 +190,11 @@ class particle_system {
|
||||||
}
|
}
|
||||||
|
|
||||||
glLoadMatrixf(m);
|
glLoadMatrixf(m);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void render(camera& cam, texture** textures) {
|
void render(camera& cam, texture** textures) {
|
||||||
|
#ifndef EXTRAS
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
// by batching particles by texture we save a little driver overhead
|
// by batching particles by texture we save a little driver overhead
|
||||||
for (auto& pair : particles) {
|
for (auto& pair : particles) {
|
||||||
|
@ -243,6 +248,7 @@ class particle_system {
|
||||||
str << (randomizeTexture ? "True" : "False");
|
str << (randomizeTexture ? "True" : "False");
|
||||||
glutSetWindowTitle(str.str().c_str());
|
glutSetWindowTitle(str.str().c_str());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void randomizeSpeed(float n) {
|
void randomizeSpeed(float n) {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <string>
|
||||||
|
std::string shader_frag = R"("
|
||||||
|
#version 460
|
||||||
|
|
||||||
|
in vec2 uv_;
|
||||||
|
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
out_color = vec4(uv_, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
")";
|
||||||
|
#endif
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <string>
|
||||||
|
std::string shader_vert = R"("
|
||||||
|
#version 460
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 vertex;
|
||||||
|
layout (location = 1) in vec2 uv;
|
||||||
|
layout (location = 2) in vec4 pos;
|
||||||
|
layout (location = 3) in vec4 dir;
|
||||||
|
|
||||||
|
out vec2 uv_;
|
||||||
|
|
||||||
|
uniform mat4 pvm;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// passthough the UV (OpenGL interpolates this per fragment)
|
||||||
|
uv_ = uv;
|
||||||
|
// offset the vertex by the particle's position
|
||||||
|
gl_Position = pvm * vec4(vertex + pos.xyz, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
")";
|
||||||
|
#endif
|
|
@ -798,8 +798,8 @@ static int stbi__sse2_available(void)
|
||||||
//
|
//
|
||||||
// stbi__context struct and start_xxx functions
|
// stbi__context struct and start_xxx functions
|
||||||
|
|
||||||
// stbi__context structure is our modes context used by all images, so it
|
// stbi__context structure is our basic context used by all images, so it
|
||||||
// contains all the IO context, plus some modes image information
|
// contains all the IO context, plus some basic image information
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
stbi__uint32 img_x, img_y;
|
stbi__uint32 img_x, img_y;
|
||||||
|
@ -2983,7 +2983,7 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
|
||||||
for (k=0; k < z->scan_n; ++k) {
|
for (k=0; k < z->scan_n; ++k) {
|
||||||
int n = z->order[k];
|
int n = z->order[k];
|
||||||
// scan out an mcu's worth of this component; that's just determined
|
// scan out an mcu's worth of this component; that's just determined
|
||||||
// by the modes H and V specified for the component
|
// by the basic H and V specified for the component
|
||||||
for (y=0; y < z->img_comp[n].v; ++y) {
|
for (y=0; y < z->img_comp[n].v; ++y) {
|
||||||
for (x=0; x < z->img_comp[n].h; ++x) {
|
for (x=0; x < z->img_comp[n].h; ++x) {
|
||||||
int x2 = (i*z->img_comp[n].h + x)*8;
|
int x2 = (i*z->img_comp[n].h + x)*8;
|
||||||
|
@ -3043,7 +3043,7 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
|
||||||
for (k=0; k < z->scan_n; ++k) {
|
for (k=0; k < z->scan_n; ++k) {
|
||||||
int n = z->order[k];
|
int n = z->order[k];
|
||||||
// scan out an mcu's worth of this component; that's just determined
|
// scan out an mcu's worth of this component; that's just determined
|
||||||
// by the modes H and V specified for the component
|
// by the basic H and V specified for the component
|
||||||
for (y=0; y < z->img_comp[n].v; ++y) {
|
for (y=0; y < z->img_comp[n].v; ++y) {
|
||||||
for (x=0; x < z->img_comp[n].h; ++x) {
|
for (x=0; x < z->img_comp[n].h; ++x) {
|
||||||
int x2 = (i*z->img_comp[n].h + x);
|
int x2 = (i*z->img_comp[n].h + x);
|
||||||
|
@ -5471,7 +5471,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
|
||||||
if (hsz != 12) {
|
if (hsz != 12) {
|
||||||
int compress = stbi__get32le(s);
|
int compress = stbi__get32le(s);
|
||||||
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
|
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
|
||||||
if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes
|
if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG basic
|
||||||
if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel
|
if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel
|
||||||
stbi__get32le(s); // discard sizeof
|
stbi__get32le(s); // discard sizeof
|
||||||
stbi__get32le(s); // discard hres
|
stbi__get32le(s); // discard hres
|
||||||
|
@ -5912,7 +5912,7 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req
|
||||||
if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
|
if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
|
||||||
else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
|
else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
|
||||||
|
|
||||||
if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured modes consistency
|
if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency
|
||||||
return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
|
return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
|
||||||
|
|
||||||
// tga info
|
// tga info
|
||||||
|
@ -6173,7 +6173,7 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req
|
||||||
if (stbi__get16be(s) != 3)
|
if (stbi__get16be(s) != 3)
|
||||||
return stbi__errpuc("wrong color format", "PSD is not in RGB color format");
|
return stbi__errpuc("wrong color format", "PSD is not in RGB color format");
|
||||||
|
|
||||||
// Skip the Mode Data. (It's the palette for indexed color; other info for other modes.)
|
// Skip the Mode Data. (It's the palette for indexed color; other info for other basic.)
|
||||||
stbi__skip(s,stbi__get32be(s) );
|
stbi__skip(s,stbi__get32be(s) );
|
||||||
|
|
||||||
// Skip the image resources. (resolution, pen tool paths, etc)
|
// Skip the image resources. (resolution, pen tool paths, etc)
|
||||||
|
|
|
@ -32,6 +32,10 @@ typedef struct {
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
} vec;
|
} vec;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float x, y, z, w;
|
||||||
|
} vec4;
|
||||||
|
|
||||||
inline vec operator+(const vec& l, const vec& r) {
|
inline vec operator+(const vec& l, const vec& r) {
|
||||||
return {l.x + r.x, l.y + r.y, l.z + r.z};
|
return {l.x + r.x, l.y + r.y, l.z + r.z};
|
||||||
}
|
}
|
||||||
|
|
2
libs/BLT
2
libs/BLT
|
@ -1 +1 @@
|
||||||
Subproject commit 5d841afe8ca0a8776820eb8593005ca5539205bc
|
Subproject commit 289af1317141c53e04998b32760efced0956db57
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/bash
|
||||||
|
mangohud $1
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
#include <modes/basic.h>
|
#include <modes/basic.h>
|
||||||
|
|
||||||
#ifndef EXTRAS
|
//#ifndef EXTRAS
|
||||||
texture* world_floor;
|
texture* world_floor;
|
||||||
texture* particle_tex[10];
|
texture* particle_tex[10];
|
||||||
|
|
||||||
|
@ -64,4 +64,4 @@
|
||||||
void cleanup() {
|
void cleanup() {
|
||||||
delete world_floor;
|
delete world_floor;
|
||||||
}
|
}
|
||||||
#endif
|
//#endif
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* Created by Brett on 31/03/23.
|
||||||
|
* Licensed under GNU General Public License V3.0
|
||||||
|
* See LICENSE file for license detail
|
||||||
|
*/
|
||||||
|
#include <high_perf/gl_util.h>
|
||||||
|
#include "blt/std/memory.h"
|
||||||
|
#include <blt/std/loader.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: This is taken from my final project,
|
||||||
|
* https://github.com/Tri11Paragon/COSC-3P98-Final-Project/blob/main/include/render/gl.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned int shader::createShader(const std::string& source, int type) {
|
||||||
|
const char* shader_code = source.c_str();
|
||||||
|
// creates a Shader
|
||||||
|
unsigned int shaderID = glCreateShader(type);
|
||||||
|
// loads the shader code for later complication and uploading into the graphics card
|
||||||
|
// TODO: defines can be added here by sending them as additional strings. No need to edit the source string
|
||||||
|
glShaderSource(shaderID, 1, &shader_code, nullptr);
|
||||||
|
// Compile it
|
||||||
|
glCompileShader(shaderID);
|
||||||
|
|
||||||
|
// make sure there are no errors in the compilation. If there is then print out information pertaining to the error.
|
||||||
|
// the actual log is highly dependent on the platform this is being run from, so we cannot make any assumptions about the issue.
|
||||||
|
// the TODO: maybe find a way of lexing the output to give suggestions about fixing the error? default error messages can be unhelpful at times.
|
||||||
|
GLint success;
|
||||||
|
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success) {
|
||||||
|
int log_length = 0;
|
||||||
|
glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
|
||||||
|
// scoped buffers will delete their memory when they go out of scope. A benefit of using BLT
|
||||||
|
blt::scoped_buffer<GLchar> infoLog{static_cast<unsigned long>(log_length + 1)};
|
||||||
|
|
||||||
|
glGetShaderInfoLog(shaderID, log_length + 1, nullptr, infoLog.buffer);
|
||||||
|
auto shader_type_str = (type == GL_VERTEX_SHADER ? "Vertex Shader" : type == GL_FRAGMENT_SHADER ? "Fragment Shader" : "Other Shader");
|
||||||
|
BLT_ERROR("--- --- --- --- --- --- --- --- ---");
|
||||||
|
BLT_ERROR("Unable to compile shader of type %s\nShader source:", shader_type_str);
|
||||||
|
BLT_ERROR(source);
|
||||||
|
BLT_ERROR("I have an log of %d length", log_length);
|
||||||
|
BLT_ERROR(infoLog.buffer);
|
||||||
|
BLT_ERROR("--- --- --- --- --- --- --- --- ---");
|
||||||
|
}
|
||||||
|
return shaderID;
|
||||||
|
}
|
||||||
|
|
||||||
|
shader::shader(const std::string& vertex, const std::string& fragment, const std::string& geometry, bool load_as_string) {
|
||||||
|
// load shader sources
|
||||||
|
bool load_geometry = !geometry.empty();
|
||||||
|
std::string vertex_source = vertex;
|
||||||
|
std::string fragment_source = fragment;
|
||||||
|
std::string geometry_source = geometry;
|
||||||
|
if (!load_as_string){
|
||||||
|
// BLT provides a recursive file loader for glsl shaders. It's pretty much just a recursive function looking for include statements.
|
||||||
|
vertex_source = blt::fs::loadShaderFile(vertex);
|
||||||
|
fragment_source = blt::fs::loadShaderFile(fragment);
|
||||||
|
if (load_geometry)
|
||||||
|
geometry_source = blt::fs::loadShaderFile(geometry);
|
||||||
|
} else {
|
||||||
|
vertex_source = removeEmptyFirstLines(vertex_source);
|
||||||
|
fragment_source = removeEmptyFirstLines(fragment_source);
|
||||||
|
geometry_source = removeEmptyFirstLines(geometry_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the shaders
|
||||||
|
vertexShaderID = createShader(vertex_source, GL_VERTEX_SHADER);
|
||||||
|
fragmentShaderID = createShader(fragment_source, GL_FRAGMENT_SHADER);
|
||||||
|
if (load_geometry)
|
||||||
|
BLT_ERROR("Unable to load geometry shader because webgl doesn't support it!");
|
||||||
|
|
||||||
|
// bind them to a program
|
||||||
|
programID = glCreateProgram();
|
||||||
|
// attach the loaded shaders to the Shader program
|
||||||
|
glAttachShader(programID, vertexShaderID);
|
||||||
|
glAttachShader(programID, fragmentShaderID);
|
||||||
|
if (load_geometry)
|
||||||
|
glAttachShader(programID, geometryShaderID);
|
||||||
|
// link and make sure that our program is valid.
|
||||||
|
glLinkProgram(programID);
|
||||||
|
|
||||||
|
GLint success;
|
||||||
|
glGetProgramiv(programID, GL_LINK_STATUS, &success);
|
||||||
|
if (!success) {
|
||||||
|
int log_length = 0;
|
||||||
|
glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
|
||||||
|
// scoped buffers will delete their memory when they go out of scope.
|
||||||
|
blt::scoped_buffer<GLchar> infoLog{static_cast<unsigned long>(log_length + 1)};
|
||||||
|
|
||||||
|
glGetProgramInfoLog(programID, log_length + 1, nullptr, infoLog.buffer);
|
||||||
|
BLT_ERROR("--- --- --- --- --- --- --- --- ---");
|
||||||
|
BLT_ERROR("Unable to link program of ID: %d", programID);
|
||||||
|
BLT_ERROR(vertex_source);
|
||||||
|
BLT_ERROR(fragment_source);
|
||||||
|
BLT_ERROR(geometry_source);
|
||||||
|
BLT_ERROR("I have an log of %d length", log_length);
|
||||||
|
BLT_ERROR(infoLog.buffer);
|
||||||
|
BLT_ERROR("--- --- --- --- --- --- --- --- ---");
|
||||||
|
}
|
||||||
|
|
||||||
|
glValidateProgram(programID);
|
||||||
|
bind();
|
||||||
|
setUniformBlockLocation("StandardMatrices", 0);
|
||||||
|
glUseProgram(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void shader::bindAttribute(int attribute, const std::string &name) const {
|
||||||
|
bind();
|
||||||
|
glBindAttribLocation(programID, attribute, name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void shader::setUniformBlockLocation(const std::string &name, int location) const {
|
||||||
|
bind();
|
||||||
|
glUniformBlockBinding(programID, glGetUniformBlockIndex(programID, name.c_str()), location);
|
||||||
|
}
|
||||||
|
|
||||||
|
shader::~shader() {
|
||||||
|
glUseProgram(0);
|
||||||
|
// shader was moved
|
||||||
|
if (programID <= 0)
|
||||||
|
return;
|
||||||
|
// remove all the shaders from the program
|
||||||
|
glDetachShader(programID, vertexShaderID);
|
||||||
|
if (geometryShaderID)
|
||||||
|
glDetachShader(programID, geometryShaderID);
|
||||||
|
if (tessellationShaderID)
|
||||||
|
glDetachShader(programID, tessellationShaderID);
|
||||||
|
glDetachShader(programID, fragmentShaderID);
|
||||||
|
|
||||||
|
// delete the shaders
|
||||||
|
glDeleteShader(vertexShaderID);
|
||||||
|
if (geometryShaderID)
|
||||||
|
glDeleteShader(geometryShaderID);
|
||||||
|
if (tessellationShaderID)
|
||||||
|
glDeleteShader(tessellationShaderID);
|
||||||
|
glDeleteShader(fragmentShaderID);
|
||||||
|
|
||||||
|
// delete the Shader program
|
||||||
|
glDeleteProgram(programID);
|
||||||
|
}
|
||||||
|
|
||||||
|
shader::shader(shader&& move) noexcept {
|
||||||
|
// the move constructor doesn't need to construct a new shader but it does need to ensure all old variables are moved over
|
||||||
|
programID = move.programID;
|
||||||
|
vertexShaderID = move.vertexShaderID;
|
||||||
|
fragmentShaderID = move.fragmentShaderID;
|
||||||
|
geometryShaderID = move.geometryShaderID;
|
||||||
|
tessellationShaderID = move.tessellationShaderID;
|
||||||
|
for (const auto& pair : move.uniformVars)
|
||||||
|
uniformVars.insert(pair);
|
||||||
|
// by setting the program ID to -1 we tell the shader it has been moved.
|
||||||
|
move.programID = -1;
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* Created by Brett on 30/03/23.
|
||||||
|
* Licensed under GNU General Public License V3.0
|
||||||
|
* See LICENSE file for license detail
|
||||||
|
*/
|
||||||
|
#include <high_perf/gl_util.h>
|
||||||
|
#include <modes/high_perf.h>
|
||||||
|
#include <util.h>
|
||||||
|
#include <camera.h>
|
||||||
|
#include "blt/std/memory.h"
|
||||||
|
#include <shaders/vertex.vert>
|
||||||
|
#include <shaders/fragment.frag>
|
||||||
|
|
||||||
|
//static inline float degreesToRadian(float deg) {
|
||||||
|
// return deg * (float)M_PI / 180.0f;
|
||||||
|
//}
|
||||||
|
|
||||||
|
blt::mat4x4 createViewMatrix(){
|
||||||
|
auto position = cam.getPosition();
|
||||||
|
auto rotation = cam.getRotation();
|
||||||
|
|
||||||
|
blt::mat4x4 viewMatrix;
|
||||||
|
|
||||||
|
viewMatrix.rotateX(rotation.y() * TO_RAD);
|
||||||
|
viewMatrix.rotateY(rotation.z() * TO_RAD);
|
||||||
|
viewMatrix.translate(-position);
|
||||||
|
|
||||||
|
return viewMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
void window_resize(int width, int height) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint particleTranslationsVBO;
|
||||||
|
GLuint verticesVBO;
|
||||||
|
GLuint uvsVBO;
|
||||||
|
GLuint indicesEBO;
|
||||||
|
GLuint particleVAO;
|
||||||
|
|
||||||
|
const unsigned int particle_count = 25000000;
|
||||||
|
|
||||||
|
// generally alignment to multiples of 4 floats helps performance, plus we can use that extra space for info we need.
|
||||||
|
typedef struct {
|
||||||
|
// x y z (texture index)
|
||||||
|
vec4 pos;
|
||||||
|
// dx dy dz (unused)
|
||||||
|
vec4 dir;
|
||||||
|
} particle_record;
|
||||||
|
|
||||||
|
const float vertices[] = {
|
||||||
|
0.5f, 0.5f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.0f,
|
||||||
|
-0.5f, -0.5f, 0.0f,
|
||||||
|
-0.5f, 0.5f, 0.0f
|
||||||
|
};
|
||||||
|
const float uvs[] = {
|
||||||
|
0, 0,
|
||||||
|
0, 1,
|
||||||
|
1, 1,
|
||||||
|
1, 0
|
||||||
|
};
|
||||||
|
const unsigned int indices[] = {
|
||||||
|
0, 1, 3,
|
||||||
|
1, 2, 3
|
||||||
|
};
|
||||||
|
|
||||||
|
blt::mat4x4 perspectiveMatrix;
|
||||||
|
blt::mat4x4 viewMatrix;
|
||||||
|
|
||||||
|
shader* instance_shader;
|
||||||
|
|
||||||
|
void updateView() {
|
||||||
|
viewMatrix = createViewMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void render() {
|
||||||
|
updateView();
|
||||||
|
perspectiveMatrix = blt::perspective(FOV, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 0.1f, 1000.0f);
|
||||||
|
auto pvm = perspectiveMatrix * viewMatrix;
|
||||||
|
|
||||||
|
instance_shader->bind();
|
||||||
|
instance_shader->setMatrix("pvm", pvm);
|
||||||
|
|
||||||
|
glBindVertexArray(particleVAO);
|
||||||
|
glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, particle_count);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
blt::scoped_buffer<particle_record> translations{particle_count};
|
||||||
|
blt::random<float> pos{-50.0, 50.0};
|
||||||
|
|
||||||
|
for (int i = 0; i < particle_count; i++)
|
||||||
|
translations[i] = particle_record{vec4{pos.get(), pos.get() / 2, pos.get(), (float)(i % 10)}, vec4{0, 0, 0, 0}};
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// Create OpenGL Objects
|
||||||
|
// ----------------------------------
|
||||||
|
// create our VAO
|
||||||
|
glGenVertexArrays(1, &particleVAO);
|
||||||
|
// create our VBOs
|
||||||
|
glGenBuffers(1, &particleTranslationsVBO);
|
||||||
|
glGenBuffers(1, &verticesVBO);
|
||||||
|
glGenBuffers(1, &uvsVBO);
|
||||||
|
glGenBuffers(1, &indicesEBO);
|
||||||
|
|
||||||
|
glBindVertexArray(particleVAO);
|
||||||
|
|
||||||
|
// bind and upload vertices data to the GPU
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, verticesVBO);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 12, vertices, GL_STATIC_DRAW);
|
||||||
|
// tell OpenGL how to handle the vertex data when rendering the VAO, the vertices will be bound to slot 0.
|
||||||
|
// (we will tell OpenGL what variable uses slot 0 in the shader!)
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*) 0);
|
||||||
|
// tell OpenGL we will be using the first VAO slot, prevents us from having to call it before rendering
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, uvsVBO);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, uvs, GL_STATIC_DRAW);
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, (void*) 0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
int translations_size = sizeof(particle_record) * particle_count;
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, particleTranslationsVBO);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, translations_size, translations.buffer, GL_DYNAMIC_DRAW); // allocate some memory on the GPU
|
||||||
|
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(particle_record), (void*) 0);
|
||||||
|
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(particle_record), (void*) offsetof(particle_record, dir));
|
||||||
|
// tells opengl that we want to present this data per 1 instance instead of per vertex.
|
||||||
|
glVertexAttribDivisor(2, 1);
|
||||||
|
glVertexAttribDivisor(3, 1);
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
glEnableVertexAttribArray(3);
|
||||||
|
|
||||||
|
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesEBO);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(float) * 6, indices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
|
||||||
|
instance_shader = new shader(shader_vert, shader_frag, "", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup() {
|
||||||
|
// cleanup opengl resources
|
||||||
|
glDeleteVertexArrays(1, &particleVAO);
|
||||||
|
glDeleteBuffers(1, &particleTranslationsVBO);
|
||||||
|
glDeleteBuffers(1, &verticesVBO);
|
||||||
|
glDeleteBuffers(1, &uvsVBO);
|
||||||
|
glDeleteBuffers(1, &indicesEBO);
|
||||||
|
|
||||||
|
delete(instance_shader);
|
||||||
|
}
|
24
src/main.cpp
24
src/main.cpp
|
@ -1,10 +1,12 @@
|
||||||
#define GLAD_GL_IMPLEMENTATION
|
#define GLAD_GL_IMPLEMENTATION
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#ifdef EXTRAS
|
#ifdef EXTRAS
|
||||||
#include <modes/advanced.h>
|
//#include <modes/basic.h>
|
||||||
|
#include <modes/high_perf.h>
|
||||||
#else
|
#else
|
||||||
#include <modes/basic.h>
|
#include <modes/basic.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <camera.h>
|
#include <camera.h>
|
||||||
#include <blt/std/logging.h>
|
#include <blt/std/logging.h>
|
||||||
|
|
||||||
|
@ -40,6 +42,16 @@ void render_i(){
|
||||||
updateView();
|
updateView();
|
||||||
|
|
||||||
render();
|
render();
|
||||||
|
|
||||||
|
#ifdef EXTRAS
|
||||||
|
std::stringstream str;
|
||||||
|
str << WINDOW_TITLE;
|
||||||
|
str << " | Particle Count: ";
|
||||||
|
str << particle_count;
|
||||||
|
str << " | FPS: ";
|
||||||
|
str << 1000000000.0 / (double)getDelta();
|
||||||
|
glutSetWindowTitle(str.str().c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
glutSwapBuffers();
|
glutSwapBuffers();
|
||||||
cam.inputUpdate();
|
cam.inputUpdate();
|
||||||
|
@ -55,7 +67,6 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
blt::logging::init(logging_properties);
|
blt::logging::init(logging_properties);
|
||||||
|
|
||||||
|
|
||||||
// BLT logging functions are designed to operate one call per line of text. Thus use formatting for all uses
|
// BLT logging functions are designed to operate one call per line of text. Thus use formatting for all uses
|
||||||
// (\n is implicitly added, if the last character in the format string is \n, it will be ignored!)
|
// (\n is implicitly added, if the last character in the format string is \n, it will be ignored!)
|
||||||
// (\n\n will for instance insert one extra line between the current line and the next, not two!)
|
// (\n\n will for instance insert one extra line between the current line and the next, not two!)
|
||||||
|
@ -83,9 +94,14 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
// create the display
|
// create the display
|
||||||
glutInit(&argc, argv);
|
glutInit(&argc, argv);
|
||||||
|
#ifdef EXTRAS
|
||||||
|
glutInitContextVersion(4, 6);
|
||||||
|
glutInitContextProfile(GLUT_CORE_PROFILE);
|
||||||
|
glutInitContextFlags(GLUT_FORWARD_COMPATIBLE);
|
||||||
|
#endif
|
||||||
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
|
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||||
glutSetOption(GLUT_MULTISAMPLE, 8);
|
glutSetOption(GLUT_MULTISAMPLE, 8);
|
||||||
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE | GLUT_DEPTH);
|
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_MULTISAMPLE | GLUT_DEPTH);
|
||||||
glutCreateWindow(WINDOW_TITLE.c_str());
|
glutCreateWindow(WINDOW_TITLE.c_str());
|
||||||
BLT_DEBUG("Window successfully created!");
|
BLT_DEBUG("Window successfully created!");
|
||||||
|
|
||||||
|
@ -161,7 +177,7 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
fountain = new particle_system({0, 1, 0}, {0, 1, 0}, 4.5, 100);
|
fountain = new particle_system({0, 1, 0}, {0, 1, 0}, 4.5, 5000);
|
||||||
|
|
||||||
BLT_DEBUG("Resource initialization complete!");
|
BLT_DEBUG("Resource initialization complete!");
|
||||||
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
* Created by Brett on 30/03/23.
|
|
||||||
* Licensed under GNU General Public License V3.0
|
|
||||||
* See LICENSE file for license detail
|
|
||||||
*/
|
|
||||||
#include <modes/advanced.h>
|
|
||||||
|
|
||||||
#ifdef EXTRAS
|
|
||||||
|
|
||||||
void window_resize(int width, int height) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateView() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void render() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void init() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void cleanup() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue