src/graphics moved to src/graphics/core

This commit is contained in:
MihailRis
2024-03-18 20:47:35 +03:00
parent ba762584a7
commit b56408a202
63 changed files with 156 additions and 147 deletions
+87
View File
@@ -0,0 +1,87 @@
#include "Atlas.h"
#include <stdexcept>
#include "../../maths/LMPacker.h"
#include "Texture.h"
#include "ImageData.h"
Atlas::Atlas(ImageData* image, std::unordered_map<std::string, UVRegion> regions)
: texture(Texture::from(image)),
image(image),
regions(regions) {
}
Atlas::~Atlas() {
}
bool Atlas::has(const std::string& name) const {
return regions.find(name) != regions.end();
}
const UVRegion& Atlas::get(const std::string& name) const {
return regions.at(name);
}
Texture* Atlas::getTexture() const {
return texture.get();
}
ImageData* Atlas::getImage() const {
return image.get();
}
void AtlasBuilder::add(std::string name, ImageData* image) {
entries.push_back(atlasentry{name, std::shared_ptr<ImageData>(image)});
names.insert(name);
}
bool AtlasBuilder::has(const std::string& name) const {
return names.find(name) != names.end();
}
Atlas* AtlasBuilder::build(uint extrusion, uint maxResolution) {
auto sizes = std::make_unique<uint[]>(entries.size() * 2);
uint index = 0;
for (auto& entry : entries) {
auto image = entry.image;
sizes[index++] = image->getWidth();
sizes[index++] = image->getHeight();
}
LMPacker packer(sizes.get(), entries.size()*2);
sizes.reset(nullptr);
uint width = 32;
uint height = 32;
while (!packer.buildCompact(width, height, extrusion)) {
if (width > height) {
height *= 2;
} else {
width *= 2;
}
if (width > maxResolution || height > maxResolution) {
throw std::runtime_error("max atlas resolution "+
std::to_string(maxResolution)+" exceeded");
}
}
auto canvas = std::make_unique<ImageData>(ImageFormat::rgba8888, width, height);
std::unordered_map<std::string, UVRegion> regions;
std::vector<rectangle> rects = packer.getResult();
for (uint i = 0; i < entries.size(); i++) {
const rectangle& rect = rects[i];
const atlasentry& entry = entries[rect.idx];
uint x = rect.x;
uint y = rect.y;
uint w = rect.width;
uint h = rect.height;
canvas->blit(entry.image.get(), rect.x, rect.y);
for (uint j = 0; j < extrusion; j++) {
canvas->extrude(x - j, y - j, w + j*2, h + j*2);
}
float unitX = 1.0f / width;
float unitY = 1.0f / height;
regions[entry.name] = UVRegion(unitX * x, unitY * y,
unitX * (x + w), unitY * (y + h));
}
return new Atlas(canvas.release(), regions);
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef GRAPHICS_CORE_ATLAS_H_
#define GRAPHICS_CORE_ATLAS_H_
#include <set>
#include <string>
#include <memory>
#include <vector>
#include <unordered_map>
#include "UVRegion.h"
#include "../../typedefs.h"
class ImageData;
class Texture;
class Atlas {
std::unique_ptr<Texture> texture;
std::unique_ptr<ImageData> image;
std::unordered_map<std::string, UVRegion> regions;
public:
Atlas(ImageData* image, std::unordered_map<std::string, UVRegion> regions);
~Atlas();
bool has(const std::string& name) const;
const UVRegion& get(const std::string& name) const;
Texture* getTexture() const;
ImageData* getImage() const;
};
struct atlasentry {
std::string name;
std::shared_ptr<ImageData> image;
};
class AtlasBuilder {
std::vector<atlasentry> entries;
std::set<std::string> names;
public:
AtlasBuilder() {}
void add(std::string name, ImageData* image);
bool has(const std::string& name) const;
const std::set<std::string>& getNames() { return names; };
Atlas* build(uint extrusion, uint maxResolution=8192);
};
#endif // GRAPHICS_CORE_ATLAS_H_
+311
View File
@@ -0,0 +1,311 @@
#include "Batch2D.h"
#include "Mesh.h"
#include "Texture.h"
#include <GL/glew.h>
inline constexpr uint B2D_VERTEX_SIZE = 8;
Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
const vattr attrs[] = {
{2}, {2}, {4}, {0}
};
buffer = new float[capacity * B2D_VERTEX_SIZE];
mesh = std::make_unique<Mesh>(buffer, 0, attrs);
index = 0;
ubyte pixels[] = {
0xFF, 0xFF, 0xFF, 0xFF
};
blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888);
_texture = nullptr;
}
Batch2D::~Batch2D(){
delete[] buffer;
}
void Batch2D::begin(){
_texture = nullptr;
blank->bind();
color = glm::vec4(1.0f);
}
void Batch2D::vertex(
float x, float y,
float u, float v,
float r, float g, float b, float a
) {
buffer[index++] = x;
buffer[index++] = y;
buffer[index++] = u;
buffer[index++] = v;
buffer[index++] = r;
buffer[index++] = g;
buffer[index++] = b;
buffer[index++] = a;
}
void Batch2D::vertex(
glm::vec2 point,
glm::vec2 uvpoint,
float r, float g, float b, float a
) {
buffer[index++] = point.x;
buffer[index++] = point.y;
buffer[index++] = uvpoint.x;
buffer[index++] = uvpoint.y;
buffer[index++] = r;
buffer[index++] = g;
buffer[index++] = b;
buffer[index++] = a;
}
void Batch2D::texture(Texture* new_texture){
if (_texture == new_texture)
return;
flush(GL_TRIANGLES);
_texture = new_texture;
if (new_texture == nullptr)
blank->bind();
else
new_texture->bind();
}
void Batch2D::untexture() {
texture(nullptr);
}
void Batch2D::point(float x, float y, float r, float g, float b, float a){
if (index + 6*B2D_VERTEX_SIZE >= capacity)
flush(GL_TRIANGLES);
vertex(x, y, 0, 0, r,g,b,a);
flush(GL_POINTS);
}
void Batch2D::line(float x1, float y1, float x2, float y2, float r, float g, float b, float a){
if (index + 6*B2D_VERTEX_SIZE >= capacity)
flush(GL_TRIANGLES);
vertex(x1, y1, 0, 0, r,g,b,a);
vertex(x2, y2, 1, 1, r,g,b,a);
flush(GL_LINES);
}
void Batch2D::rect(float x, float y, float w, float h){
const float r = color.r;
const float g = color.g;
const float b = color.b;
const float a = color.a;
if (index + 6*B2D_VERTEX_SIZE >= capacity)
flush(GL_TRIANGLES);
vertex(x, y, 0, 0, r,g,b,a);
vertex(x, y+h, 0, 1, r,g,b,a);
vertex(x+w, y+h, 1, 1, r,g,b,a);
vertex(x, y, 0, 0, r,g,b,a);
vertex(x+w, y+h, 1, 1, r,g,b,a);
vertex(x+w, y, 1, 0, r,g,b,a);
}
void Batch2D::rect(
float x, float y,
float w, float h,
float ox, float oy,
float angle,
UVRegion region,
bool flippedX,
bool flippedY,
glm::vec4 tint
) {
if (index + 6*B2D_VERTEX_SIZE >= capacity)
flush(GL_TRIANGLES);
float centerX = w*ox;
float centerY = h*oy;
float acenterX = w-centerX;
float acenterY = h-centerY;
float _x1 = -centerX;
float _y1 = -centerY;
float _x2 = -centerX;
float _y2 = +acenterY;
float _x3 = +acenterX;
float _y3 = +acenterY;
float _x4 = +acenterX;
float _y4 = -centerY;
float x1,y1,x2,y2,x3,y3,x4,y4;
if (angle != 0) {
float s = sin(angle);
float c = cos(angle);
x1 = c * _x1 - s * _y1;
y1 = s * _x1 + c * _y1;
x2 = c * _x2 - s * _y2;
y2 = s * _x2 + c * _y2;
x3 = c * _x3 - s * _y3;
y3 = s * _x3 + c * _y3;
x4 = x1 + (x3 - x2);
y4 = y3 - (y2 - y1);
} else {
x1 = _x1;
y1 = _y1;
x2 = _x2;
y2 = _y2;
x3 = _x3;
y3 = _y3;
x4 = _x4;
y4 = _y4;
}
x1 += x; x2 += x; x3 += x; x4 += x;
y1 += y; y2 += y; y3 += y; y4 += y;
float u1 = region.u1;
float v1 = region.v1;
float u2 = region.u1;
float v2 = region.v2;
float u3 = region.u2;
float v3 = region.v2;
float u4 = region.u2;
float v4 = region.v1;
if (flippedX) {
float temp = u1;
u1 = u3;
u4 = temp;
u2 = u3;
u3 = temp;
}
if (flippedY) {
float temp = v1;
v1 = v2;
v4 = v2;
v2 = temp;
v3 = temp;
}
vertex(x1, y1, u1, v1, tint.r, tint.g, tint.b, tint.a);
vertex(x2, y2, u2, v2, tint.r, tint.g, tint.b, tint.a);
vertex(x3, y3, u3, v3, tint.r, tint.g, tint.b, tint.a);
/* Right down triangle */
vertex(x1, y1, u1, v1, tint.r, tint.g, tint.b, tint.a);
vertex(x3, y3, u3, v3, tint.r, tint.g, tint.b, tint.a);
vertex(x4, y4, u4, v4, tint.r, tint.g, tint.b, tint.a);
}
void Batch2D::rect(
float x, float y, float w, float h,
float u, float v, float tx, float ty,
float r, float g, float b, float a
){
if (index + 6*B2D_VERTEX_SIZE >= capacity)
flush(GL_TRIANGLES);
vertex(x, y, u, v+ty, r,g,b,a);
vertex(x+w, y+h, u+tx, v, r,g,b,a);
vertex(x, y+h, u, v, r,g,b,a);
vertex(x, y, u, v+ty, r,g,b,a);
vertex(x+w, y, u+tx, v+ty, r,g,b,a);
vertex(x+w, y+h, u+tx, v, r,g,b,a);
}
void Batch2D::rect(
float x, float y, float w, float h,
float r0, float g0, float b0,
float r1, float g1, float b1,
float r2, float g2, float b2,
float r3, float g3, float b3,
float r4, float g4, float b4, int sh
){
if (index + 30*B2D_VERTEX_SIZE >= capacity)
flush(GL_TRIANGLES);
glm::vec2 v0(x+h/2,y+h/2);
glm::vec2 v1(x+w-sh,y);
glm::vec2 v2(x+sh,y);
glm::vec2 v3(x,y+sh);
glm::vec2 v4(x,y+h-sh);
glm::vec2 v5(x+sh,y+h);
glm::vec2 v6(x+w-h/2,y+h/2);
glm::vec2 v7(x+w-sh,y+h);
glm::vec2 v8(x+w,y+h-sh);
glm::vec2 v9(x+w,y+sh);
vertex(v0, glm::vec2(0, 0), r1,g1,b1,1.0f);
vertex(v6, glm::vec2(0, 0), r1,g1,b1,1.0f);
vertex(v1, glm::vec2(0, 0), r1,g1,b1,1.0f);
vertex(v0, glm::vec2(0, 0), r1,g1,b1,1.0f);
vertex(v1, glm::vec2(0, 0), r1,g1,b1,1.0f);
vertex(v2, glm::vec2(0, 0), r1,g1,b1,1.0f);
vertex(v0, glm::vec2(0, 0), r0,g0,b0,1.0f);
vertex(v2, glm::vec2(0, 0), r0,g0,b0,1.0f);
vertex(v3, glm::vec2(0, 0), r0,g0,b0,1.0f);
vertex(v0, glm::vec2(0, 0), r1,g1,b1,1.0f);
vertex(v3, glm::vec2(0, 0), r1,g1,b1,1.0f);
vertex(v4, glm::vec2(0, 0), r1,g1,b1,1.0f);
vertex(v0, glm::vec2(0, 0), r2,g2,b2,1.0f);
vertex(v4, glm::vec2(0, 0), r2,g2,b2,1.0f);
vertex(v5, glm::vec2(0, 0), r2,g2,b2,1.0f);
vertex(v0, glm::vec2(0, 0), r3,g3,b3,1.0f);
vertex(v5, glm::vec2(0, 0), r3,g3,b3,1.0f);
vertex(v6, glm::vec2(0, 0), r3,g3,b3,1.0f);
vertex(v6, glm::vec2(0, 0), r3,g3,b3,1.0f);
vertex(v5, glm::vec2(0, 0), r3,g3,b3,1.0f);
vertex(v7, glm::vec2(0, 0), r3,g3,b3,1.0f);
vertex(v6, glm::vec2(0, 0), r4,g4,b4,1.0f);
vertex(v7, glm::vec2(0, 0), r4,g4,b4,1.0f);
vertex(v8, glm::vec2(0, 0), r4,g4,b4,1.0f);
vertex(v6, glm::vec2(0, 0), r3,g3,b3,1.0f);
vertex(v8, glm::vec2(0, 0), r3,g3,b3,1.0f);
vertex(v9, glm::vec2(0, 0), r3,g3,b3,1.0f);
vertex(v6, glm::vec2(0, 0), r2,g2,b2,1.0f);
vertex(v9, glm::vec2(0, 0), r2,g2,b2,1.0f);
vertex(v1, glm::vec2(0, 0), r2,g2,b2,1.0f);
}
void Batch2D::sprite(float x, float y, float w, float h, const UVRegion& region, glm::vec4 tint){
rect(x, y, w, h, region.u1, region.v1, region.u2-region.u1, region.v2-region.v1, tint.r, tint.g, tint.b, tint.a);
}
void Batch2D::sprite(float x, float y, float w, float h, int atlasRes, int index, glm::vec4 tint){
float scale = 1.0f / (float)atlasRes;
float u = (index % atlasRes) * scale;
float v = 1.0f - ((index / atlasRes) * scale) - scale;
rect(x, y, w, h, u, v, scale, scale, tint.r, tint.g, tint.b, tint.a);
}
void Batch2D::flush(unsigned int gl_primitive) {
if (index == 0)
return;
mesh->reload(buffer, index / B2D_VERTEX_SIZE);
mesh->draw(gl_primitive);
index = 0;
}
void Batch2D::flush() {
flush(GL_TRIANGLES);
}
void Batch2D::lineWidth(float width) {
glLineWidth(width);
}
+90
View File
@@ -0,0 +1,90 @@
#ifndef GRAPHICS_CORE_BATCH2D_H_
#define GRAPHICS_CORE_BATCH2D_H_
#include <memory>
#include <stdlib.h>
#include <glm/glm.hpp>
#include "UVRegion.h"
class Mesh;
class Texture;
class Batch2D {
float* buffer;
size_t capacity;
std::unique_ptr<Mesh> mesh;
std::unique_ptr<Texture> blank;
size_t index;
glm::vec4 color;
Texture* _texture;
void vertex(
float x, float y,
float u, float v,
float r, float g, float b, float a
);
void vertex(
glm::vec2 point,
glm::vec2 uvpoint,
float r, float g, float b, float a
);
public:
Batch2D(size_t capacity);
~Batch2D();
void begin();
void texture(Texture* texture);
void untexture();
void sprite(float x, float y, float w, float h, const UVRegion& region, glm::vec4 tint);
void sprite(float x, float y, float w, float h, int atlasRes, int index, glm::vec4 tint);
void point(float x, float y, float r, float g, float b, float a);
inline void setColor(glm::vec4 color) {
this->color = color;
}
inline glm::vec4 getColor() const {
return color;
}
void line(
float x1, float y1,
float x2, float y2,
float r, float g, float b, float a
);
void rect(
float x, float y,
float w, float h,
float ox, float oy,
float angle, UVRegion region,
bool flippedX, bool flippedY,
glm::vec4 tint
);
void rect(float x, float y, float w, float h);
void rect(
float x, float y, float w, float h,
float u, float v, float tx, float ty,
float r, float g, float b, float a
);
void rect(
float x, float y, float w, float h,
float r0, float g0, float b0,
float r1, float g1, float b1,
float r2, float g2, float b2,
float r3, float g3, float b3,
float r4, float g4, float b4, int sh
);
void flush(unsigned int gl_primitive);
void flush();
void lineWidth(float width);
};
#endif // GRAPHICS_CORE_BATCH2D_H_
+256
View File
@@ -0,0 +1,256 @@
#include "Batch3D.h"
#include "Mesh.h"
#include "Texture.h"
#include <GL/glew.h>
#include "../../typedefs.h"
inline constexpr uint B3D_VERTEX_SIZE = 9;
Batch3D::Batch3D(size_t capacity)
: capacity(capacity) {
const vattr attrs[] = {
{3}, {2}, {4}, {0}
};
buffer = new float[capacity * B3D_VERTEX_SIZE];
mesh = std::make_unique<Mesh>(buffer, 0, attrs);
index = 0;
ubyte pixels[] = {
255, 255, 255, 255,
};
blank = std::make_unique<Texture>(pixels, 1, 1, ImageFormat::rgba8888);
_texture = nullptr;
}
Batch3D::~Batch3D(){
delete[] buffer;
}
void Batch3D::begin(){
_texture = nullptr;
blank->bind();
}
void Batch3D::vertex(float x, float y, float z, float u, float v,
float r, float g, float b, float a) {
buffer[index++] = x;
buffer[index++] = y;
buffer[index++] = z;
buffer[index++] = u;
buffer[index++] = v;
buffer[index++] = r;
buffer[index++] = g;
buffer[index++] = b;
buffer[index++] = a;
}
void Batch3D::vertex(glm::vec3 coord, float u, float v,
float r, float g, float b, float a) {
buffer[index++] = coord.x;
buffer[index++] = coord.y;
buffer[index++] = coord.z;
buffer[index++] = u;
buffer[index++] = v;
buffer[index++] = r;
buffer[index++] = g;
buffer[index++] = b;
buffer[index++] = a;
}
void Batch3D::vertex(glm::vec3 point,
glm::vec2 uvpoint,
float r, float g, float b, float a) {
buffer[index++] = point.x;
buffer[index++] = point.y;
buffer[index++] = point.z;
buffer[index++] = uvpoint.x;
buffer[index++] = uvpoint.y;
buffer[index++] = r;
buffer[index++] = g;
buffer[index++] = b;
buffer[index++] = a;
}
void Batch3D::face(
const glm::vec3& coord,
float w, float h,
const glm::vec3& axisX,
const glm::vec3& axisY,
const UVRegion& region,
const glm::vec4& tint
) {
if (index + B3D_VERTEX_SIZE * 6 > capacity) {
flush();
}
vertex(coord, region.u1, region.v1,
tint.r, tint.g, tint.b, tint.a);
vertex(coord + axisX * w, region.u2, region.v1,
tint.r, tint.g, tint.b, tint.a);
vertex(coord + axisX * w + axisY * h, region.u2, region.v2,
tint.r, tint.g, tint.b, tint.a);
vertex(coord, region.u1, region.v1,
tint.r, tint.g, tint.b, tint.a);
vertex(coord + axisX * w + axisY * h, region.u2, region.v2,
tint.r, tint.g, tint.b, tint.a);
vertex(coord + axisY * h, region.u1, region.v2,
tint.r, tint.g, tint.b, tint.a);
}
void Batch3D::texture(Texture* new_texture){
if (_texture == new_texture)
return;
flush();
_texture = new_texture;
if (new_texture == nullptr)
blank->bind();
else
new_texture->bind();
}
void Batch3D::sprite(
glm::vec3 pos,
glm::vec3 up,
glm::vec3 right,
float w, float h,
const UVRegion& uv,
glm::vec4 color
){
const float r = color.r;
const float g = color.g;
const float b = color.b;
const float a = color.a;
if (index + 6*B3D_VERTEX_SIZE >= capacity) {
flush();
}
vertex(pos.x - right.x * w - up.x * h,
pos.y - right.y * w - up.y * h,
pos.z - right.z * w - up.z * h,
uv.u1, uv.v1,
r,g,b,a);
vertex(pos.x + right.x * w + up.x * h,
pos.y + right.y * w + up.y * h,
pos.z + right.z * w + up.z * h,
uv.u2, uv.v2,
r,g,b,a);
vertex(pos.x - right.x * w + up.x * h,
pos.y - right.y * w + up.y * h,
pos.z - right.z * w + up.z * h,
uv.u1, uv.v2,
r,g,b,a);
vertex(pos.x - right.x * w - up.x * h,
pos.y - right.y * w - up.y * h,
pos.z - right.z * w - up.z * h,
uv.u1, uv.v1,
r,g,b,a);
vertex(pos.x + right.x * w - up.x * h,
pos.y + right.y * w - up.y * h,
pos.z + right.z * w - up.z * h,
uv.u2, uv.v1,
r,g,b,a);
vertex(pos.x + right.x * w + up.x * h,
pos.y + right.y * w + up.y * h,
pos.z + right.z * w + up.z * h,
uv.u2, uv.v2,
r,g,b,a);
}
inline glm::vec4 do_tint(float value) {
return glm::vec4(value, value, value, 1.0f);
}
void Batch3D::xSprite(float w, float h, const UVRegion& uv, const glm::vec4 tint, bool shading) {
face(
glm::vec3(-w * 0.25f, 0.0f, -w * 0.25f),
w, h,
glm::vec3(1, 0, 0),
glm::vec3(0, 1, 0),
uv, (shading ? do_tint(1.0f)*tint : tint)
);
face(
glm::vec3(w * 0.25f, 0.0f, w * 0.5f - w * 0.25f),
w, h,
glm::vec3(0, 0, -1),
glm::vec3(0, 1, 0),
uv, (shading ? do_tint(0.9f)*tint : tint)
);
}
void Batch3D::cube(
const glm::vec3 coord,
const glm::vec3 size,
const UVRegion(&texfaces)[6],
const glm::vec4 tint,
bool shading
) {
const glm::vec3 X(1.0f, 0.0f, 0.0f);
const glm::vec3 Y(0.0f, 1.0f, 0.0f);
const glm::vec3 Z(0.0f, 0.0f, 1.0f);
face(
coord+glm::vec3(0.0f, 0.0f, 0.0f),
size.x, size.y, X, Y, texfaces[5],
(shading ? do_tint(0.8)*tint : tint)
);
face(
coord+glm::vec3(size.x, 0.0f, -size.z),
size.x, size.y, -X, Y, texfaces[4],
(shading ? do_tint(0.8f)*tint : tint)
);
face(
coord+glm::vec3(0.0f, size.y, 0.0f),
size.x, size.z, X, -Z, texfaces[3],
(shading ? do_tint(1.0f)*tint : tint)
);
face(
coord+glm::vec3(0.0f, 0.0f, -size.z),
size.x, size.z, X, Z, texfaces[2],
(shading ? do_tint(0.7f)*tint : tint)
);
face(
coord+glm::vec3(0.0f, 0.0f, -size.z),
size.z, size.y, Z, Y, texfaces[0],
(shading ? do_tint(0.9f)*tint : tint)
);
face(
coord+glm::vec3(size.x, 0.0f, 0.0f),
size.z, size.y, -Z, Y, texfaces[1],
(shading ? do_tint(0.9f)*tint : tint)
);
}
void Batch3D::blockCube(
const glm::vec3 size,
const UVRegion(&texfaces)[6],
const glm::vec4 tint,
bool shading
) {
cube((1.0f - size) * -0.5f, size, texfaces, tint, shading);
}
void Batch3D::point(glm::vec3 coord, glm::vec2 uv, glm::vec4 tint) {
vertex(coord, uv, tint.r, tint.g, tint.b, tint.a);
}
void Batch3D::point(glm::vec3 coord, glm::vec4 tint) {
point(coord, glm::vec2(), tint);
}
void Batch3D::flush() {
mesh->reload(buffer, index / B3D_VERTEX_SIZE);
mesh->draw();
index = 0;
}
void Batch3D::flushPoints() {
mesh->reload(buffer, index / B3D_VERTEX_SIZE);
mesh->draw(GL_POINTS);
index = 0;
}
+54
View File
@@ -0,0 +1,54 @@
#ifndef GRAPHICS_CORE_BATCH3D_H_
#define GRAPHICS_CORE_BATCH3D_H_
#include "UVRegion.h"
#include "../../typedefs.h"
#include <memory>
#include <stdlib.h>
#include <glm/glm.hpp>
class Mesh;
class Texture;
class Batch3D {
float* buffer;
size_t capacity;
std::unique_ptr<Mesh> mesh;
std::unique_ptr<Texture> blank;
size_t index;
Texture* _texture;
void vertex(float x, float y, float z,
float u, float v,
float r, float g, float b, float a);
void vertex(glm::vec3 coord,
float u, float v,
float r, float g, float b, float a);
void vertex(glm::vec3 point, glm::vec2 uvpoint,
float r, float g, float b, float a);
void face(const glm::vec3& coord, float w, float h,
const glm::vec3& axisX,
const glm::vec3& axisY,
const UVRegion& region,
const glm::vec4& tint);
public:
Batch3D(size_t capacity);
~Batch3D();
void begin();
void texture(Texture* texture);
void sprite(glm::vec3 pos, glm::vec3 up, glm::vec3 right, float w, float h, const UVRegion& uv, glm::vec4 tint);
void xSprite(float w, float h, const UVRegion& uv, const glm::vec4 tint, bool shading=true);
void cube(const glm::vec3 coords, const glm::vec3 size, const UVRegion(&texfaces)[6], const glm::vec4 tint, bool shading=true);
void blockCube(const glm::vec3 size, const UVRegion(&texfaces)[6], const glm::vec4 tint, bool shading=true);
void point(glm::vec3 pos, glm::vec2 uv, glm::vec4 tint);
void point(glm::vec3 pos, glm::vec4 tint);
void flush();
void flushPoints();
};
#endif // GRAPHICS_CORE_BATCH3D_H_
+39
View File
@@ -0,0 +1,39 @@
#include "Cubemap.h"
#include "gl_util.h"
#include <GL/glew.h>
Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat)
: Texture(0, width, height)
{
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
uint format = gl::to_gl_format(imageFormat);
for (uint face = 0; face < 6; face++) {
glTexImage2D(
GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
0,
format,
width,
height,
0,
format,
GL_UNSIGNED_BYTE,
NULL
);
}
}
void Cubemap::bind(){
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
}
void Cubemap::unbind() {
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef GRAPHICS_CORE_CUBEMAP_H_
#define GRAPHICS_CORE_CUBEMAP_H_
#include "Texture.h"
/// @brief Cubemap texture
class Cubemap : public Texture {
public:
Cubemap(uint width, uint height, ImageFormat format);
virtual void bind() override;
virtual void unbind() override;
};
#endif // GRAPHICS_CORE_CUBEMAP_H_
+97
View File
@@ -0,0 +1,97 @@
#include "Font.h"
#include "Texture.h"
#include "Batch2D.h"
inline constexpr uint GLYPH_SIZE = 16;
inline constexpr uint MAX_CODEPAGES = 10000; // idk ho many codepages unicode has
inline constexpr glm::vec4 SHADOW_TINT(0.0f, 0.0f, 0.0f, 1.0f);
Font::Font(std::vector<std::unique_ptr<Texture>> pages, int lineHeight, int yoffset)
: lineHeight(lineHeight), yoffset(yoffset), pages(std::move(pages)) {
}
Font::~Font(){
}
int Font::getYOffset() const {
return yoffset;
}
int Font::getLineHeight() const {
return lineHeight;
}
bool Font::isPrintableChar(uint codepoint) const {
switch (codepoint){
case ' ':
case '\t':
case '\n':
case '\f':
case '\r':
return false;
default:
return true;
}
}
int Font::calcWidth(std::wstring text, size_t length) {
return std::min(text.length(), length) * 8;
}
void Font::draw(Batch2D* batch, std::wstring text, int x, int y) {
draw(batch, text, x, y, FontStyle::none);
}
static inline void drawGlyph(Batch2D* batch, int x, int y, uint c, FontStyle style) {
switch (style){
case FontStyle::none:
break;
case FontStyle::shadow:
batch->sprite(x+1, y+1, GLYPH_SIZE, GLYPH_SIZE, 16, c, SHADOW_TINT);
break;
case FontStyle::outline:
for (int oy = -1; oy <= 1; oy++){
for (int ox = -1; ox <= 1; ox++){
if (ox || oy) {
batch->sprite(x+ox, y+oy, GLYPH_SIZE, GLYPH_SIZE, 16, c, SHADOW_TINT);
}
}
}
break;
}
batch->sprite(x, y, GLYPH_SIZE, GLYPH_SIZE, 16, c, batch->getColor());
}
void Font::draw(Batch2D* batch, std::wstring text, int x, int y, FontStyle style) {
draw(batch, std::wstring_view(text.c_str(), text.length()), x, y, style);
}
void Font::draw(Batch2D* batch, std::wstring_view text, int x, int y, FontStyle style) {
uint page = 0;
uint next = MAX_CODEPAGES;
int init_x = x;
do {
for (uint c : text){
if (!isPrintableChar(c)) {
x += 8;
continue;
}
uint charpage = c >> 8;
if (charpage == page){
Texture* texture = pages[charpage].get();
if (texture == nullptr){
texture = pages[0].get();
}
batch->texture(texture);
drawGlyph(batch, x, y, c, style);
}
else if (charpage > page && charpage < next){
next = charpage;
}
x += 8;//getGlyphWidth(c);
}
page = next;
next = MAX_CODEPAGES;
x = init_x;
} while (page < MAX_CODEPAGES);
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef GRAPHICS_CORE_FONT_H_
#define GRAPHICS_CORE_FONT_H_
#include <memory>
#include <string>
#include <vector>
#include "../../typedefs.h"
class Texture;
class Batch2D;
enum class FontStyle {
none,
shadow,
outline
};
class Font {
int lineHeight;
int yoffset;
public:
std::vector<std::unique_ptr<Texture>> pages;
Font(std::vector<std::unique_ptr<Texture>> pages, int lineHeight, int yoffset);
~Font();
int getLineHeight() const;
int getYOffset() const;
/// @brief Calculate text width in pixels
/// @param text selected text
/// @param length max text chunk length (default: no limit)
/// @return pixel width of the text
int calcWidth(std::wstring text, size_t length=-1);
/// @brief Check if character is visible (non-whitespace)
/// @param codepoint character unicode codepoint
bool isPrintableChar(uint codepoint) const;
void draw(Batch2D* batch, std::wstring text, int x, int y);
void draw(Batch2D* batch, std::wstring text, int x, int y, FontStyle style);
void draw(Batch2D* batch, std::wstring_view text, int x, int y, FontStyle style);
};
#endif // GRAPHICS_CORE_FONT_H_
+84
View File
@@ -0,0 +1,84 @@
#include "Framebuffer.h"
#include <GL/glew.h>
#include "Texture.h"
Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture)
: fbo(fbo), depth(depth), texture(std::move(texture))
{
if (texture) {
width = texture->getWidth();
height = texture->getHeight();
} else {
width = 0;
height = 0;
}
}
Framebuffer::Framebuffer(uint width, uint height, bool alpha)
: width(width), height(height)
{
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Setup color attachment (texture)
GLuint tex;
format = alpha ? GL_RGBA : GL_RGB;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
texture = std::make_unique<Texture>(tex, width, height);
// Setup depth attachment
glGenRenderbuffers(1, &depth);
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Framebuffer::~Framebuffer() {
glDeleteFramebuffers(1, &fbo);
glDeleteRenderbuffers(1, &depth);
}
void Framebuffer::bind() {
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
}
void Framebuffer::unbind() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Framebuffer::resize(uint width, uint height) {
if (this->width == width && this->height == height) {
return;
}
this->width = width;
this->height = height;
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
texture->bind();
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
texture->unbind();
}
Texture* Framebuffer::getTexture() const {
return texture.get();
}
uint Framebuffer::getWidth() const {
return width;
}
uint Framebuffer::getHeight() const {
return height;
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef GRAPHICS_CORE_FRAMEBUFFER_H_
#define GRAPHICS_CORE_FRAMEBUFFER_H_
#include "../../typedefs.h"
#include <memory>
class Texture;
class Framebuffer {
uint fbo;
uint depth;
uint width;
uint height;
uint format;
std::unique_ptr<Texture> texture;
public:
Framebuffer(uint fbo, uint depth, std::unique_ptr<Texture> texture);
Framebuffer(uint width, uint height, bool alpha=false);
~Framebuffer();
/// @brief Use framebuffer
void bind();
/// @brief Stop using framebuffer
void unbind();
/// @brief Update framebuffer texture size
/// @param width new width
/// @param height new height
void resize(uint width, uint height);
/// @brief Get framebuffer color attachment
Texture* getTexture() const;
/// @brief Get framebuffer width
uint getWidth() const;
/// @brief Get framebuffer height
uint getHeight() const;
};
#endif // GRAPHICS_CORE_FRAMEBUFFER_H_
+132
View File
@@ -0,0 +1,132 @@
#include "GfxContext.h"
#include <GL/glew.h>
#include "Batch2D.h"
#include "Framebuffer.h"
GfxContext::GfxContext(
const GfxContext* parent,
const Viewport& viewport,
Batch2D* g2d
) : parent(parent),
viewport(viewport),
g2d(g2d)
{}
GfxContext::~GfxContext() {
if (g2d) {
g2d->flush();
}
while (scissorsCount--) {
Window::popScissor();
}
if (parent == nullptr)
return;
if (fbo != parent->fbo) {
if (fbo) {
fbo->unbind();
}
if (parent->fbo) {
parent->fbo->bind();
}
}
Window::viewport(
0, 0,
parent->viewport.getWidth(),
parent->viewport.getHeight()
);
if (depthMask != parent->depthMask) {
glDepthMask(parent->depthMask);
}
if (depthTest != parent->depthTest) {
if (depthTest) glDisable(GL_DEPTH_TEST);
else glEnable(GL_DEPTH_TEST);
}
if (cullFace != parent->cullFace) {
if (cullFace) glDisable(GL_CULL_FACE);
else glEnable(GL_CULL_FACE);
}
if (blendMode != parent->blendMode) {
Window::setBlendMode(parent->blendMode);
}
}
const Viewport& GfxContext::getViewport() const {
return viewport;
}
Batch2D* GfxContext::getBatch2D() const {
return g2d;
}
GfxContext GfxContext::sub() const {
auto ctx = GfxContext(this, viewport, g2d);
ctx.depthTest = depthTest;
ctx.cullFace = cullFace;
return ctx;
}
void GfxContext::setViewport(const Viewport& viewport) {
this->viewport = viewport;
Window::viewport(
0, 0,
viewport.getWidth(),
viewport.getHeight()
);
}
void GfxContext::setFramebuffer(Framebuffer* fbo) {
if (this->fbo == fbo)
return;
this->fbo = fbo;
if (fbo) {
fbo->bind();
}
}
void GfxContext::setDepthMask(bool flag) {
if (depthMask == flag)
return;
depthMask = flag;
glDepthMask(GL_FALSE + flag);
}
void GfxContext::setDepthTest(bool flag) {
if (depthTest == flag)
return;
depthTest = flag;
if (flag) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
}
void GfxContext::setCullFace(bool flag) {
if (cullFace == flag)
return;
cullFace = flag;
if (flag) {
glEnable(GL_CULL_FACE);
} else {
glDisable(GL_CULL_FACE);
}
}
void GfxContext::setBlendMode(blendmode mode) {
if (blendMode == mode)
return;
blendMode = mode;
Window::setBlendMode(mode);
}
void GfxContext::setScissors(glm::vec4 area) {
Window::pushScissor(area);
scissorsCount++;
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef GRAPHICS_CORE_GFX_CONTEXT_H_
#define GRAPHICS_CORE_GFX_CONTEXT_H_
#include "Viewport.h"
#include "../../window/Window.h"
#include "../../typedefs.h"
class Batch2D;
class Framebuffer;
class GfxContext {
const GfxContext* parent;
Viewport viewport;
Batch2D* const g2d;
Framebuffer* fbo = nullptr;
bool depthMask = true;
bool depthTest = false;
bool cullFace = false;
blendmode blendMode = blendmode::normal;
int scissorsCount = 0;
public:
GfxContext(const GfxContext* parent, const Viewport& viewport, Batch2D* g2d);
~GfxContext();
Batch2D* getBatch2D() const;
const Viewport& getViewport() const;
GfxContext sub() const;
void setViewport(const Viewport& viewport);
void setFramebuffer(Framebuffer* fbo);
void setDepthMask(bool flag);
void setDepthTest(bool flag);
void setCullFace(bool flag);
void setBlendMode(blendmode mode);
void setScissors(glm::vec4 area);
};
#endif // GRAPHICS_CORE_GFX_CONTEXT_H_
+305
View File
@@ -0,0 +1,305 @@
#include "ImageData.h"
#include <assert.h>
#include <stdexcept>
inline int min(int a, int b) {
return (a < b) ? a : b;
}
inline int max(int a, int b) {
return (a > b) ? a : b;
}
ImageData::ImageData(ImageFormat format, uint width, uint height)
: format(format), width(width), height(height) {
switch (format) {
case ImageFormat::rgb888: data = new ubyte[width*height*3]{}; break;
case ImageFormat::rgba8888: data = new ubyte[width*height*4]{}; break;
default:
throw std::runtime_error("format is not supported");
}
}
ImageData::ImageData(ImageFormat format, uint width, uint height, void* data)
: format(format), width(width), height(height), data(data) {
}
ImageData::~ImageData() {
switch (format) {
case ImageFormat::rgb888:
case ImageFormat::rgba8888:
delete[] (ubyte*)data;
break;
}
}
void ImageData::flipX() {
uint size;
switch (format) {
case ImageFormat::rgb888:
case ImageFormat::rgba8888: {
size = (format == ImageFormat::rgba8888) ? 4 : 3;
ubyte* pixels = (ubyte*)data;
for (uint y = 0; y < height; y++) {
for (uint x = 0; x < width/2; x++) {
for (uint c = 0; c < size; c++) {
ubyte temp = pixels[(y * width + x) * size + c];
pixels[(y * width + x) * size + c] = pixels[(y * width + (width - x - 1)) * size + c];
pixels[(y * width + (width - x - 1)) * size + c] = temp;
}
}
}
break;
}
default:
throw std::runtime_error("format is not supported");
}
}
void ImageData::flipY() {
uint size;
switch (format) {
case ImageFormat::rgb888:
case ImageFormat::rgba8888: {
size = (format == ImageFormat::rgba8888) ? 4 : 3;
ubyte* pixels = (ubyte*)data;
for (uint y = 0; y < height/2; y++) {
for (uint x = 0; x < width; x++) {
for (uint c = 0; c < size; c++) {
ubyte temp = pixels[(y * width + x) * size + c];
pixels[(y * width + x) * size + c] =
pixels[((height-y-1) * width + x) * size + c];
pixels[((height-y-1) * width + x) * size + c] = temp;
}
}
}
break;
}
default:
throw std::runtime_error("format is not supported");
}
}
void ImageData::blit(const ImageData* image, int x, int y) {
if (format == image->format) {
blitMatchingFormat(image, x, y);
return;
}
if (format == ImageFormat::rgba8888 &&
image->format == ImageFormat::rgb888) {
blitRGB_on_RGBA(image, x, y);
return;
}
throw std::runtime_error("mismatching format");
}
void ImageData::blitRGB_on_RGBA(const ImageData* image, int x, int y) {
ubyte* pixels = static_cast<ubyte*>(data);
ubyte* source = static_cast<ubyte*>(image->getData());
uint srcwidth = image->getWidth();
uint srcheight = image->getHeight();
for (uint srcy = max(0, -y); (int)srcy < min(srcheight, height-y); srcy++) {
for (uint srcx = max(0, -x); (int)srcx < min(srcwidth, width-x); srcx++) {
uint dstx = srcx + x;
uint dsty = srcy + y;
uint dstidx = (dsty * width + dstx) * 4;
uint srcidx = (srcy * srcwidth + srcx) * 3;
for (uint c = 0; c < 3; c++) {
pixels[dstidx + c] = source[srcidx + c];
}
pixels[dstidx + 3] = 255;
}
}
}
void ImageData::blitMatchingFormat(const ImageData* image, int x, int y) {
uint comps;
switch (format) {
case ImageFormat::rgb888: comps = 3; break;
case ImageFormat::rgba8888: comps = 4; break;
default:
throw std::runtime_error("only unsigned byte formats supported");
}
ubyte* pixels = static_cast<ubyte*>(data);
ubyte* source = static_cast<ubyte*>(image->getData());
uint srcwidth = image->getWidth();
uint srcheight = image->getHeight();
for (uint srcy = max(0, -y); (int)srcy < min(srcheight, height-y); srcy++) {
for (uint srcx = max(0, -x); (int)srcx < min(srcwidth, width-x); srcx++) {
uint dstx = srcx + x;
uint dsty = srcy + y;
uint dstidx = (dsty * width + dstx) * comps;
uint srcidx = (srcy * srcwidth + srcx) * comps;
for (uint c = 0; c < comps; c++) {
pixels[dstidx + c] = source[srcidx + c];
}
}
}
}
/* Extrude rectangle zone border pixels out by 1 pixel.
Used to remove atlas texture border artifacts */
void ImageData::extrude(int x, int y, int w, int h) {
uint comps;
switch (format) {
case ImageFormat::rgb888: comps = 3; break;
case ImageFormat::rgba8888: comps = 4; break;
default:
throw std::runtime_error("only unsigned byte formats supported");
}
ubyte* pixels = static_cast<ubyte*>(data);
int rx = x + w - 1;
int ry = y + h - 1;
// top-left pixel
if (x > 0 && (uint)x < width && y > 0 && (uint)y < height) {
uint srcidx = (y * width + x) * comps;
uint dstidx = ((y - 1) * width + x - 1) * comps;
for (uint c = 0; c < comps; c++) {
pixels[dstidx + c] = pixels[srcidx + c];
}
}
// top-right pixel
if (rx >= 0 && (uint)rx < width-1 && y > 0 && (uint)y < height) {
uint srcidx = (y * width + rx) * comps;
uint dstidx = ((y - 1) * width + rx + 1) * comps;
for (uint c = 0; c < comps; c++) {
pixels[dstidx + c] = pixels[srcidx + c];
}
}
// bottom-left pixel
if (x > 0 && (uint)x < width && ry >= 0 && (uint)ry < height-1) {
uint srcidx = (ry * width + x) * comps;
uint dstidx = ((ry + 1) * width + x - 1) * comps;
for (uint c = 0; c < comps; c++) {
pixels[dstidx + c] = pixels[srcidx + c];
}
}
// bottom-right pixel
if (rx >= 0 && (uint)rx < width-1 && ry >= 0 && (uint)ry < height-1) {
uint srcidx = (ry * width + rx) * comps;
uint dstidx = ((ry + 1) * width + rx + 1) * comps;
for (uint c = 0; c < comps; c++) {
pixels[dstidx + c] = pixels[srcidx + c];
}
}
// left border
if (x > 0 && (uint)x < width) {
for (uint ey = max(y, 0); (int)ey < y + h; ey++) {
uint srcidx = (ey * width + x) * comps;
uint dstidx = (ey * width + x - 1) * comps;
for (uint c = 0; c < comps; c++) {
pixels[dstidx + c] = pixels[srcidx + c];
}
}
}
// top border
if (y > 0 && (uint)y < height) {
for (uint ex = max(x, 0); (int)ex < x + w; ex++) {
uint srcidx = (y * width + ex) * comps;
uint dstidx = ((y-1) * width + ex) * comps;
for (uint c = 0; c < comps; c++) {
pixels[dstidx + c] = pixels[srcidx + c];
}
}
}
// right border
if (rx >= 0 && (uint)rx < width-1) {
for (uint ey = max(y, 0); (int)ey < y + h; ey++) {
uint srcidx = (ey * width + rx) * comps;
uint dstidx = (ey * width + rx + 1) * comps;
for (uint c = 0; c < comps; c++) {
pixels[dstidx + c] = pixels[srcidx + c];
}
}
}
// bottom border
if (ry >= 0 && (uint)ry < height-1) {
for (uint ex = max(x, 0); (int)ex < x + w; ex++) {
uint srcidx = (ry * width + ex) * comps;
uint dstidx = ((ry+1) * width + ex) * comps;
for (uint c = 0; c < comps; c++) {
pixels[dstidx + c] = pixels[srcidx + c];
}
}
}
}
void ImageData::fixAlphaColor() {
ubyte* pixels = static_cast<ubyte*>(data);
// Fixing black transparent pixels for Mip-Mapping
for (uint ly = 0; ly < height-1; ly++) {
for (uint lx = 0; lx < width-1; lx++) {
if (pixels[((ly) * width + lx) * 4 + 3]) {
for (int c = 0; c < 3; c++) {
int val = pixels[((ly) + + lx) * 4 + c];
if (pixels[((ly) * width + lx + 1) * 4 + 3] == 0)
pixels[((ly) * width + lx + 1) * 4 + c] = val;
if (pixels[((ly + 1) * width + lx) * 4 + 3] == 0)
pixels[((ly + 1) * width + lx) * 4 + c] = val;
}
}
}
}
}
ImageData* add_atlas_margins(ImageData* image, int grid_size) {
// RGBA is only supported
assert(image->getFormat() == ImageFormat::rgba8888);
assert(image->getWidth() == image->getHeight());
int srcwidth = image->getWidth();
int srcheight = image->getHeight();
int dstwidth = srcwidth + grid_size * 2;
int dstheight = srcheight + grid_size * 2;
const ubyte* srcdata = (const ubyte*)image->getData();
ubyte* dstdata = new ubyte[dstwidth*dstheight * 4];
int imgres = image->getWidth() / grid_size;
for (int row = 0; row < grid_size; row++) {
for (int col = 0; col < grid_size; col++) {
int sox = col * imgres;
int soy = row * imgres;
int dox = 1 + col * (imgres + 2);
int doy = 1 + row * (imgres + 2);
for (int ly = -1; ly <= imgres; ly++) {
for (int lx = -1; lx <= imgres; lx++) {
int sy = max(min(ly, imgres-1), 0);
int sx = max(min(lx, imgres-1), 0);
for (int c = 0; c < 4; c++)
dstdata[((doy+ly) * dstwidth + dox + lx) * 4 + c] =
srcdata[((soy+sy) * srcwidth + sox + sx) * 4 + c];
}
}
// Fixing black transparent pixels for Mip-Mapping
for (int ly = 0; ly < imgres; ly++) {
for (int lx = 0; lx < imgres; lx++) {
if (srcdata[((soy+ly) * srcwidth + sox + lx) * 4 + 3]) {
for (int c = 0; c < 3; c++) {
int val = srcdata[((soy+ly) * srcwidth + sox + lx) * 4 + c];
if (dstdata[((doy+ly) * dstwidth + dox + lx + 1) * 4 + 3] == 0)
dstdata[((doy+ly) * dstwidth + dox + lx + 1) * 4 + c] = val;
if (dstdata[((doy+ly + 1) * dstwidth + dox + lx) * 4 + 3] == 0)
dstdata[((doy+ly + 1) * dstwidth + dox + lx) * 4 + c] = val;
}
}
}
}
}
}
return new ImageData(image->getFormat(), dstwidth, dstheight, dstdata);
}
+49
View File
@@ -0,0 +1,49 @@
#ifndef GRAPHICS_CORE_IMAGE_DATA_H_
#define GRAPHICS_CORE_IMAGE_DATA_H_
#include "../../typedefs.h"
enum class ImageFormat {
rgb888,
rgba8888
};
class ImageData {
ImageFormat format;
uint width;
uint height;
void* data;
public:
ImageData(ImageFormat format, uint width, uint height);
ImageData(ImageFormat format, uint width, uint height, void* data);
~ImageData();
void flipX();
void flipY();
void blitRGB_on_RGBA(const ImageData* image, int x, int y);
void blitMatchingFormat(const ImageData* image, int x, int y);
void blit(const ImageData* image, int x, int y);
void extrude(int x, int y, int w, int h);
void fixAlphaColor();
void* getData() const {
return data;
}
ImageFormat getFormat() const {
return format;
}
uint getWidth() const {
return width;
}
uint getHeight() const {
return height;
}
};
extern ImageData* add_atlas_margins(ImageData* image, int grid_size);
#endif // GRAPHICS_CORE_IMAGE_DATA_H_
+79
View File
@@ -0,0 +1,79 @@
#include "LineBatch.h"
#include "Mesh.h"
#include <GL/glew.h>
inline constexpr uint LB_VERTEX_SIZE = (3+4);
LineBatch::LineBatch(size_t capacity) : capacity(capacity) {
const vattr attrs[] = { {3},{4}, {0} };
buffer = new float[capacity * LB_VERTEX_SIZE * 2];
mesh = std::make_unique<Mesh>(buffer, 0, attrs);
index = 0;
}
LineBatch::~LineBatch(){
delete[] buffer;
}
void LineBatch::line(
float x1, float y1,
float z1, float x2,
float y2, float z2,
float r, float g, float b, float a
) {
if (index + LB_VERTEX_SIZE * 2 >= capacity) {
render();
}
buffer[index] = x1;
buffer[index+1] = y1;
buffer[index+2] = z1;
buffer[index+3] = r;
buffer[index+4] = g;
buffer[index+5] = b;
buffer[index+6] = a;
index += LB_VERTEX_SIZE;
buffer[index] = x2;
buffer[index+1] = y2;
buffer[index+2] = z2;
buffer[index+3] = r;
buffer[index+4] = g;
buffer[index+5] = b;
buffer[index+6] = a;
index += LB_VERTEX_SIZE;
}
void LineBatch::box(float x, float y, float z, float w, float h, float d,
float r, float g, float b, float a) {
w *= 0.5f;
h *= 0.5f;
d *= 0.5f;
line(x-w, y-h, z-d, x+w, y-h, z-d, r,g,b,a);
line(x-w, y+h, z-d, x+w, y+h, z-d, r,g,b,a);
line(x-w, y-h, z+d, x+w, y-h, z+d, r,g,b,a);
line(x-w, y+h, z+d, x+w, y+h, z+d, r,g,b,a);
line(x-w, y-h, z-d, x-w, y+h, z-d, r,g,b,a);
line(x+w, y-h, z-d, x+w, y+h, z-d, r,g,b,a);
line(x-w, y-h, z+d, x-w, y+h, z+d, r,g,b,a);
line(x+w, y-h, z+d, x+w, y+h, z+d, r,g,b,a);
line(x-w, y-h, z-d, x-w, y-h, z+d, r,g,b,a);
line(x+w, y-h, z-d, x+w, y-h, z+d, r,g,b,a);
line(x-w, y+h, z-d, x-w, y+h, z+d, r,g,b,a);
line(x+w, y+h, z-d, x+w, y+h, z+d, r,g,b,a);
}
void LineBatch::render(){
if (index == 0)
return;
mesh->reload(buffer, index / LB_VERTEX_SIZE);
mesh->draw(GL_LINES);
index = 0;
}
void LineBatch::lineWidth(float width) {
glLineWidth(width);
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef GRAPHICS_CORE_LINEBATCH_H_
#define GRAPHICS_CORE_LINEBATCH_H_
#include <memory>
#include <stdlib.h>
#include <glm/glm.hpp>
class Mesh;
class LineBatch {
std::unique_ptr<Mesh> mesh;
float* buffer;
size_t index;
size_t capacity;
public:
LineBatch(size_t capacity=4096);
~LineBatch();
inline void line(const glm::vec3 a, const glm::vec3 b, const glm::vec4 color) {
line(a.x, a.y, a.z, b.x, b.y, b.z, color.r, color.g, color.b, color.a);
}
void line(float x1, float y1, float z1, float x2, float y2, float z2,
float r, float g, float b, float a);
void box(float x, float y, float z, float w, float h, float d,
float r, float g, float b, float a);
inline void box(glm::vec3 xyz, glm::vec3 whd, glm::vec4 rgba) {
box(xyz.x, xyz.y, xyz.z, whd.x, whd.y, whd.z,
rgba.r, rgba.g, rgba.b, rgba.a);
}
void render();
void lineWidth(float width);
};
#endif // GRAPHICS_CORE_LINEBATCH_H_
+75
View File
@@ -0,0 +1,75 @@
#include "Mesh.h"
#include <GL/glew.h>
int Mesh::meshesCount = 0;
Mesh::Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const vattr* attrs) :
ibo(0),
vertices(vertices),
indices(indices)
{
meshesCount++;
vertexSize = 0;
for (int i = 0; attrs[i].size; i++) {
vertexSize += attrs[i].size;
}
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
reload(vertexBuffer, vertices, indexBuffer, indices);
// attributes
int offset = 0;
for (int i = 0; attrs[i].size; i++) {
int size = attrs[i].size;
glVertexAttribPointer(i, size, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (GLvoid*)(offset * sizeof(float)));
glEnableVertexAttribArray(i);
offset += size;
}
glBindVertexArray(0);
}
Mesh::~Mesh(){
meshesCount--;
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
if (ibo != 0) glDeleteBuffers(1, &ibo);
}
void Mesh::reload(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices){
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
if (vertexBuffer != nullptr && vertices != 0) {
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, vertexBuffer, GL_STATIC_DRAW);
}
else {
glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STATIC_DRAW);
}
if (indexBuffer != nullptr && indices != 0) {
if (ibo == 0) glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * indices, indexBuffer, GL_STATIC_DRAW);
}
else if (ibo != 0) {
glDeleteBuffers(1, &ibo);
}
this->vertices = vertices;
this->indices = indices;
}
void Mesh::draw(unsigned int primitive){
glBindVertexArray(vao);
if (ibo != 0) {
glDrawElements(primitive, indices, GL_UNSIGNED_INT, 0);
}
else {
glDrawArrays(primitive, 0, vertices);
}
glBindVertexArray(0);
}
void Mesh::draw() {
draw(GL_TRIANGLES);
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef GRAPHICS_CORE_MESH_H_
#define GRAPHICS_CORE_MESH_H_
#include <stdlib.h>
#include "../../typedefs.h"
struct vattr {
ubyte size;
};
class Mesh {
unsigned int vao;
unsigned int vbo;
unsigned int ibo;
size_t vertices;
size_t indices;
size_t vertexSize;
public:
Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const vattr* attrs);
Mesh(const float* vertexBuffer, size_t vertices, const vattr* attrs) :
Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {};
~Mesh();
/// @brief Update GL vertex and index buffers data without changing VAO attributes
/// @param vertexBuffer vertex data buffer
/// @param vertices number of vertices in new buffer
/// @param indexBuffer indices buffer
/// @param indices number of values in indices buffer
void reload(const float* vertexBuffer, size_t vertices, const int* indexBuffer = nullptr, size_t indices = 0);
/// @brief Draw mesh with specified primitives type
/// @param primitive primitives type
void draw(unsigned int primitive);
/// @brief Draw mesh as triangles
void draw();
/// @brief Total numbers of alive mesh objects
static int meshesCount;
};
#endif // GRAPHICS_CORE_MESH_H_
+42
View File
@@ -0,0 +1,42 @@
#include "PostProcessing.h"
#include "Mesh.h"
#include "Shader.h"
#include "Texture.h"
#include "Framebuffer.h"
#include <stdexcept>
PostProcessing::PostProcessing() {
// Fullscreen quad mesh bulding
float vertices[] {
-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f
};
vattr attrs[] {{2}, {0}};
quadMesh = std::make_unique<Mesh>(vertices, 6, attrs);
}
PostProcessing::~PostProcessing() {
}
void PostProcessing::use(GfxContext& context) {
const auto& vp = context.getViewport();
if (fbo) {
fbo->resize(vp.getWidth(), vp.getHeight());
} else {
fbo = std::make_unique<Framebuffer>(vp.getWidth(), vp.getHeight());
}
context.setFramebuffer(fbo.get());
}
void PostProcessing::render(const GfxContext& context, Shader* screenShader) {
if (fbo == nullptr) {
throw std::runtime_error("'use(...)' was never called");
}
const auto& viewport = context.getViewport();
screenShader->use();
screenShader->uniform2i("u_screenSize", viewport.size());
fbo->getTexture()->bind();
quadMesh->draw();
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef GRAPHICS_CORE_POST_PROCESSING_H_
#define GRAPHICS_CORE_POST_PROCESSING_H_
#include "Viewport.h"
#include "GfxContext.h"
#include <memory>
class Mesh;
class Shader;
class Framebuffer;
/// @brief Framebuffer with blitting with shaders.
/// @attention Current implementation does not support multiple render passes
/// for multiple effects. Will be implemented in v0.21
class PostProcessing {
/// @brief Main framebuffer (lasy field)
std::unique_ptr<Framebuffer> fbo;
/// @brief Fullscreen quad mesh as the post-processing canvas
std::unique_ptr<Mesh> quadMesh;
public:
PostProcessing();
~PostProcessing();
/// @brief Prepare and bind framebuffer
/// @param context graphics context will be modified
void use(GfxContext& context);
/// @brief Render fullscreen quad using the passed shader
/// with framebuffer texture bound
/// @param context graphics context
/// @param screenShader shader used for fullscreen quad
/// @throws std::runtime_error if use(...) wasn't called before
void render(const GfxContext& context, Shader* screenShader);
};
#endif // GRAPHICS_CORE_POST_PROCESSING_H_
+133
View File
@@ -0,0 +1,133 @@
#include "Shader.h"
#include <exception>
#include <fstream>
#include <iostream>
#include <sstream>
#include <filesystem>
#include <glm/gtc/type_ptr.hpp>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "../../coders/GLSLExtension.h"
namespace fs = std::filesystem;
GLSLExtension* Shader::preprocessor = new GLSLExtension();
Shader::Shader(unsigned int id) : id(id){
}
Shader::~Shader(){
glDeleteProgram(id);
}
void Shader::use(){
glUseProgram(id);
}
void Shader::uniformMatrix(std::string name, glm::mat4 matrix){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(matrix));
}
void Shader::uniform1i(std::string name, int x){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform1i(transformLoc, x);
}
void Shader::uniform1f(std::string name, float x){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform1f(transformLoc, x);
}
void Shader::uniform2f(std::string name, float x, float y){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform2f(transformLoc, x, y);
}
void Shader::uniform2f(std::string name, glm::vec2 xy){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform2f(transformLoc, xy.x, xy.y);
}
void Shader::uniform2i(std::string name, glm::ivec2 xy){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform2i(transformLoc, xy.x, xy.y);
}
void Shader::uniform3f(std::string name, float x, float y, float z){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform3f(transformLoc, x,y,z);
}
void Shader::uniform3f(std::string name, glm::vec3 xyz){
GLuint transformLoc = glGetUniformLocation(id, name.c_str());
glUniform3f(transformLoc, xyz.x, xyz.y, xyz.z);
}
Shader* Shader::create(
std::string vertexFile,
std::string fragmentFile,
std::string vertexCode,
std::string fragmentCode
) {
vertexCode = preprocessor->process(fs::path(vertexFile), vertexCode);
fragmentCode = preprocessor->process(fs::path(fragmentFile), fragmentCode);
const GLchar* vShaderCode = vertexCode.c_str();
const GLchar* fShaderCode = fragmentCode.c_str();
GLuint vertex, fragment;
GLint success;
GLchar infoLog[512];
// Vertex Shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, nullptr);
glCompileShader(vertex);
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(vertex, 512, nullptr, infoLog);
std::cerr << "SHADER::VERTEX: compilation failed: " << vertexFile << std::endl;
std::cerr << infoLog << std::endl;
return nullptr;
}
// Fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, nullptr);
glCompileShader(fragment);
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(fragment, 512, nullptr, infoLog);
std::cerr << "SHADER::FRAGMENT: compilation failed: " << vertexFile << std::endl;
std::cerr << infoLog << std::endl;
return nullptr;
}
// Shader Program
GLuint id = glCreateProgram();
glAttachShader(id, vertex);
glAttachShader(id, fragment);
glLinkProgram(id);
glGetProgramiv(id, GL_LINK_STATUS, &success);
if (!success){
glGetProgramInfoLog(id, 512, nullptr, infoLog);
std::cerr << "SHADER::PROGRAM: linking failed" << std::endl;
std::cerr << infoLog << std::endl;
glDeleteShader(vertex);
glDeleteShader(fragment);
return nullptr;
}
glDeleteShader(vertex);
glDeleteShader(fragment);
return new Shader(id);
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef GRAPHICS_CORE_SHADER_H_
#define GRAPHICS_CORE_SHADER_H_
#include <string>
#include <glm/glm.hpp>
#include "../../typedefs.h"
class GLSLExtension;
class Shader {
uint id;
public:
static GLSLExtension* preprocessor;
Shader(unsigned int id);
~Shader();
void use();
void uniformMatrix(std::string name, glm::mat4 matrix);
void uniform1i(std::string name, int x);
void uniform1f(std::string name, float x);
void uniform2f(std::string name, float x, float y);
void uniform2f(std::string name, glm::vec2 xy);
void uniform2i(std::string name, glm::ivec2 xy);
void uniform3f(std::string name, float x, float y, float z);
void uniform3f(std::string name, glm::vec3 xyz);
static Shader* create(
std::string vertexFile,
std::string fragmentFile,
std::string vertexSource,
std::string fragmentSource
);
};
#endif // GRAPHICS_SHADER_H_
+82
View File
@@ -0,0 +1,82 @@
#include "Texture.h"
#include <GL/glew.h>
#include <stdexcept>
#include <memory>
#include "ImageData.h"
#include "gl_util.h"
Texture::Texture(uint id, uint width, uint height)
: id(id), width(width), height(height) {
}
Texture::Texture(ubyte* data, uint width, uint height, ImageFormat imageFormat)
: width(width), height(height) {
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLenum format = gl::to_gl_format(imageFormat);
glTexImage2D(
GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, (GLvoid *) data
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glBindTexture(GL_TEXTURE_2D, 0);
}
Texture::~Texture() {
glDeleteTextures(1, &id);
}
void Texture::bind(){
glBindTexture(GL_TEXTURE_2D, id);
}
void Texture::unbind() {
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::reload(ubyte* data){
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) data);
glBindTexture(GL_TEXTURE_2D, 0);
}
ImageData* Texture::readData() {
std::unique_ptr<ubyte[]> data (new ubyte[width * height * 4]);
glBindTexture(GL_TEXTURE_2D, id);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.get());
glBindTexture(GL_TEXTURE_2D, 0);
return new ImageData(ImageFormat::rgba8888, width, height, data.release());
}
void Texture::setNearestFilter() {
bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
}
Texture* Texture::from(const ImageData* image) {
uint width = image->getWidth();
uint height = image->getHeight();
const void* data = image->getData();
return new Texture((ubyte*)data, width, height, image->getFormat());
}
uint Texture::getWidth() const {
return width;
}
uint Texture::getHeight() const {
return height;
}
uint Texture::getId() const {
return id;
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef GRAPHICS_CORE_TEXTURE_H_
#define GRAPHICS_CORE_TEXTURE_H_
#include <string>
#include "../../typedefs.h"
#include "ImageData.h"
class Texture {
protected:
uint id;
uint width;
uint height;
public:
Texture(uint id, uint width, uint height);
Texture(ubyte* data, uint width, uint height, ImageFormat format);
virtual ~Texture();
virtual void bind();
virtual void unbind();
virtual void reload(ubyte* data);
void setNearestFilter();
virtual ImageData* readData();
virtual uint getWidth() const;
virtual uint getHeight() const;
virtual uint getId() const;
static Texture* from(const ImageData* image);
};
#endif // GRAPHICS_CORE_TEXTURE_H_
+90
View File
@@ -0,0 +1,90 @@
#include "TextureAnimation.h"
#include "Texture.h"
#include "Framebuffer.h"
#include <GL/glew.h>
#include <unordered_set>
TextureAnimator::TextureAnimator() {
glGenFramebuffers(1, &fboR);
glGenFramebuffers(1, &fboD);
}
TextureAnimator::~TextureAnimator() {
glDeleteFramebuffers(1, &fboR);
glDeleteFramebuffers(1, &fboD);
}
void TextureAnimator::addAnimations(const std::vector<TextureAnimation>& animations) {
for (const auto& elem : animations) {
addAnimation(elem);
}
}
void TextureAnimator::update(float delta) {
std::unordered_set<uint> changedTextures;
for (auto& elem : animations) {
elem.timer += delta;
size_t frameNum = elem.currentFrame;
Frame frame = elem.frames[elem.currentFrame];
while (elem.timer >= frame.duration) {
elem.timer -= frame.duration;
elem.currentFrame++;
if (elem.currentFrame >= elem.frames.size()) elem.currentFrame = 0;
frame = elem.frames[elem.currentFrame];
}
if (frameNum != elem.currentFrame){
uint elemDstId = elem.dstTexture->getId();
uint elemSrcId = elem.srcTexture->getId();
if (changedTextures.find(elemDstId) == changedTextures.end())
changedTextures.insert(elemDstId);
glBindFramebuffer(GL_FRAMEBUFFER, fboD);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, elemDstId, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fboR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, elemSrcId, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboD);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboR);
float srcPosY = elem.srcTexture->getHeight() - frame.size.y - frame.srcPos.y; // vertical flip
// Extensions
const int ext = 2;
for (int y = -1; y <= 1; y++) {
for (int x = -1; x <= 1; x++) {
if (x == 0 && y == 0)
continue;
glBlitFramebuffer(
frame.srcPos.x, srcPosY, frame.srcPos.x + frame.size.x, srcPosY + frame.size.y,
frame.dstPos.x+x*ext, frame.dstPos.y+y*ext,
frame.dstPos.x + frame.size.x+x*ext, frame.dstPos.y + frame.size.y+y*ext,
GL_COLOR_BUFFER_BIT, GL_NEAREST
);
}
}
glBlitFramebuffer(
frame.srcPos.x, srcPosY,
frame.srcPos.x + frame.size.x,
srcPosY + frame.size.y,
frame.dstPos.x, frame.dstPos.y,
frame.dstPos.x + frame.size.x,
frame.dstPos.y + frame.size.y,
GL_COLOR_BUFFER_BIT, GL_NEAREST
);
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
for (auto& elem : changedTextures) {
glBindTexture(GL_TEXTURE_2D, elem);
glGenerateMipmap(GL_TEXTURE_2D);
}
glBindTexture(GL_TEXTURE_2D, 0);
}
+52
View File
@@ -0,0 +1,52 @@
#ifndef GRAPHICS_CORE_TEXTURE_ANIMATION_H_
#define GRAPHICS_CORE_TEXTURE_ANIMATION_H_
#include "../../typedefs.h"
#include <glm/glm.hpp>
#include <vector>
class Assets;
class Texture;
class Framebuffer;
constexpr float DEFAULT_FRAME_DURATION = 0.150f;
struct Frame {
glm::ivec2 srcPos;
glm::ivec2 dstPos;
glm::ivec2 size;
float duration = DEFAULT_FRAME_DURATION;
};
class TextureAnimation {
public:
TextureAnimation(Texture* srcTex, Texture* dstTex) : srcTexture(srcTex), dstTexture(dstTex) {};
~TextureAnimation() {};
void addFrame(const Frame& frame) { frames.emplace_back(frame); };
size_t currentFrame = 0;
float timer = 0.f;
Texture* srcTexture;
Texture* dstTexture;
std::vector<Frame> frames;
};
class TextureAnimator {
public:
TextureAnimator();
~TextureAnimator();
void addAnimation(const TextureAnimation& animation) { animations.emplace_back(animation); };
void addAnimations(const std::vector<TextureAnimation>& animations);
void update(float delta);
private:
uint fboR;
uint fboD;
std::vector<TextureAnimation> animations;
};
#endif // GRAPHICS_CORE_TEXTURE_ANIMATION_H_
+1
View File
@@ -0,0 +1 @@
#include "UVRegion.h"
+17
View File
@@ -0,0 +1,17 @@
#ifndef GRAPHICS_CORE_UVREGION_H_
#define GRAPHICS_CORE_UVREGION_H_
class UVRegion {
public:
float u1;
float v1;
float u2;
float v2;
UVRegion(float u1, float v1, float u2, float v2)
: u1(u1), v1(v1), u2(u2), v2(v2){}
UVRegion() : u1(0.0f), v1(0.0f), u2(1.0f), v2(1.0f){}
};
#endif // SRC_GRAPHICS_UVREGION_H_
+13
View File
@@ -0,0 +1,13 @@
#include "Viewport.h"
Viewport::Viewport(uint width, uint height)
: width(width), height(height) {
}
uint Viewport::getWidth() const {
return width;
}
uint Viewport::getHeight() const {
return height;
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef GRAPHICS_CORE_VIEWPORT_H_
#define GRAPHICS_CORE_VIEWPORT_H_
#include <glm/glm.hpp>
#include "../../typedefs.h"
class Viewport {
uint width;
uint height;
public:
Viewport(uint width, uint height);
virtual uint getWidth() const;
virtual uint getHeight() const;
glm::ivec2 size() const {
return glm::ivec2(width, height);
}
};
#endif // GRAPHICS_VIEWPORT_H_
+19
View File
@@ -0,0 +1,19 @@
#ifndef GRAPHICS_CORE_GL_UTIL_H_
#define GRAPHICS_CORE_GL_UTIL_H_
#include <GL/glew.h>
#include "ImageData.h"
namespace gl {
inline GLenum to_gl_format(ImageFormat imageFormat) {
switch (imageFormat) {
case ImageFormat::rgb888: return GL_RGB;
case ImageFormat::rgba8888: return GL_RGBA;
default:
return 0;
}
}
}
#endif // GRAPHICS_CORE_GL_UTIL_H_