From a4a5aef4228138586b06a2b9b6128db2015b8a8c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 26 Jan 2024 02:49:42 +0300 Subject: [PATCH] skybox: added moon and stars --- res/shaders/main.glslv | 1 + res/shaders/skybox_gen.glslf | 2 +- res/textures/misc/moon.png | Bin 0 -> 39273 bytes res/textures/misc/sun.png | Bin 0 -> 22686 bytes src/assets/AssetsLoader.cpp | 2 + src/coders/gzip.h | 8 ++ src/coders/png.cpp | 4 +- src/frontend/WorldRenderer.cpp | 23 +++--- src/frontend/WorldRenderer.h | 3 + src/frontend/graphics/Skybox.cpp | 123 +++++++++++++++++++++++++++---- src/frontend/graphics/Skybox.h | 33 ++++++++- src/graphics/Batch3D.cpp | 22 ++++-- src/graphics/Batch3D.h | 2 + src/graphics/GfxContext.cpp | 26 ++++++- src/graphics/GfxContext.h | 5 ++ src/graphics/Texture.cpp | 7 ++ src/graphics/Texture.h | 2 + src/logic/BlocksController.cpp | 6 +- src/logic/BlocksController.h | 2 + src/maths/fastmaths.h | 22 ++++-- src/window/Window.cpp | 11 +++ src/window/Window.h | 6 ++ 22 files changed, 258 insertions(+), 52 deletions(-) create mode 100644 res/textures/misc/moon.png create mode 100644 res/textures/misc/sun.png diff --git a/res/shaders/main.glslv b/res/shaders/main.glslv index ffbf1d43..f368328d 100644 --- a/res/shaders/main.glslv +++ b/res/shaders/main.glslv @@ -39,6 +39,7 @@ void main(){ skyLightColor.g *= 0.9; skyLightColor.b *= 0.8; skyLightColor = min(vec3(1.0), skyLightColor*SKY_LIGHT_MUL); + skyLightColor = max(vec3(0.1, 0.11, 0.14), skyLightColor); a_color.rgb = max(a_color.rgb, skyLightColor.rgb*decomp_light.a); a_distance = length(u_view * u_model * vec4(pos3d.x, pos3d.y*0.2, pos3d.z, 0.0)); diff --git a/res/shaders/skybox_gen.glslf b/res/shaders/skybox_gen.glslf index 8edff477..27c8f567 100644 --- a/res/shaders/skybox_gen.glslf +++ b/res/shaders/skybox_gen.glslf @@ -277,7 +277,7 @@ void main() { MIE_BETA, // Mie scattering coefficient ABSORPTION_BETA, // Absorbtion coefficient AMBIENT_BETA, // ambient scattering, turned off for now. This causes the air to glow a bit when no light reaches it - G*fog, // Mie preferred scattering direction + G*fog*0.7, // Mie preferred scattering direction HEIGHT_RAY, // Rayleigh scale height HEIGHT_MIE*u_mie*u_mie, // Mie scale height HEIGHT_ABSORPTION, // the height at which the most absorption happens diff --git a/res/textures/misc/moon.png b/res/textures/misc/moon.png new file mode 100644 index 0000000000000000000000000000000000000000..8f68b989fcc28137a14bba7427b45eee20a478ab GIT binary patch literal 39273 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 compress(const ubyte* src, size_t size); + + /* Decompress bytes array from GZIP + @param src GZIP data + @param size length of GZIP data */ std::vector decompress(const ubyte* src, size_t size); } diff --git a/src/coders/png.cpp b/src/coders/png.cpp index 36287669..9ac44525 100644 --- a/src/coders/png.cpp +++ b/src/coders/png.cpp @@ -355,7 +355,9 @@ Texture* png::load_texture(std::string filename) { std::cerr << "Could not load texture " << filename << std::endl; return nullptr; } - return Texture::from(image.get()); + auto texture = Texture::from(image.get()); + texture->setNearestFilter(); + return texture; } void png::write_image(std::string filename, const ImageData* image) { diff --git a/src/frontend/WorldRenderer.cpp b/src/frontend/WorldRenderer.cpp index 8ae83df0..d61394b4 100644 --- a/src/frontend/WorldRenderer.cpp +++ b/src/frontend/WorldRenderer.cpp @@ -5,13 +5,14 @@ #include #include -#include "../content/Content.h" -#include "../graphics/ChunksRenderer.h" #include "../window/Window.h" #include "../window/Camera.h" +#include "../content/Content.h" +#include "../graphics/ChunksRenderer.h" #include "../graphics/Mesh.h" #include "../graphics/Atlas.h" #include "../graphics/Shader.h" +#include "../graphics/Batch3D.h" #include "../graphics/Texture.h" #include "../graphics/LineBatch.h" #include "../voxels/Chunks.h" @@ -46,7 +47,8 @@ WorldRenderer::WorldRenderer(Engine* engine, LevelFrontend* frontend) lineBatch(new LineBatch()), renderer(new ChunksRenderer(level, frontend->getContentGfxCache(), - engine->getSettings())) { + engine->getSettings())), + batch3d(new Batch3D(4096)) { auto& settings = engine->getSettings(); level->events->listen(EVT_CHUNK_HIDDEN, @@ -129,31 +131,24 @@ void WorldRenderer::drawChunks(Chunks* chunks, void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible){ + Window::clearDepth(); EngineSettings& settings = engine->getSettings(); - skybox->refresh(level->world->daytime, - 1.0f+fog*2.0f, 4); + skybox->refresh(pctx, level->world->daytime, 1.0f+fog*2.0f, 4); const Content* content = level->content; auto indices = content->getIndices(); Assets* assets = engine->getAssets(); Atlas* atlas = assets->getAtlas("blocks"); Shader* shader = assets->getShader("main"); - Shader* linesShader = assets->getShader("lines"); const Viewport& viewport = pctx.getViewport(); int displayWidth = viewport.getWidth(); int displayHeight = viewport.getHeight(); - Window::clearDepth(); - Window::viewport(0, 0, displayWidth, displayHeight); // Drawing background sky plane - Shader* backShader = assets->getShader("background"); - backShader->use(); - backShader->uniformMatrix("u_view", camera->getView(false)); - backShader->uniform1f("u_zoom", camera->zoom*camera->getFov()/(3.141592*0.5f)); - backShader->uniform1f("u_ar", float(displayWidth)/float(displayHeight)); - skybox->draw(backShader); + skybox->draw(pctx, camera, assets, level->getWorld()->daytime, fog); + Shader* linesShader = assets->getShader("lines"); { GfxContext ctx = pctx.sub(); ctx.depthTest(true); diff --git a/src/frontend/WorldRenderer.h b/src/frontend/WorldRenderer.h index bb500c3b..c08b37fb 100644 --- a/src/frontend/WorldRenderer.h +++ b/src/frontend/WorldRenderer.h @@ -2,6 +2,7 @@ #define WORLD_RENDERER_CPP #include +#include #include #include #include @@ -14,6 +15,7 @@ class Level; class Camera; +class Batch3D; class LineBatch; class ChunksRenderer; class Shader; @@ -31,6 +33,7 @@ class WorldRenderer { LineBatch* lineBatch; ChunksRenderer* renderer; Skybox* skybox; + std::unique_ptr batch3d; bool drawChunk(size_t index, Camera* camera, Shader* shader, bool culling); void drawChunks(Chunks* chunks, Camera* camera, Shader* shader); public: diff --git a/src/frontend/graphics/Skybox.cpp b/src/frontend/graphics/Skybox.cpp index 859dd380..82bc6f36 100644 --- a/src/frontend/graphics/Skybox.cpp +++ b/src/frontend/graphics/Skybox.cpp @@ -1,19 +1,28 @@ #include "Skybox.h" -#include + #include +#include #include +#include "../../assets/Assets.h" #include "../../graphics/Shader.h" #include "../../graphics/Mesh.h" +#include "../../graphics/Batch3D.h" #include "../../window/Window.h" +#include "../../window/Camera.h" #ifndef M_PI #define M_PI 3.141592 #endif // M_PI -using glm::vec3; +const int STARS_COUNT = 3000; +const int STARS_SEED = 632; -Skybox::Skybox(uint size, Shader* shader) : size(size), shader(shader) { +Skybox::Skybox(uint size, Shader* shader) + : size(size), + shader(shader), + batch3d(new Batch3D(4096)) +{ glGenTextures(1, &cubemap); glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -31,30 +40,118 @@ Skybox::Skybox(uint size, Shader* shader) : size(size), shader(shader) { -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f }; vattr attrs[] {2, 0}; - mesh = new Mesh(vertices, 6, attrs); + mesh = std::make_unique(vertices, 6, attrs); + + sprites.push_back(skysprite { + "misc/moon", + M_PI*0.5f, + 4.0f, + false + }); + + sprites.push_back(skysprite { + "misc/sun", + M_PI*1.5f, + 4.0f, + true + }); } Skybox::~Skybox() { glDeleteTextures(1, &cubemap); glDeleteFramebuffers(1, &fbo); - delete mesh; } -void Skybox::draw(Shader* shader) { - shader->uniform1i("u_cubemap", 1); +void Skybox::drawBackground(Camera* camera, Assets* assets, int width, int height) { + Shader* backShader = assets->getShader("background"); + backShader->use(); + backShader->uniformMatrix("u_view", camera->getView(false)); + backShader->uniform1f("u_zoom", camera->zoom*camera->getFov()/(M_PI*0.5f)); + backShader->uniform1f("u_ar", float(width)/float(height)); + backShader->uniform1i("u_cubemap", 1); bind(); mesh->draw(); unbind(); } -void Skybox::refresh(float t, float mie, uint quality) { +void Skybox::drawStars(Camera* camera, float angle, float opacity) { + batch3d->texture(nullptr); + random.setSeed(STARS_SEED); + for (int i = 0; i < STARS_COUNT; i++) { + float rx = (random.randFloat()) - 0.5f; + float ry = (random.randFloat()) - 0.5f; + float z = (random.randFloat()) - 0.5f; + float x = rx * sin(angle) + ry * -cos(angle); + float y = rx * cos(angle) + ry * sin(angle); + + float sopacity = random.randFloat(); + if (y < 0.0f) + continue; + + sopacity *= (0.2f+sqrt(cos(angle))*0.5) - 0.05; + glm::vec4 tint (1,1,1, sopacity * opacity); + batch3d->point(camera->position + glm::vec3(x, y, z), tint); + } + batch3d->flushPoints(); +} + +void Skybox::draw( + const GfxContext& pctx, + Camera* camera, + Assets* assets, + float daytime, + float fog) +{ + const Viewport& viewport = pctx.getViewport(); + int width = viewport.getWidth(); + int height = viewport.getHeight(); + + drawBackground(camera, assets, width, height); + + GfxContext ctx = pctx.sub(); + ctx.blendMode(blendmode::addition); + + Shader* shader = assets->getShader("ui3d"); + shader->use(); + shader->uniformMatrix("u_projview", camera->getProjView()); + shader->uniformMatrix("u_apply", glm::mat4(1.0f)); + batch3d->begin(); + + float angle = daytime * M_PI * 2; + float opacity = glm::pow(1.0f-fog, 7.0f); + + for (auto& sprite : sprites) { + batch3d->texture(assets->getTexture(sprite.texture)); + + float sangle = daytime * M_PI*2 + sprite.phase; + float distance = sprite.distance; + + glm::vec3 pos(-cos(sangle)*distance, sin(sangle)*distance, 0); + glm::vec3 up(-sin(-sangle), cos(-sangle), 0.0f); + glm::vec4 tint (1,1,1, opacity); + if (!sprite.emissive) { + tint *= 0.6f+cos(angle)*0.4; + } + batch3d->sprite(camera->position+pos, up, + glm::vec3(0, 0, -1), 1, 1, UVRegion(), tint); + } + + drawStars(camera, angle, opacity); +} + +void Skybox::refresh(const GfxContext& pctx, float t, float mie, uint quality) { + GfxContext ctx = pctx.sub(); + ctx.depthMask(false); + ctx.depthTest(false); + ready = true; glBindFramebuffer(GL_FRAMEBUFFER, fbo); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap); shader->use(); - Window::viewport(0,0, size,size); - const vec3 xaxs[] = { + Window::viewport(0,0, size, size); + + const glm::vec3 xaxs[] = { {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}, @@ -63,7 +160,7 @@ void Skybox::refresh(float t, float mie, uint quality) { {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, }; - const vec3 yaxs[] = { + const glm::vec3 yaxs[] = { {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, @@ -73,7 +170,7 @@ void Skybox::refresh(float t, float mie, uint quality) { {0.0f, 1.0f, 0.0f}, }; - const vec3 zaxs[] = { + const glm::vec3 zaxs[] = { {1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, @@ -87,7 +184,7 @@ void Skybox::refresh(float t, float mie, uint quality) { shader->uniform1i("u_quality", quality); shader->uniform1f("u_mie", mie); shader->uniform1f("u_fog", mie - 1.0f); - shader->uniform3f("u_lightDir", glm::normalize(vec3(sin(t), -cos(t), -0.7f))); + shader->uniform3f("u_lightDir", glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f))); for (uint face = 0; face < 6; face++) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, cubemap, 0); shader->uniform3f("u_xaxis", xaxs[face]); diff --git a/src/frontend/graphics/Skybox.h b/src/frontend/graphics/Skybox.h index cdf18966..cc949617 100644 --- a/src/frontend/graphics/Skybox.h +++ b/src/frontend/graphics/Skybox.h @@ -1,25 +1,52 @@ #ifndef FRONTEND_GRAPHICS_SKYBOX_H_ #define FRONTEND_GRAPHICS_SKYBOX_H_ +#include +#include +#include #include "../../typedefs.h" +#include "../../maths/fastmaths.h" +#include "../../graphics/GfxContext.h" class Mesh; class Shader; +class Assets; +class Camera; +class Batch3D; + +struct skysprite { + std::string texture; + float phase; + float distance; + bool emissive; +}; class Skybox { uint fbo; uint cubemap; uint size; - Mesh* mesh; Shader* shader; bool ready = false; + FastRandom random; + + std::unique_ptr mesh; + std::unique_ptr batch3d; + std::vector sprites; + + void drawStars(Camera* camera, float angle, float opacity); + void drawBackground(Camera* camera, Assets* assets, int width, int height); public: Skybox(uint size, Shader* shader); ~Skybox(); - void draw(Shader* shader); + void draw( + const GfxContext& pctx, + Camera* camera, + Assets* assets, + float daytime, + float fog); - void refresh(float t, float mie, uint quality); + void refresh(const GfxContext& pctx, float t, float mie, uint quality); void bind() const; void unbind() const; bool isReady() const { diff --git a/src/graphics/Batch3D.cpp b/src/graphics/Batch3D.cpp index cf47dd2e..58b64a7b 100644 --- a/src/graphics/Batch3D.cpp +++ b/src/graphics/Batch3D.cpp @@ -134,9 +134,9 @@ void Batch3D::sprite(vec3 pos, vec3 up, vec3 right, float w, float h, const UVRe 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, + 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); @@ -146,9 +146,9 @@ void Batch3D::sprite(vec3 pos, vec3 up, vec3 right, float w, float h, const UVRe 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, + 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); @@ -178,8 +178,18 @@ void Batch3D::blockCube(const vec3 size, const UVRegion(&texfaces)[6], const vec face(coord+vec3(size.x, 0.0f, 0.0f), size.z, size.y, vec3(0, 0, -1), vec3(0, 1, 0), texfaces[1], (shading ? do_tint(0.9f)*tint : tint)); } +void Batch3D::point(glm::vec3 coord, glm::vec4 tint) { + vertex(coord, glm::vec2(), tint.r, tint.g, tint.b, tint.a); +} + 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; +} diff --git a/src/graphics/Batch3D.h b/src/graphics/Batch3D.h index 5de47c84..d5f5ae5a 100644 --- a/src/graphics/Batch3D.h +++ b/src/graphics/Batch3D.h @@ -43,7 +43,9 @@ public: 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 blockCube(const glm::vec3 size, const UVRegion(&texfaces)[6], const glm::vec4 tint, bool shading=true); + void point(glm::vec3 pos, glm::vec4 tint); void flush(); + void flushPoints(); }; #endif /* GRAPHICS_BATCH3D_H_ */ diff --git a/src/graphics/GfxContext.cpp b/src/graphics/GfxContext.cpp index e15dd5bf..44e915cb 100644 --- a/src/graphics/GfxContext.cpp +++ b/src/graphics/GfxContext.cpp @@ -11,6 +11,9 @@ GfxContext::GfxContext(const GfxContext* parent, Viewport& viewport, Batch2D* g2 GfxContext::~GfxContext() { if (parent == nullptr) return; + if (depthMask_ != parent->depthMask_) { + glDepthMask(parent->depthMask_); + } if (depthTest_ != parent->depthTest_) { if (depthTest_) glDisable(GL_DEPTH_TEST); else glEnable(GL_DEPTH_TEST); @@ -19,6 +22,9 @@ GfxContext::~GfxContext() { if (cullFace_) glDisable(GL_CULL_FACE); else glEnable(GL_CULL_FACE); } + if (blendMode_ != parent->blendMode_) { + Window::setBlendMode(parent->blendMode_); + } } const Viewport& GfxContext::getViewport() const { @@ -36,11 +42,18 @@ GfxContext GfxContext::sub() const { return ctx; } +void GfxContext::depthMask(bool flag) { + if (depthMask_ == flag) + return; + depthMask_ = flag; + glDepthMask(GL_FALSE + flag); +} + void GfxContext::depthTest(bool flag) { if (depthTest_ == flag) return; depthTest_ = flag; - if (depthTest_) { + if (flag) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); @@ -51,9 +64,16 @@ void GfxContext::cullFace(bool flag) { if (cullFace_ == flag) return; cullFace_ = flag; - if (cullFace_) { + if (flag) { glEnable(GL_CULL_FACE); } else { glDisable(GL_CULL_FACE); } -} \ No newline at end of file +} + +void GfxContext::blendMode(blendmode mode) { + if (blendMode_ == mode) + return; + blendMode_ = mode; + Window::setBlendMode(mode); +} diff --git a/src/graphics/GfxContext.h b/src/graphics/GfxContext.h index 43e97b5c..7da9dd90 100644 --- a/src/graphics/GfxContext.h +++ b/src/graphics/GfxContext.h @@ -3,6 +3,7 @@ #include "../typedefs.h" #include "Viewport.h" +#include "../window/Window.h" class Batch2D; @@ -10,8 +11,10 @@ class GfxContext { const GfxContext* parent; Viewport& viewport; Batch2D* const g2d; + bool depthMask_ = true; bool depthTest_ = false; bool cullFace_ = false; + blendmode blendMode_ = blendmode::normal; public: GfxContext(const GfxContext* parent, Viewport& viewport, Batch2D* g2d); ~GfxContext(); @@ -20,8 +23,10 @@ public: const Viewport& getViewport() const; GfxContext sub() const; + void depthMask(bool flag); void depthTest(bool flag); void cullFace(bool flag); + void blendMode(blendmode mode); }; #endif // GRAPHICS_GFX_CONTEXT_H_ \ No newline at end of file diff --git a/src/graphics/Texture.cpp b/src/graphics/Texture.cpp index 5531be1e..42bfb622 100644 --- a/src/graphics/Texture.cpp +++ b/src/graphics/Texture.cpp @@ -46,6 +46,13 @@ ImageData* Texture::readData() { 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(); diff --git a/src/graphics/Texture.h b/src/graphics/Texture.h index 2dc9064e..8ece550a 100644 --- a/src/graphics/Texture.h +++ b/src/graphics/Texture.h @@ -18,6 +18,8 @@ public: void bind(); void reload(ubyte* data); + void setNearestFilter(); + ImageData* readData(); static Texture* from(const ImageData* image); diff --git a/src/logic/BlocksController.cpp b/src/logic/BlocksController.cpp index 5378010a..46a548d4 100644 --- a/src/logic/BlocksController.cpp +++ b/src/logic/BlocksController.cpp @@ -125,9 +125,9 @@ void BlocksController::randomTick(int tickid, int parts) { continue; for (int s = 0; s < segments; s++) { for (int i = 0; i < 4; i++) { - int bx = fastmaths::rand() % CHUNK_W; - int by = fastmaths::rand() % segheight + s * segheight; - int bz = fastmaths::rand() % CHUNK_D; + int bx = random.rand() % CHUNK_W; + int by = random.rand() % segheight + s * segheight; + int bz = random.rand() % CHUNK_D; const voxel& vox = chunk->voxels[(by * CHUNK_D + bz) * CHUNK_W + bx]; Block* block = indices->getBlockDef(vox.id); if (block->rt.funcsset.randupdate) { diff --git a/src/logic/BlocksController.h b/src/logic/BlocksController.h index b0dc0fe7..83bc8b02 100644 --- a/src/logic/BlocksController.h +++ b/src/logic/BlocksController.h @@ -2,6 +2,7 @@ #define LOGIC_BLOCKS_CONTROLLER_H_ #include "../typedefs.h" +#include "../maths/fastmaths.h" class Player; class Block; @@ -33,6 +34,7 @@ class BlocksController { Clock randTickClock; Clock blocksTickClock; uint padding; + FastRandom random; public: BlocksController(Level* level, uint padding); diff --git a/src/maths/fastmaths.h b/src/maths/fastmaths.h index 73ea99e5..3d6a800a 100644 --- a/src/maths/fastmaths.h +++ b/src/maths/fastmaths.h @@ -1,17 +1,23 @@ #ifndef MATHS_FASTMATHS_H_ #define MATHS_FASTMATHS_H_ -namespace fastmaths { - static unsigned int g_seed; +#include "../typedefs.h" - inline void srand(int seed) { - g_seed = seed; +class FastRandom { + uint seed; +public: + inline void setSeed(uint seed) { + this->seed = seed; } - inline int rand(void) { - g_seed = (214013*g_seed+2531011); - return (g_seed>>16)&0x7FFF; + inline int rand() { + seed = (214013 * seed + 2531011); + return (seed>>16) & 0x7FFF; } -} + + inline float randFloat() { + return rand() / float(0x7FFF); + } +}; #endif // MATHS_FASTMATHS_H_ diff --git a/src/window/Window.cpp b/src/window/Window.cpp index 6a692902..4470d117 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -167,6 +167,17 @@ int Window::initialize(DisplaySettings& settings){ return 0; } +void Window::setBlendMode(blendmode mode) { + switch (mode) { + case blendmode::normal: + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case blendmode::addition: + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + } +} + void Window::clear() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } diff --git a/src/window/Window.h b/src/window/Window.h index e9f925cd..96bd210a 100644 --- a/src/window/Window.h +++ b/src/window/Window.h @@ -14,6 +14,10 @@ class ImageData; struct DisplaySettings; struct GLFWmonitor; +enum class blendmode { + normal, addition +}; + class Window { static GLFWwindow* window; static DisplaySettings* settings; @@ -53,6 +57,8 @@ public: static const char* getClipboardText(); static DisplaySettings* getSettings(); + static void setBlendMode(blendmode mode); + static glm::vec2 size() { return glm::vec2(width, height); }