|
|
@@ -73,59 +73,6 @@ struct ChunkProg: public GlProgram { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
struct ChunkShadowProg: public GlProgram { |
|
|
|
template<typename... T> |
|
|
|
ChunkShadowProg(const T &... shaders): GlProgram(shaders...) { init(); } |
|
|
|
~ChunkShadowProg() { deinit(); } |
|
|
|
|
|
|
|
GLint camera = uniformLoc("camera"); |
|
|
|
GLint pos = uniformLoc("pos"); |
|
|
|
GLint vertex = attribLoc("vertex"); |
|
|
|
GLint tex = uniformLoc("tex"); |
|
|
|
|
|
|
|
GLuint vbo; |
|
|
|
|
|
|
|
static constexpr float ch = (float)SwanCommon::CHUNK_HEIGHT; |
|
|
|
static constexpr float cw = (float)SwanCommon::CHUNK_WIDTH; |
|
|
|
static constexpr GLfloat vertexes[] = { |
|
|
|
0.0f, 0.0f, // pos 0: top left |
|
|
|
0.0f, ch , // pos 1: bottom left |
|
|
|
cw, ch, // pos 2: bottom right |
|
|
|
cw, ch, // pos 2: bottom right |
|
|
|
cw, 0.0f, // pos 3: top right |
|
|
|
0.0f, 0.0f, // pos 0: top left |
|
|
|
}; |
|
|
|
|
|
|
|
void enable() { |
|
|
|
glUseProgram(id()); |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo); |
|
|
|
glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0); |
|
|
|
glEnableVertexAttribArray(vertex); |
|
|
|
glCheck(); |
|
|
|
|
|
|
|
glUniform1i(tex, 0); |
|
|
|
} |
|
|
|
|
|
|
|
void disable() { |
|
|
|
glDisableVertexAttribArray(vertex); |
|
|
|
glCheck(); |
|
|
|
} |
|
|
|
|
|
|
|
void init() { |
|
|
|
glGenBuffers(1, &vbo); |
|
|
|
glCheck(); |
|
|
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo); |
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW); |
|
|
|
glCheck(); |
|
|
|
} |
|
|
|
|
|
|
|
void deinit() { |
|
|
|
glDeleteBuffers(1, &vbo); |
|
|
|
glCheck(); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
struct TileProg: public GlProgram { |
|
|
|
template<typename... T> |
|
|
|
TileProg(const T &... shaders): GlProgram(shaders...) { init(); } |
|
|
@@ -337,8 +284,6 @@ struct BlendProg: public GlProgram { |
|
|
|
struct RendererState { |
|
|
|
GlVxShader chunkVx{Shaders::chunkVx}; |
|
|
|
GlFrShader chunkFr{Shaders::chunkFr}; |
|
|
|
GlVxShader chunkShadowVx{Shaders::chunkShadowVx}; |
|
|
|
GlFrShader chunkShadowFr{Shaders::chunkShadowFr}; |
|
|
|
GlVxShader tileVx{Shaders::tileVx}; |
|
|
|
GlFrShader tileFr{Shaders::tileFr}; |
|
|
|
GlVxShader spriteVx{Shaders::spriteVx}; |
|
|
@@ -349,7 +294,6 @@ struct RendererState { |
|
|
|
GlFrShader blendFr{Shaders::blendFr}; |
|
|
|
|
|
|
|
ChunkProg chunkProg{chunkVx, chunkFr}; |
|
|
|
ChunkShadowProg chunkShadowProg{chunkShadowVx, chunkShadowFr}; |
|
|
|
TileProg tileProg{tileVx, tileFr}; |
|
|
|
SpriteProg spriteProg{spriteVx, spriteFr}; |
|
|
|
RectProg rectProg{rectVx, rectFr}; |
|
|
@@ -358,6 +302,8 @@ struct RendererState { |
|
|
|
SwanCommon::Vec2i screenSize; |
|
|
|
GLuint offscreenFramebuffer = 0; |
|
|
|
GLuint offscreenTex = 0; |
|
|
|
GLuint opacityFramebuffer = 0; |
|
|
|
GLuint opacityTex = 0; |
|
|
|
GLuint atlasTex = 0; |
|
|
|
SwanCommon::Vec2 atlasTexSize; |
|
|
|
}; |
|
|
@@ -366,8 +312,15 @@ Renderer::Renderer(): state_(std::make_unique<RendererState>()) { |
|
|
|
glGenTextures(1, &state_->atlasTex); |
|
|
|
glCheck(); |
|
|
|
|
|
|
|
glGenFramebuffers(1, &state_->offscreenFramebuffer); |
|
|
|
glCheck(); |
|
|
|
glGenTextures(1, &state_->offscreenTex); |
|
|
|
glCheck(); |
|
|
|
|
|
|
|
glGenFramebuffers(1, &state_->opacityFramebuffer); |
|
|
|
glCheck(); |
|
|
|
glGenTextures(1, &state_->opacityTex); |
|
|
|
glCheck(); |
|
|
|
} |
|
|
|
|
|
|
|
Renderer::~Renderer() { |
|
|
@@ -392,7 +345,6 @@ void Renderer::draw(const RenderCamera &cam) { |
|
|
|
} |
|
|
|
|
|
|
|
auto &chunkProg = state_->chunkProg; |
|
|
|
auto &chunkShadowProg = state_->chunkShadowProg; |
|
|
|
auto &tileProg = state_->tileProg; |
|
|
|
auto &spriteProg = state_->spriteProg; |
|
|
|
auto &rectProg = state_->rectProg; |
|
|
@@ -400,6 +352,7 @@ void Renderer::draw(const RenderCamera &cam) { |
|
|
|
|
|
|
|
if (state_->screenSize != cam.size) { |
|
|
|
state_->screenSize = cam.size; |
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, state_->offscreenTex); |
|
|
|
glCheck(); |
|
|
|
glTexImage2D( |
|
|
@@ -409,14 +362,47 @@ void Renderer::draw(const RenderCamera &cam) { |
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|
|
|
glCheck(); |
|
|
|
|
|
|
|
glGenFramebuffers(1, &state_->offscreenFramebuffer); |
|
|
|
glBindTexture(GL_TEXTURE_2D, state_->opacityTex); |
|
|
|
glCheck(); |
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, state_->offscreenFramebuffer); |
|
|
|
glTexImage2D( |
|
|
|
GL_TEXTURE_2D, 0, GL_RGBA, cam.size.x, cam.size.y, 0, |
|
|
|
GL_RGBA, GL_UNSIGNED_BYTE, NULL); |
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|
|
|
glCheck(); |
|
|
|
glFramebufferTexture2D( |
|
|
|
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
|
|
|
state_->offscreenTex, 0); |
|
|
|
} |
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, state_->opacityFramebuffer); |
|
|
|
glFramebufferTexture2D( |
|
|
|
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
|
|
|
state_->opacityTex, 0); |
|
|
|
glClearColor(0, 0, 0, 0); |
|
|
|
glClear(GL_COLOR_BUFFER_BIT); |
|
|
|
glCheck(); |
|
|
|
|
|
|
|
{ |
|
|
|
Mat3gf scaledCamMat = camMat; |
|
|
|
scaledCamMat.scale({0.5, 0.5}); |
|
|
|
chunkProg.enable(); |
|
|
|
glUniformMatrix3fv(chunkProg.camera, 1, GL_TRUE, scaledCamMat.data()); |
|
|
|
glCheck(); |
|
|
|
|
|
|
|
glUniform2f(chunkProg.tileAtlasSize, state_->atlasTexSize.x, state_->atlasTexSize.y); |
|
|
|
glCheck(); |
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0); |
|
|
|
glBindTexture(GL_TEXTURE_2D, state_->atlasTex); |
|
|
|
glCheck(); |
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE1); |
|
|
|
for (auto [pos, chunk]: drawChunks_) { |
|
|
|
glUniform2f(chunkProg.pos, pos.x, pos.y); |
|
|
|
glBindTexture(GL_TEXTURE_2D, chunk.tex); |
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6); |
|
|
|
glCheck(); |
|
|
|
} |
|
|
|
|
|
|
|
chunkProg.disable(); |
|
|
|
} |
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, state_->offscreenFramebuffer); |
|
|
@@ -514,28 +500,11 @@ void Renderer::draw(const RenderCamera &cam) { |
|
|
|
{ |
|
|
|
blendProg.enable(); |
|
|
|
glActiveTexture(GL_TEXTURE0); |
|
|
|
glBindTexture(GL_TEXTURE_2D, state_->offscreenTex); |
|
|
|
glBindTexture(GL_TEXTURE_2D, state_->opacityTex); |
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6); |
|
|
|
glCheck(); |
|
|
|
blendProg.disable(); |
|
|
|
} |
|
|
|
|
|
|
|
{ |
|
|
|
chunkShadowProg.enable(); |
|
|
|
glUniformMatrix3fv(chunkShadowProg.camera, 1, GL_TRUE, camMat.data()); |
|
|
|
glCheck(); |
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0); |
|
|
|
for (auto [pos, shadow]: drawChunkShadows_) { |
|
|
|
glUniform2f(chunkShadowProg.pos, pos.x, pos.y); |
|
|
|
glBindTexture(GL_TEXTURE_2D, shadow.tex); |
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6); |
|
|
|
glCheck(); |
|
|
|
} |
|
|
|
|
|
|
|
drawChunkShadows_.clear(); |
|
|
|
chunkShadowProg.disable(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void Renderer::uploadTileAtlas(const void *data, int width, int height) { |