Compare commits

..

10 Commits

Author SHA1 Message Date
7a218edcce 08: Add first particle system prototype
Also update the README.md
2023-12-23 17:09:43 +01:00
351286d16a 07: Extend and play around with batching 2023-12-16 01:33:13 +01:00
6fdbcc8825 07: Add basic boilerplate for batching 2023-12-15 21:43:42 +01:00
ced87e0af1 06 GUI: add button text + basic alignment 2023-12-06 23:38:38 +01:00
0xdeadbeer
cad444e05d 06 GUI: refactor button code and add basic scenes 2023-12-06 22:15:20 +01:00
0xdeadbeer
8a99476507 Update README.md file 2023-12-05 23:38:12 +01:00
0xdeadbeer
ae2c68bb24 06: initialize basic GUI with button functionality 2023-12-05 23:36:59 +01:00
0xdeadbeer
727d3535ba 06: add introduction to monogame 2023-12-05 17:18:36 +01:00
0xdeadbeer
8455ffac2e 05: refactor code and implement dynamic buffers 2023-12-03 11:55:15 +01:00
0xdeadbeer
67aa648299 05: Bootstrap basic OpenGL project 2023-12-01 00:36:23 +01:00
122 changed files with 27113 additions and 6 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ build/
*.o *.o
compile_commands.json compile_commands.json
.idea/ .idea/
bin/

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "06-monogame/Introduction/themes/hugo-bearcub"]
path = 06-monogame/Introduction/themes/hugo-bearcub
url = https://github.com/clente/hugo-bearcub

BIN
.imgs/monogame.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
.imgs/opengl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 105 KiB

View File

@ -1,6 +1,6 @@
<!-- <p align="center"> --> <p align="center">
<!-- <img src=".imgs/showcase.png" width="300" /> --> <img src=".imgs/showcase.png" width="300" />
<!-- </p> --> </p>
# Map # Map

29
05-opengl/Makefile Normal file
View File

@ -0,0 +1,29 @@
CC=g++
CFLAGS=-std=c++20 `pkg-config --cflags glfw3 glew glm`
LDFLAGS=`pkg-config --libs glfw3 glew glm`
INCLUDE=/usr/include/stb/
TARGET=opengl
SDIR=src
ADIR=assets
ODIR=build
SRC=$(shell find $(SDIR) -type f -name *.cpp)
OBJ=$(SRC:.cpp=.o)
all: $(TARGET)
.PHONY: default
$(TARGET): $(OBJ)
mkdir -p build
cp -rf $(ADIR) $(ODIR)/$(ADIR)
$(CC) -o $(ODIR)/$@ $^ $(LDFLAGS)
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $<
run:
$(ODIR)/$(TARGET)
.PHONY: clean
clean:
rm -f $(ODIR)/$(TARGET) $(OBJ)

3
05-opengl/README.md Normal file
View File

@ -0,0 +1,3 @@
# Opengl
Playing with Opengl because I realized SDL2 is not enough :/

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,13 @@
#version 330 core
out vec4 color;
in vec2 tex_coord;
uniform sampler2D sampler;
void main() {
color = texture(sampler, tex_coord);
// color = vec4(1.0, 0.0, 0.0, 1.0);
if (color.a < 0.1)
discard;
}

View File

@ -0,0 +1,14 @@
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texture_coord;
uniform mat4 view;
uniform mat4 projection;
out vec2 tex_coord;
void main() {
gl_Position = projection * view * vec4(pos.xyz, 1.0);
tex_coord = texture_coord;
}

22
05-opengl/src/common.cpp Normal file
View File

@ -0,0 +1,22 @@
#include <iostream>
#include <fstream>
#include "common.hpp"
std::string read_file(const char *path) {
std::string content;
std::ifstream fs(path, std::ios::in);
if(!fs.is_open()) {
std::cerr << "Error: Could not read file " << path << ". File does not exist." << std::endl;
return NULL;
}
std::string line = "";
while(!fs.eof()) {
std::getline(fs, line);
content.append(line + "\n");
}
fs.close();
return content;
}

5
05-opengl/src/common.hpp Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <string>
std::string read_file(const char *path);

172
05-opengl/src/game.cpp Normal file
View File

@ -0,0 +1,172 @@
#include <iostream>
#include <fstream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/mat4x4.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "game.hpp"
#include "texture.hpp"
#include "sprite.hpp"
#include "other/stb_image.h"
Game::Game(GLFWwindow *window) {
this->window = window;
this->program = Program();
stbi_set_flip_vertically_on_load(true);
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &this->texture_slots);
}
// code this later lol
int Game::setup(int initial_width, int initial_height) {
glfwSetKeyCallback(this->window, Game::input_callback);
glfwSetFramebufferSizeCallback(this->window, Game::resize_callback);
Game::resize_callback(this->window, initial_width, initial_height);
int ret = this->program.add_shader("assets/shaders/vertex.glsl", GL_VERTEX_SHADER);
if (ret != 0) {
std::cout << "Error: failed adding vertex shader" << std::endl;
return -1;
}
ret = this->program.add_shader("assets/shaders/fragment.glsl", GL_FRAGMENT_SHADER);
if (ret != 0) {
std::cout << "Error: failed adding fragment shader" << std::endl;
return -1;
}
if (this->program.link() != 0) {
std::cout << "Error: failed linking program" << std::endl;
return -1;
}
glUseProgram(this->program.id);
glGenVertexArrays(1, &this->vao);
glGenBuffers(1, &this->vbo);
glGenBuffers(1, &this->ebo);
glBindVertexArray(this->vao);
glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ebo);
return 0;
}
void Game::run() {
this->counter = 0;
this->vbo_offset = 0;
this->ebo_offset = 0;
Sprite sprite("assets/player/idle.png", SPLIT_TEXTURE);
sprite.bake();
this->sprites.push_back(&sprite);
glBindVertexArray(this->vao);
glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ebo);
glBufferData(GL_ARRAY_BUFFER, sizeof(struct vertex) * 4 * this->texture_slots, nullptr, GL_DYNAMIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * 6 * this->texture_slots, nullptr, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void *) offsetof(vertex, position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void *) offsetof(vertex, texture));
glEnableVertexAttribArray(1);
Game::logic();
}
void Game::input_callback(GLFWwindow *window, int key, int scancode, int action, int mods) {
if (action != GLFW_PRESS)
return;
switch (key) {
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, true);
break;
default:
break;
}
}
void Game::resize_callback(GLFWwindow *window, int new_width, int new_height) {
glViewport(0, 0, new_width, new_height);
}
void Game::logic() {
while (!glfwWindowShouldClose(this->window)) {
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
for (int sprite = 0; sprite < this->sprites.size(); sprite++, counter++) {
Game::load(this->sprites[sprite], this->counter);
std::cout << "Counter: " << counter << " Texture slots: " << this->texture_slots << std::endl;
if (counter > 0 && counter % this->texture_slots == 0) {
Game::draw();
this->counter = 0;
this->vbo_offset = 0;
this->ebo_offset = 0;
}
}
Game::draw();
this->counter = 0;
this->vbo_offset = 0;
this->ebo_offset = 0;
glfwPollEvents();
glfwSwapBuffers(this->window);
}
glBindVertexArray(0);
}
void Game::load(Sprite *sprite, int count) {
unsigned int program = this->program.id;
glUseProgram(program);
glUniform1i(glGetUniformLocation(program, "sampler"), count);
glBufferSubData(GL_ARRAY_BUFFER, vbo_offset, sizeof(struct vertex) * sprite->vertices.size(), sprite->vertices.data());
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, ebo_offset, sizeof(int) * sprite->indices.size(), sprite->indices.data());
vbo_offset += sizeof(struct vertex) * sprite->vertices.size();
ebo_offset += sizeof(int) * sprite->indices.size();
glActiveTexture(GL_TEXTURE0 + count);
glBindTexture(GL_TEXTURE_2D, sprite->texture.texture_id);
}
void Game::draw() {
unsigned int program = this->program.id;
glUseProgram(program);
glm::mat4 view = glm::mat4(1.0f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
glm::mat4 projection = glm::mat4(1.0f);
int width, height;
float half_width, half_height;
glfwGetWindowSize(this->window, &width, &height);
half_width = (float) width / 2;
half_height = (float) height / 2;
projection = glm::ortho(-half_width/100, half_width/100, -half_height/100, half_height/100, 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(program,"view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glDrawElements(GL_TRIANGLES, this->sprites[0]->indices.size(), GL_UNSIGNED_INT, 0);
std::cout << "Error: " << glGetError() << std::endl;
}

34
05-opengl/src/game.hpp Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <iostream>
#include <vector>
#include <GLFW/glfw3.h>
#include "program.hpp"
#include "sprite.hpp"
class Game {
public:
Game(GLFWwindow *window);
int setup(int initial_width, int initial_height);
void run();
void logic();
void load(Sprite *sprite, int counter);
void draw();
// callbacks
static void input_callback(GLFWwindow *window, int key, int scancode, int action, int mods);
static void resize_callback(GLFWwindow *window, int new_width, int new_height);
GLFWwindow *window;
Program program;
std::vector<Sprite *> sprites;
int texture_slots;
unsigned int vao;
unsigned int vbo;
unsigned int ebo;
unsigned int counter;
unsigned int vbo_offset;
unsigned int ebo_offset;
};

40
05-opengl/src/main.cpp Normal file
View File

@ -0,0 +1,40 @@
#include <iostream>
#include <fstream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stb/stb_image.h>
#include "game.hpp"
int initial_width = 1000;
int initial_height = 600;
std::string vertex_shader_location = "assets/shaders/shader.vert";
std::string fragment_shader_location = "assets/shaders/shader.frag";
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow *window = glfwCreateWindow(initial_width, initial_height, "OpenGL", NULL, NULL);
if (window == NULL) {
std::cout << "Error: failed creating window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
GLenum err = glewInit();
if (err != GLEW_OK) {
std::cout << "Error: failed initializing glew " << glewGetErrorString(err) << std::endl;
return -1;
}
Game main_game(window);
main_game.setup(initial_width, initial_height);
main_game.run();
glfwTerminate();
return 0;
}

View File

@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

File diff suppressed because it is too large Load Diff

38
05-opengl/src/program.cpp Normal file
View File

@ -0,0 +1,38 @@
#include <iostream>
#include <GL/glew.h>
#include "program.hpp"
Program::Program() {
this->id = glCreateProgram();
}
int Program::add_shader(const char *path, unsigned int type) {
Shader new_shader;
unsigned int ret = new_shader.load(path, type);
if (!ret)
return -1;
this->shaders.push_back(new_shader);
return 0;
}
int Program::link() {
for (int shader = 0; shader < this->shaders.size(); shader++)
glAttachShader(this->id, this->shaders[shader].id);
glLinkProgram(this->id);
int success;
char info_log[512];
glGetProgramiv(this->id, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(this->id, 512, NULL, info_log);
std::cout << "Error: failed linking program. " << info_log << std::endl;
return -1;
}
return 0;
}

13
05-opengl/src/program.hpp Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <vector>
#include "shader.hpp"
struct Program {
unsigned int id;
std::vector<Shader> shaders;
Program();
int add_shader(const char *path, unsigned int type);
int link();
};

31
05-opengl/src/shader.cpp Normal file
View File

@ -0,0 +1,31 @@
#include <iostream>
#include <GL/glew.h>
#include "shader.hpp"
#include "common.hpp"
unsigned int Shader::load(const char *path, unsigned int type) {
std::string source_s = read_file(path);
const char *source = source_s.c_str();
unsigned int new_shader = glCreateShader(type);
if (!new_shader)
return 0;
glShaderSource(new_shader, 1, &source, NULL);
glCompileShader(new_shader);
int success;
char info_log[512];
glGetShaderiv(new_shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(new_shader, 512, NULL, info_log);
std::cout << "Error: failed compiling new shader " << info_log << std::endl;
return 0;
}
this->id = new_shader;
this->type = type;
return new_shader;
}

8
05-opengl/src/shader.hpp Normal file
View File

@ -0,0 +1,8 @@
#pragma once
struct Shader {
unsigned int id;
unsigned int type;
unsigned int load(const char *path, unsigned int type);
};

59
05-opengl/src/sprite.cpp Normal file
View File

@ -0,0 +1,59 @@
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <stb/stb_image.h>
#include "game.hpp"
#include "sprite.hpp"
Sprite::Sprite(const char *path, enum TextureType type) : texture(type) {
int image_width;
int image_height;
int image_resolution;
int image_channels;
unsigned char *image_bytes = stbi_load(path, &image_width, &image_height, &image_channels, 0);
if (image_bytes == NULL) {
std::cout << "Error: failed loading image data" << std::endl;
return;
}
this->texture.bind_texture();
this->texture.load_data(image_bytes, image_width, image_height, image_height);
stbi_image_free(image_bytes);
this->pos = glm::vec3(0.0f);
this->size = glm::vec3(1.0f);
this->rot = glm::vec3(0.0f);
}
void Sprite::bake() {
struct vertex v1 = { {0.5f, 0.5f, 0.0f}, {1.0f, 1.0f} };
struct vertex v2 = { {0.5f, -0.5f, 0.0f}, {1.0f, 0.0f} };
struct vertex v3 = { {-0.5f, -0.5f, 0.0f}, {0.0f, 0.0f} };
struct vertex v4 = { {-0.5f, 0.5f, 0.0f}, {0.0f, 1.0f} };
this->vertices.push_back(v1);
this->vertices.push_back(v2);
this->vertices.push_back(v3);
this->vertices.push_back(v4);
this->indices = {
0, 1, 3,
1, 2, 3
};
Texture &tex = this->texture;
if (tex.type == SPLIT_TEXTURE) {
for (int i = 0; i < this->vertices.size(); i++) {
struct vertex *v = &this->vertices[i];
float tex_x = ((tex.cell_x + v->texture[0]) * tex.cell_res) / tex.texture_width;
float tex_y = ((tex.cell_y + v->texture[1]) * tex.cell_res) / tex.texture_height;
v->texture[0] = tex_x;
v->texture[1] = tex_y;
}
}
}

29
05-opengl/src/sprite.hpp Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <vector>
#include <glm/vec3.hpp>
#include "texture.hpp"
class Game;
class Texture;
struct vertex {
float position[3];
float texture[2];
};
class Sprite {
public:
Texture texture;
glm::vec3 pos;
glm::vec3 size;
glm::vec3 rot;
std::vector<struct vertex> vertices;
std::vector<int> indices;
Game *game;
Sprite(const char *path, enum TextureType type);
void bake();
};

29
05-opengl/src/texture.cpp Normal file
View File

@ -0,0 +1,29 @@
#include <GL/glew.h>
#include "texture.hpp"
Texture::Texture(enum TextureType type) {
glGenTextures(1, &this->texture_id);
this->type = type;
this->cell_x = 0;
this->cell_y = 0;
this->cell_res = 0;
}
void Texture::bind_texture() {
glBindTexture(GL_TEXTURE_2D, this->texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
void Texture::load_data(unsigned char *bytes, int width, int height, int cell_res) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bytes);
glGenerateMipmap(GL_TEXTURE_2D);
this->texture_width = width;
this->texture_height = height;
this->cell_res = cell_res;
}

24
05-opengl/src/texture.hpp Normal file
View File

@ -0,0 +1,24 @@
#pragma once
enum TextureType {
FULL_TEXTURE,
SPLIT_TEXTURE,
DYNAMIC_TEXTURE
};
class Texture {
public:
unsigned int texture_id;
Texture(enum TextureType type);
void bind_texture();
void load_data(unsigned char *bytes, int width, int height, int cell_res);
enum TextureType type;
int texture_width;
int texture_height;
int cell_res;
int cell_x;
int cell_y;
};

43
06-monogame/.gitignore vendored Normal file
View File

@ -0,0 +1,43 @@
*.swp
*.*~
project.lock.json
.DS_Store
*.pyc
nupkg/
# Visual Studio Code
.vscode/
# Rider
.idea/
# Visual Studio
.vs/
# Fleet
.fleet/
# Code Rush
.cr/
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
msbuild.log
msbuild.err
msbuild.wrn

View File

@ -0,0 +1,36 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-mgcb": {
"version": "3.8.1.303",
"commands": [
"mgcb"
]
},
"dotnet-mgcb-editor": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor"
]
},
"dotnet-mgcb-editor-linux": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor-linux"
]
},
"dotnet-mgcb-editor-windows": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor-windows"
]
},
"dotnet-mgcb-editor-mac": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor-mac"
]
}
}
}

View File

@ -0,0 +1,46 @@
#----------------------------- Global Properties ----------------------------#
/outputDir:bin/$(Platform)
/intermediateDir:obj/$(Platform)
/platform:DesktopGL
/config:
/profile:Reach
/compress:False
#-------------------------------- References --------------------------------#
#---------------------------------- Content ---------------------------------#
#begin button-default-texture.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:button-default-texture.png
#begin button.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:button.png
#begin Fonts/default.spritefont
/importer:FontDescriptionImporter
/processor:LocalizedFontProcessor
/processorParam:PremultiplyAlpha=True
/processorParam:TextureFormat=Compressed
/build:Fonts/default.spritefont

Binary file not shown.

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
<Asset Type="Graphics:LocalizedFontDescription">
<!--
Modify this string to change the font that will be imported.
-->
<FontName>HackNerdFont.ttf</FontName>
<!--
Size is a float value, measured in points. Modify this value to change
the size of the font.
-->
<Size>12</Size>
<!--
Spacing is a float value, measured in pixels. Modify this value to change
the amount of spacing in between characters.
-->
<Spacing>0</Spacing>
<!--
UseKerning controls the layout of the font. If this value is true, kerning information
will be used when placing characters.
-->
<UseKerning>true</UseKerning>
<!--
Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
and "Bold, Italic", and are case sensitive.
-->
<Style>Regular</Style>
<!--
If you uncomment this line, the default character will be substituted if you draw
or measure text that contains characters which were not included in the font.
-->
<DefaultCharacter>A</DefaultCharacter>
<!--
CharacterRegions control what letters are available in the font. Every
character from Start to End will be built and made available for drawing. The
default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
character set. The characters are ordered according to the Unicode standard.
See the documentation for more information.
For localized fonts you can leave this empty as the character range will be picked up
from the Resource Files.
-->
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#8364;</End>
</CharacterRegion>
</CharacterRegions>
<!--
ResourceFiles control the characters which will be in the font. It does this
by scanning the text in each of the resource files and adding those specific
characters to the font.
-->
<ResourceFiles>
<!-- <Resx>Strings.resx</Resx> -->
</ResourceFiles>
</Asset>
</XnaContent>

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RollForward>Major</RollForward>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Icon.ico" />
<None Remove="Icon.bmp" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icon.ico" />
<EmbeddedResource Include="Icon.bmp" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
</ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
<Message Text="Restoring dotnet tools" Importance="High" />
<Exec Command="dotnet tool restore" />
</Target>
</Project>

73
06-monogame/GUI/Game1.cs Normal file
View File

@ -0,0 +1,73 @@
using System;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using GUI.UIElements;
namespace GUI;
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
private Scene mainScene;
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void Initialize()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
Scene.graphics = _graphics;
Scene.spriteBatch = _spriteBatch;
Scene.content = Content;
mainScene = new Scene();
DrawableData drawableData = new DrawableData("button");
drawableData.position = new Vector2(100.0f, 100.0f);
void buttonOnClick(Button obj)
{
Console.WriteLine("ACTION CALLED SUCCESSFULLY!");
}
ButtonData buttonData = new ButtonData(buttonOnClick);
buttonData.text = "Click me!";
Button mainButton = new Button(drawableData, buttonData);
mainScene.drawables.Add(mainButton);
mainScene.Initialize();
base.Initialize();
}
protected override void LoadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
mainScene.Update(gameTime);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
mainScene.Draw(gameTime);
base.Draw(gameTime);
}
}

BIN
06-monogame/GUI/Icon.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
06-monogame/GUI/Icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View File

@ -0,0 +1,3 @@

using var game = new GUI.Game1();
game.Run();

View File

@ -0,0 +1,176 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Vector2 = Microsoft.Xna.Framework.Vector2;
namespace GUI.UIElements;
public class ButtonData
{
public Color bgColor;
public Color fgColor;
public Color? hoverBgColor;
public Color? hoverFgColor;
public Color? pressedBgColor;
public Color? pressedFgColor;
public Color idleBgColor = Color.Black;
public Color idleFgColor = Color.White;
public bool isPressed = false;
public bool isReleased = false;
public bool isHovered = false;
public bool isIdle = false;
public Action<Button>? onClick;
public string text = "";
public Vector2 textPosition;
public Vector2 textResolution;
public Vector2 textScale;
public ButtonData(Action<Button>? onClick)
{
this.onClick = onClick;
}
}
public class Button : Drawable
{
private DrawableData _drawableData;
public ButtonData _buttonData;
private SpriteFont buttonFont;
public Button(DrawableData data, ButtonData buttonData)
{
_drawableData = data;
_buttonData = buttonData;
}
public override void Initialize()
{
buttonFont = Scene.content.Load<SpriteFont>("Fonts/default");
}
void onPressed()
{
if (_buttonData.isPressed)
return;
_buttonData.bgColor = _buttonData.pressedBgColor ?? _buttonData.idleBgColor;
_buttonData.fgColor = _buttonData.pressedFgColor ?? _buttonData.idleFgColor;
if (_buttonData.onClick is not null)
_buttonData.onClick(this);
_buttonData.isReleased = false;
_buttonData.isPressed = true;
}
void onReleased()
{
if (!_buttonData.isPressed)
return;
_buttonData.bgColor = _buttonData.hoverBgColor ?? _buttonData.idleBgColor;
_buttonData.fgColor = _buttonData.hoverFgColor ?? _buttonData.idleFgColor;
_buttonData.isPressed = false;
_buttonData.isReleased = true;
}
void onHovered()
{
if (_buttonData.isHovered)
return;
_buttonData.bgColor = _buttonData.hoverBgColor ?? _buttonData.idleBgColor;
_buttonData.fgColor = _buttonData.hoverFgColor ?? _buttonData.idleFgColor;
_buttonData.isHovered = true;
}
void onIdle()
{
_buttonData.bgColor = _buttonData.idleBgColor;
_buttonData.fgColor = _buttonData.idleFgColor;
_buttonData.isPressed = false;
_buttonData.isReleased = false;
_buttonData.isHovered = false;
}
public void buttonLogic()
{
var mstate = Mouse.GetState();
Vector2 mousePosition = mstate.Position.ToVector2();
bool outsideHorizontalBoundary = (mousePosition.X < _drawableData.position.X) || (mousePosition.X > (_drawableData.position.X + _drawableData.scale.X));
bool outsideVerticalBoundary = (mousePosition.Y < _drawableData.position.Y) || (mousePosition.Y > (_drawableData.position.Y + _drawableData.scale.Y));
if (outsideHorizontalBoundary || outsideVerticalBoundary)
{
onIdle();
return;
}
if (mstate.LeftButton == ButtonState.Pressed)
{
onPressed();
return;
}
if (mstate.LeftButton == ButtonState.Released)
{
onReleased();
}
onHovered();
}
public override void Update(GameTime gameTime)
{
buttonLogic();
_buttonData.textResolution = buttonFont.MeasureString(_buttonData.text);
// we want to center the text so
Vector2 buttonCenter = (_drawableData.position + (Vector2.One / 2.0f));
Vector2 textHalfResolution = _buttonData.textResolution / 2.0f;
_buttonData.textPosition = buttonCenter - textHalfResolution;
}
public override void Draw(GameTime gameTime)
{
Scene.spriteBatch.Draw(
_drawableData.texture,
_drawableData.position,
null,
Color.White,
_drawableData.rotation,
Vector2.Zero,
_drawableData.scale,
SpriteEffects.None,
0f
);
Scene.spriteBatch.DrawString(
buttonFont,
_buttonData.text,
_buttonData.textPosition,
_buttonData.fgColor,
_drawableData.rotation,
Vector2.Zero,
_drawableData.scale,
SpriteEffects.None,
0f,
false
);
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Data;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace GUI.UIElements;
public class DrawableData
{
public Texture2D texture;
public Vector2 position = Vector2.Zero;
private Vector2 scale_multiplier = Vector2.One;
public Vector2 scale
{
get { return scale_multiplier * new Vector2(texture.Width, texture.Height); }
set
{
scale_multiplier = value;
}
}
public float rotation = 0.0f;
public DrawableData(string? texture)
{
if (texture is not null)
{
this.texture = Scene.content.Load<Texture2D>(texture);
return;
}
this.texture = Scene.content.Load<Texture2D>("button-default-texture");
}
}
public enum DrawableType
{
Container,
Text,
Button,
}
public abstract class Drawable
{
public DrawableType drawableType;
public abstract void Initialize();
public abstract void Update(GameTime gameTime);
public abstract void Draw(GameTime gameTime);
}

View File

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace GUI.UIElements;
public class Scene
{
private static ContentManager? _content;
public static ContentManager content
{
get { return _content; }
set
{
if (_content is not null)
return;
_content = value;
}
}
private static GraphicsDeviceManager? _graphics;
public static GraphicsDeviceManager graphics
{
get { return _graphics; }
set
{
if (_graphics is not null)
return;
_graphics = value;
}
}
private static SpriteBatch? _spriteBatch;
public static SpriteBatch spriteBatch
{
get { return _spriteBatch; }
set
{
if (_spriteBatch is not null)
return;
_spriteBatch = value;
}
}
public List<Drawable> drawables;
public Scene()
{
drawables = new List<Drawable>();
}
public void Initialize()
{
foreach (Drawable drawable in drawables)
drawable.Initialize();
}
public void Update(GameTime gameTime)
{
foreach (Drawable drawable in drawables)
drawable.Update(gameTime);
}
public void Draw(GameTime gameTime)
{
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
foreach (Drawable drawable in drawables)
drawable.Draw(gameTime);
spriteBatch.End();
}
}

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="GUI"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on and is
is designed to work with. Uncomment the appropriate elements and Windows will
automatically selected the most compatible environment. -->
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

View File

@ -0,0 +1,36 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-mgcb": {
"version": "3.8.1.303",
"commands": [
"mgcb"
]
},
"dotnet-mgcb-editor": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor"
]
},
"dotnet-mgcb-editor-linux": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor-linux"
]
},
"dotnet-mgcb-editor-windows": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor-windows"
]
},
"dotnet-mgcb-editor-mac": {
"version": "3.8.1.303",
"commands": [
"mgcb-editor-mac"
]
}
}
}

View File

@ -0,0 +1,100 @@
using System;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Vector2 = Microsoft.Xna.Framework.Vector2;
namespace Introduction;
public class Character
{
public Texture2D texture;
public Texture2D noise;
public Vector2 pos;
public Vector2 scale;
public Vector2 rot;
public float angles;
public float speed;
private bool glitchEnabled = false;
private Effect glitch;
private float time;
public void Initialize()
{
speed = 300.0f;
pos = Vector2.Zero;
scale = new Vector2(1f);
rot = Vector2.UnitX;
angles = 0.0f;
}
public void LoadContent(ContentManager content)
{
texture = content.Load<Texture2D>("player_texture");
noise = content.Load<Texture2D>("noise");
glitch = content.Load<Effect>("glitch");
if (glitch.Parameters["NoiseTexture"] is not null)
glitch.Parameters["NoiseTexture"].SetValue(texture);
if (glitch.Parameters["textureSize"] is not null)
glitch.Parameters["textureSize"].SetValue(new Vector2(texture.Width, texture.Height));
}
public void Update(GameTime gameTime)
{
var kstate = Keyboard.GetState();
if (kstate.IsKeyDown(Keys.W))
{
pos.Y -= speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (kstate.IsKeyDown(Keys.S))
{
pos.Y += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (kstate.IsKeyDown(Keys.A))
{
pos.X -= speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (kstate.IsKeyDown(Keys.D))
{
pos.X += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
if (kstate.IsKeyDown(Keys.K))
{
glitchEnabled = !glitchEnabled;
}
var mstate = Mouse.GetState();
Vector2 mousePosition = new Vector2(mstate.X, mstate.Y);
Vector2 distancePosition = mousePosition - pos;
angles = (float) (Math.Atan2(distancePosition.Y, distancePosition.X));
time += (float) gameTime.ElapsedGameTime.TotalSeconds;
if (glitch.Parameters["Time"] is not null)
glitch.Parameters["Time"].SetValue(time);
}
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
Vector2 origin = new Vector2(texture.Width / 2, texture.Height / 2);
if (glitchEnabled)
glitch.CurrentTechnique.Passes[0].Apply();
else
time = 0;
spriteBatch.Draw(texture, pos, null, Color.White, angles, origin, scale, SpriteEffects.None, 0.0f);
spriteBatch.End();
}
}

View File

@ -0,0 +1,45 @@
#----------------------------- Global Properties ----------------------------#
/outputDir:bin/$(Platform)
/intermediateDir:obj/$(Platform)
/platform:DesktopGL
/config:
/profile:Reach
/compress:False
#-------------------------------- References --------------------------------#
#---------------------------------- Content ---------------------------------#
#begin glitch.fx
/importer:EffectImporter
/processor:EffectProcessor
/processorParam:DebugMode=Auto
/build:glitch.fx
#begin noise.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:noise.png
#begin player_texture.png
/importer:TextureImporter
/processor:TextureProcessor
/processorParam:ColorKeyColor=255,0,255,255
/processorParam:ColorKeyEnabled=True
/processorParam:GenerateMipmaps=False
/processorParam:PremultiplyAlpha=True
/processorParam:ResizeToPowerOfTwo=False
/processorParam:MakeSquare=False
/processorParam:TextureFormat=Color
/build:player_texture.png

View File

@ -0,0 +1,47 @@
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif
matrix WorldViewProjection;
sampler s0 : register (s0);
float Time;
float2 textureSize;
Texture2D NoiseTexture;
sampler2D NoiseSampler = sampler_state
{
Texture = <NoiseTexture>;
};
float4 MainPS(float2 coords: TEXCOORD0) : COLOR0
{
float2 up_limit = float2(0.0, 0.0) + float2(Time, Time);
float2 down_limit = textureSize - float2(Time, Time);
float4 output_col;
if (coords.x < up_limit.x || coords.y < up_limit.y) {
output_col = float4(0.0, 0.0, 0.0, 0.0);
return output_col;
}
if (coords.x > down_limit.x || coords.y > down_limit.y) {
output_col = float4(0.0, 0.0, 0.0, 0.0);
return output_col;
}
return tex2D(s0, coords);
}
technique BasicColorDrawing
{
pass P0
{
PixelShader = compile PS_SHADERMODEL MainPS();
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -0,0 +1,53 @@
using System.Data;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Introduction;
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
private Character player;
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
player = new Character();
}
protected override void Initialize()
{
player.Initialize();
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
player.LoadContent(Content);
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
player.Update(gameTime);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
player.Draw(gameTime, _spriteBatch);
base.Draw(gameTime);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View File

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<RollForward>Major</RollForward>
<PublishReadyToRun>false</PublishReadyToRun>
<TieredCompilation>false</TieredCompilation>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Icon.ico" />
<None Remove="Icon.bmp" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Icon.ico" />
<EmbeddedResource Include="Icon.bmp" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" />
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
</ItemGroup>
<Target Name="RestoreDotnetTools" BeforeTargets="Restore">
<Message Text="Restoring dotnet tools" Importance="High" />
<Exec Command="dotnet tool restore" />
</Target>
</Project>

View File

@ -0,0 +1,3 @@

using var game = new Introduction.Game1();
game.Run();

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="Introduction"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on and is
is designed to work with. Uncomment the appropriate elements and Windows will
automatically selected the most compatible environment. -->
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

28
07-boilerplate/Makefile Normal file
View File

@ -0,0 +1,28 @@
CC=g++
CFLAGS=-std=c++20 `pkg-config --cflags glfw3 glew glm`
LDFLAGS=`pkg-config --libs glfw3 glew glm`
TARGET=boilerplate
SDIR=src
ADIR=assets
ODIR=build
SRC=$(shell find $(SDIR) -type f -name *.cpp)
OBJ=$(SRC:.cpp=.o)
all: $(TARGET)
.PHONY: default
$(TARGET): $(OBJ)
mkdir -p build
cp -rf $(ADIR) $(ODIR)/$(ADIR)
$(CC) -o $(ODIR)/$@ $^ $(LDFLAGS)
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $<
run:
$(ODIR)/$(TARGET)
.PHONY: clean
clean:
rm -f $(ODIR)/$(TARGET) $(OBJ)

8
07-boilerplate/README.md Normal file
View File

@ -0,0 +1,8 @@
<p align="center">
<img src=".imgs/showcase.png" width="300" />
</p>
# Boilerplate
Creating a boilerplate API to abstract away OpenGL.
- Also added my first ever batch renderer

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,12 @@
#version 330 core
in vec4 _color;
in vec2 _texture_position;
in float _ctt;
out vec4 color;
void main() {
// color = texture(sampler, _texture_position);
//color = vec4(1.0, 1.0, 1.0, 1.0);
color = _color;
}

View File

@ -0,0 +1,23 @@
#version 330 core
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 origin;
layout (location = 2) in vec4 color;
layout (location = 3) in vec2 texture_position;
layout (location = 4) in float ctt;
uniform mat4 view_matrix;
uniform mat4 projection_matrix;
out vec4 _color;
out vec2 _texture_position;
out float _ctt;
void main() {
vec3 origined_position = origin.xyz + position.xyz;
gl_Position = projection_matrix * view_matrix * vec4(origined_position, 1.0);
_color = color;
_texture_position = texture_position;
_ctt = ctt;
}

View File

@ -0,0 +1,13 @@
#version 330 core
out vec4 color;
in vec2 tex_coord;
uniform sampler2D sampler;
void main() {
color = texture(sampler, tex_coord);
// color = vec4(1.0, 0.0, 0.0, 1.0);
if (color.a < 0.1)
discard;
}

View File

@ -0,0 +1,14 @@
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texture_coord;
uniform mat4 view;
uniform mat4 projection;
out vec2 tex_coord;
void main() {
gl_Position = projection * view * vec4(pos.xyz, 1.0);
tex_coord = texture_coord;
}

View File

@ -0,0 +1,22 @@
#include <iostream>
#include <fstream>
#include "common.hpp"
std::string read_file(const char *path) {
std::string content;
std::ifstream fs(path, std::ios::in);
if(!fs.is_open()) {
std::cerr << "Error: Could not read file " << path << ". File does not exist." << std::endl;
return NULL;
}
std::string line = "";
while(!fs.eof()) {
std::getline(fs, line);
content.append(line + "\n");
}
fs.close();
return content;
}

View File

@ -0,0 +1,5 @@
#pragma once
#include <string>
std::string read_file(const char *path);

View File

@ -0,0 +1,10 @@
#pragma once
#define DEFAULT_POSITION_ATTRIBUTE 0
#define DEFAULT_ORIGIN_ATTRIBUTE 1
#define DEFAULT_COLOR_ATTRIBUTE 2
#define DEFAULT_TEXTURE_ATTRIBUTE 3
#define DEFAULT_CTT_ATTRIBUTE 4
#define QUAD 6
#define DEFAULT_VBO_SIZE QUAD * 1000000 // unit: rows of RenderData

View File

@ -0,0 +1,38 @@
#include <iostream>
#include <GL/glew.h>
#include "program.hpp"
#include "../macros.hpp"
Program::Program() {
this->id = glCreateProgram();
}
int Program::add_shader(const char *path, unsigned int type) {
Shader new_shader;
unsigned int ret = new_shader.load(path, type);
if (!ret)
return RET_ERR;
this->shaders.push_back(new_shader);
return 0;
}
int Program::link() {
for (int shader = 0; shader < this->shaders.size(); shader++)
glAttachShader(this->id, this->shaders[shader].id);
glLinkProgram(this->id);
int success;
char info_log[512];
glGetProgramiv(this->id, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(this->id, 512, NULL, info_log);
return RET_ERR;
}
return 0;
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <GL/glew.h>
#include <vector>
#include "shader.hpp"
struct Program {
GLuint id;
std::vector<Shader> shaders;
Program();
int add_shader(const char *path, unsigned int type);
int link();
};

View File

@ -0,0 +1,155 @@
#include <optional>
#include <glm/vec3.hpp>
#include <glm/mat4x4.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "renderer.hpp"
#include "../macros.hpp"
#include "graphics.hpp"
Renderer::Renderer(Window &window) : window(window) {
pack = RendererPack();
this->window = window;
glGenBuffers(1, &this->vertex_buffer_id);
glGenVertexArrays(1, &this->array_buffer_id);
this->view_matrix = glm::mat4(1.0f);
this->projection_matrix = glm::mat4(1.0f);
}
int Renderer::setup(std::optional<Program> program) {
int ret;
if (program != std::nullopt)
this->program = program.value();
else {
Program new_program = Program();
ret = new_program.add_shader("assets/shaders/default_vertex.glsl", GL_VERTEX_SHADER);
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed adding vertex shader to program");
return RET_ERR;
}
ret = new_program.add_shader("assets/shaders/default_fragment.glsl", GL_FRAGMENT_SHADER);
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed adding fragment shader to program");
return RET_ERR;
}
ret = new_program.link();
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed linking program");
return RET_ERR;
}
this->program = new_program;
}
glBindVertexArray(this->array_buffer_id);
glBindBuffer(GL_ARRAY_BUFFER, this->vertex_buffer_id);
glBufferData(GL_ARRAY_BUFFER, sizeof(struct RendererData) * DEFAULT_VBO_SIZE, nullptr, GL_DYNAMIC_DRAW);
glVertexAttribPointer(
DEFAULT_POSITION_ATTRIBUTE,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, vertex)
);
glEnableVertexAttribArray(DEFAULT_POSITION_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_ORIGIN_ATTRIBUTE,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, origin)
);
glEnableVertexAttribArray(DEFAULT_ORIGIN_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_COLOR_ATTRIBUTE,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, color)
);
glEnableVertexAttribArray(DEFAULT_COLOR_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_TEXTURE_ATTRIBUTE,
2,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, tex)
);
glEnableVertexAttribArray(DEFAULT_TEXTURE_ATTRIBUTE);
glVertexAttribPointer(
DEFAULT_CTT_ATTRIBUTE,
1,
GL_FLOAT,
GL_FALSE,
sizeof(struct RendererData),
(void *) offsetof(RendererData, ctt_ratio)
);
glEnableVertexAttribArray(DEFAULT_CTT_ATTRIBUTE);
// setup matrices
this->view_matrix = glm::translate(this->view_matrix, glm::vec3(0.0f, 0.0f, -3.0f));
return RET_OK;
}
void Renderer::draw(struct RendererData data) {
if (batch_buffer.size() >= DEFAULT_VBO_SIZE) {
LOG(LOG_WARN, "Batch buffer limit reached!");
return;
}
batch_buffer.push_back(data);
}
void Renderer::batch() {
glBindVertexArray(this->array_buffer_id);
glBindBuffer(GL_ARRAY_BUFFER, this->vertex_buffer_id);
glBufferSubData(GL_ARRAY_BUFFER, 0, batch_buffer.size() * sizeof(struct RendererData), batch_buffer.data());
glUseProgram(this->program.id);
glUniformMatrix4fv(glGetUniformLocation(this->program.id, "view_matrix"), 1, GL_FALSE, &this->view_matrix[0][0]);
glUniformMatrix4fv(glGetUniformLocation(this->program.id, "projection_matrix"), 1, GL_FALSE, &this->projection_matrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, DEFAULT_VBO_SIZE);
batch_buffer.clear();
}
void Renderer::logic() {
int window_width;
int window_height;
float half_width;
float half_height;
this->window.get_size(&window_width, &window_height);
half_width = window_width / 2.0f;
half_height = window_height / 2.0f;
this->projection_matrix = glm::ortho(-half_width/100, half_width/100, -half_height/100, half_height/100, 0.1f, 100.0f);
}
Renderer::~Renderer() {
glDisableVertexAttribArray(DEFAULT_POSITION_ATTRIBUTE);
glDisableVertexAttribArray(DEFAULT_COLOR_ATTRIBUTE);
glDisableVertexAttribArray(DEFAULT_TEXTURE_ATTRIBUTE);
glDisableVertexAttribArray(DEFAULT_CTT_ATTRIBUTE);
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <GL/glew.h>
#include <optional>
#include <glm/mat4x4.hpp>
#include "renderer_pack.hpp"
#include "program.hpp"
#include "../window/window.hpp"
class Renderer {
public:
GLuint array_buffer_id;
GLuint vertex_buffer_id;
Program program;
RendererPack pack;
glm::mat4 view_matrix;
glm::mat4 projection_matrix;
Window &window;
Renderer(Window &window);
~Renderer();
int setup(std::optional<Program> program = std::nullopt);
void logic();
std::vector<struct RendererData> batch_buffer;
void draw(struct RendererData data);
void batch();
};

View File

@ -0,0 +1,9 @@
#include "renderer_pack.hpp"
RendererPack::RendererPack() {
this->data = std::vector<struct RendererData>();
}
RendererPack::~RendererPack(){
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <iostream>
#include <vector>
#include <glm/vec4.hpp>
#include <glm/vec2.hpp>
struct RendererData {
glm::vec4 vertex;
glm::vec4 origin;
glm::vec4 color;
glm::vec2 tex;
float ctt_ratio; // color to texture ratio (i.e. how much does the color affect the texture)
};
class RendererPack {
public:
std::vector<struct RendererData> data;
RendererPack();
~RendererPack();
};

View File

@ -0,0 +1,33 @@
#include <iostream>
#include <GL/glew.h>
#include "shader.hpp"
#include "../common.hpp"
#include "../macros.hpp"
unsigned int Shader::load(const char *path, unsigned int type) {
std::string source_s = read_file(path);
const char *source = source_s.c_str();
unsigned int new_shader = glCreateShader(type);
if (!new_shader)
return 0;
glShaderSource(new_shader, 1, &source, NULL);
glCompileShader(new_shader);
int success;
char info_log[512];
glGetShaderiv(new_shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(new_shader, 512, NULL, info_log);
std::cout << "Error: failed compiling new shader " << info_log << std::endl;
LOG(LOG_ERR, "Failed compiling new shader");
return RET_OK;
}
this->id = new_shader;
this->type = type;
return new_shader;
}

View File

@ -0,0 +1,8 @@
#pragma once
struct Shader {
unsigned int id;
unsigned int type;
unsigned int load(const char *path, unsigned int type);
};

View File

@ -0,0 +1,12 @@
#pragma once
#include <iostream>
#define LOG_DEBUG "debug"
#define LOG_WARN "warning"
#define LOG_ERR "error"
#define LOG(level, ...) std::cout << "[" << __TIME__ << " " << level << "]: " << __VA_ARGS__ << std::endl;
#define RET_OK 0
#define RET_ERR -1

View File

@ -0,0 +1,39 @@
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "window.hpp"
#include "../macros.hpp"
int Window::init(int width, int height, std::string title) {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
this->window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
if (this->window == NULL) {
LOG(LOG_ERR, "Failed creating window");
glfwTerminate();
return RET_ERR;
}
glfwMakeContextCurrent(this->window);
GLenum err = glewInit();
if (err != GLEW_OK) {
LOG(LOG_ERR, "FAiled initializing Glew");
return RET_ERR;
}
glfwSetFramebufferSizeCallback(this->window, this->resize_callback);
return RET_OK;
}
void Window::resize_callback(GLFWwindow *window, int new_width, int new_height) {
glViewport(0, 0, new_width, new_height);
}
void Window::get_size(int *width, int *height) {
glfwGetWindowSize(this->window, width, height);
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <iostream>
#include <GLFW/glfw3.h>
class Window {
public:
int init(int width, int height, std::string title);
static void resize_callback(GLFWwindow *window, int new_width, int new_height);
void get_size(int *width, int *height);
GLFWwindow *window;
};

View File

@ -0,0 +1,48 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stb/stb_image.h>
#include "base/window/window.hpp"
#include "base/graphics/renderer.hpp"
#include "base/macros.hpp"
#include "sprites/sprite.hpp"
const int initial_width = 1000;
const int initial_height = 600;
int main() {
Window window;
window.init(initial_width, initial_height, "OpenGL");
Renderer main_renderer(window);
int ret = main_renderer.setup();
if (ret != RET_OK) {
LOG(LOG_ERR, "Failed setting up a new renderer");
return RET_ERR;
}
std::vector<Sprite> sprites;
Sprite sprite(main_renderer);
sprite.bake();
sprite.origin = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
while (!glfwWindowShouldClose(window.window)) {
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
sprite.update();
main_renderer.logic();
main_renderer.batch();
glfwPollEvents();
glfwSwapBuffers(window.window);
}
glfwTerminate();
return RET_OK;
}

View File

@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
#include <iostream>
#include <vector>
#include <glm/vec4.hpp>
#include <glm/vec2.hpp>
#include <GL/glew.h>
#include "../base/graphics/renderer.hpp"
#include "sprite.hpp"
Sprite::Sprite(Renderer &renderer) : renderer(renderer) {
this->vertices = std::vector<glm::vec4>();
this->origin = glm::vec4(1.0f);
this->color = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
this->texture_position = glm::vec2(0.0f);
this->ctt = 1.0f;
}
// prepare data
void Sprite::bake() {
this->vertices.push_back(glm::vec4(0.5f, 0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(0.5f, -0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(-0.5f, -0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(-0.5f, 0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(0.5f, 0.5f, 0.0f, 0.0f));
this->vertices.push_back(glm::vec4(-0.5f, -0.5f, 0.0f, 0.0f));
}
void Sprite::update() {
for (int i = 0; i < this->vertices.size(); i++) {
struct RendererData data = {
.vertex = this->vertices[i],
.origin = this->origin,
.color = this->color,
.tex = this->texture_position,
.ctt_ratio = this->ctt
};
this->renderer.draw(data);
}
}
Sprite::~Sprite() {
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <iostream>
#include <vector>
#include <glm/vec4.hpp>
#include <glm/vec2.hpp>
#include <GL/glew.h>
#include "../base/graphics/renderer.hpp"
class Sprite {
public:
std::vector<glm::vec4> vertices;
glm::vec4 origin;
glm::vec4 color;
glm::vec2 texture_position;
float ctt;
// GLuint vertex_buffer_id;
Renderer &renderer;
Sprite(Renderer &renderer);
~Sprite();
void bake();
void update();
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -0,0 +1,28 @@
CC=g++
CFLAGS=-std=c++20 `pkg-config --cflags glfw3 glew glm`
LDFLAGS=`pkg-config --libs glfw3 glew glm`
TARGET=boilerplate
SDIR=src
ADIR=assets
ODIR=build
SRC=$(shell find $(SDIR) -type f -name *.cpp)
OBJ=$(SRC:.cpp=.o)
all: $(TARGET)
.PHONY: default
$(TARGET): $(OBJ)
mkdir -p build
cp -rf $(ADIR) $(ODIR)/
$(CC) -o $(ODIR)/$@ $^ $(LDFLAGS)
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $<
run:
$(ODIR)/$(TARGET)
.PHONY: clean
clean:
rm -f $(ODIR)/$(TARGET) $(OBJ)

View File

@ -0,0 +1,10 @@
<p align="center">
<img src=".imgs/showcase.png" width="300" />
</p>
# Particle System OpenGL
Contains a particle system abstraction on top of the previous OpenGL boilerplate code (`07-boilerplate`).
Each particle system is supposed (although not necessary) to have 1 renderer fully for itself.
Meaning that all the particles will be batched into 1 draw call.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,12 @@
#version 330 core
in vec4 _color;
in vec2 _texture_position;
in float _ctt;
out vec4 color;
uniform sampler2D sampler;
void main() {
color = texture(sampler, _texture_position) * (_color * _ctt);
}

View File

@ -0,0 +1,26 @@
#version 330 core
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 origin;
layout (location = 2) in vec4 size;
layout (location = 3) in vec4 color;
layout (location = 4) in vec2 texture_position;
layout (location = 5) in float ctt;
uniform mat4 view_matrix;
uniform mat4 projection_matrix;
out vec4 _color;
out vec2 _texture_position;
out float _ctt;
void main() {
vec3 origined_position = origin.xyz + position.xyz;
origined_position *= size.xyz;
gl_Position = projection_matrix * view_matrix * vec4(origined_position, 1.0);
_color = color;
_texture_position = texture_position;
_ctt = ctt;
}

View File

@ -0,0 +1,13 @@
#version 330 core
out vec4 color;
in vec2 tex_coord;
uniform sampler2D sampler;
void main() {
color = texture(sampler, tex_coord);
// color = vec4(1.0, 0.0, 0.0, 1.0);
if (color.a < 0.1)
discard;
}

View File

@ -0,0 +1,14 @@
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texture_coord;
uniform mat4 view;
uniform mat4 projection;
out vec2 tex_coord;
void main() {
gl_Position = projection * view * vec4(pos.xyz, 1.0);
tex_coord = texture_coord;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

View File

@ -0,0 +1,22 @@
#include <iostream>
#include <fstream>
#include "common.hpp"
std::string read_file(const char *path) {
std::string content;
std::ifstream fs(path, std::ios::in);
if(!fs.is_open()) {
std::cerr << "Error: Could not read file " << path << ". File does not exist." << std::endl;
return NULL;
}
std::string line = "";
while(!fs.eof()) {
std::getline(fs, line);
content.append(line + "\n");
}
fs.close();
return content;
}

View File

@ -0,0 +1,5 @@
#pragma once
#include <string>
std::string read_file(const char *path);

Some files were not shown because too many files have changed in this diff Show More