fix: faster rendering pipeline & introduction to new gl constraints.

This commit is contained in:
JuiceyDev 2026-04-03 23:38:52 +02:00
parent 15f2f54a14
commit dc7625dfdd
4 changed files with 472 additions and 148 deletions

View file

@ -377,7 +377,14 @@ static char* gdraw_strreplace(char* src, const char* find, const char* rep) {
}
if (!count) return src;
result = (char*)malloc(strlen(src) + count * (rep_len + 1) + 1);
size_t src_len = strlen(src);
ptrdiff_t delta = (ptrdiff_t)rep_len - (ptrdiff_t)find_len;
size_t new_len = src_len + 1;
if (delta > 0)
new_len += (size_t)delta * count;
else
new_len -= (size_t)(-delta) * count;
result = (char*)malloc(new_len);
if (!result) return src;
tmp = result;
@ -389,7 +396,7 @@ static char* gdraw_strreplace(char* src, const char* find, const char* rep) {
tmp += rep_len;
src = pos + find_len;
}
strcpy(tmp, src);
memcpy(tmp, src, strlen(src) + 1);
free(base);
return result;
}
@ -409,13 +416,15 @@ static void gdraw_ShaderSourceUpgraded(GLuint shader, GLsizei count,
return;
}
src[0] = '\0';
char* dst = src;
for (int i = 0; i < count; i++) {
size_t len = lengths ? (lengths[i] >= 0 ? (size_t)lengths[i]
: strlen(strings[i]))
: strlen(strings[i]);
strncat(src, strings[i], len);
memcpy(dst, strings[i], len);
dst += len;
}
*dst = '\0';
int is_vert = (gdraw_get_shader_type(shader) == GL_VERTEX_SHADER);

View file

@ -106,6 +106,12 @@ ResourceLocation GameRenderer::SNOW_LOCATION =
// dirty light tracking
static bool s_lightTexDirty[XUSER_MAX_COUNT] = {true, true, true, true};
static uint64_t s_lightTexKey[XUSER_MAX_COUNT] = {};
static bool s_lightTexKeyValid[XUSER_MAX_COUNT] = {};
static inline uint8_t light_q8(float v) {
v = std::clamp(v, 0.0f, 1.0f);
return (uint8_t)(v * 255.0f + 0.5f);
}
GameRenderer::GameRenderer(Minecraft* mc) {
// 4J - added this block of initialisers
@ -877,6 +883,23 @@ void GameRenderer::updateLightTexture(float a) {
Level* level = player->level;
float skyDarken1 = level->getSkyDarken((float)1);
float amount =
darkenWorldAmountO + (darkenWorldAmount - darkenWorldAmountO) * a;
bool hasNV = player->hasEffect(MobEffect::nightVision);
float nvScale = hasNV ? getNightVisionScale(player, a) : 0.0f;
uint64_t key = 0;
key |= (uint64_t)light_q8(skyDarken1);
key |= (uint64_t)light_q8(blr) << 8;
key |= (uint64_t)light_q8(blg) << 16;
key |= (uint64_t)light_q8(amount) << 24;
key |= (uint64_t)light_q8(nvScale) << 32;
key |= (uint64_t)(level->skyFlashTime > 0 ? 1 : 0) << 40;
key |= (uint64_t)((unsigned int)level->dimension->id & 0xFF) << 48;
if (s_lightTexKeyValid[j] && s_lightTexKey[j] == key) continue;
s_lightTexKey[j] = key;
s_lightTexKeyValid[j] = true;
for (int i = 0; i < 256; i++) {
float darken = skyDarken1 * 0.95f + 0.05f;
float sky = level->dimension->brightnessRamp[i / 16] * darken;
@ -1240,9 +1263,9 @@ void GameRenderer::renderLevel(float a, int64_t until) {
if (mc->options->anaglyph3d) {
GameRenderer::anaglyphPass = i;
if (GameRenderer::anaglyphPass == 0)
glColorMask(false, true, true, false);
RenderManager.StateSetWriteEnable(false, true, true, false);
else
glColorMask(true, false, false, false);
RenderManager.StateSetWriteEnable(true, false, false, false);
}
glViewport(0, 0, mc->width, mc->height);
@ -1376,8 +1399,8 @@ void GameRenderer::renderLevel(float a, int64_t until) {
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(true);
RenderManager.StateSetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
RenderManager.StateSetDepthMask(true);
setupFog(0, a);
glEnable(GL_BLEND);
glDisable(GL_CULL_FACE);
@ -1394,11 +1417,11 @@ void GameRenderer::renderLevel(float a, int64_t until) {
GL11::glShadeModel(GL11::GL_SMOOTH);
}
glBlendFunc(GL_ZERO, GL_ONE);
RenderManager.StateSetBlendFunc(GL_ZERO, GL_ONE);
int visibleWaterChunks =
levelRenderer->render(cameraEntity, 1, a, updateChunks);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
RenderManager.StateSetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (visibleWaterChunks > 0) {
levelRenderer->render(
@ -1433,7 +1456,7 @@ void GameRenderer::renderLevel(float a, int64_t until) {
turnOffLightLayer(a); // 4J - brought forward from 1.8.2
////////////////////////// End of 4J added section
glDepthMask(true);
RenderManager.StateSetDepthMask(true);
glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
@ -1457,7 +1480,7 @@ void GameRenderer::renderLevel(float a, int64_t until) {
*/
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
RenderManager.StateSetBlendFunc(GL_SRC_ALPHA, GL_ONE);
{
FRAME_PROFILE_SCOPE(WeatherSky);
levelRenderer->renderDestroyAnimation(
@ -1491,7 +1514,7 @@ void GameRenderer::renderLevel(float a, int64_t until) {
return;
}
}
glColorMask(true, true, true, false);
RenderManager.StateSetWriteEnable(true, true, true, false);
}
void GameRenderer::prepareAndRenderClouds(LevelRenderer* levelRenderer,
@ -1620,7 +1643,7 @@ void GameRenderer::renderSnowAndRain(float a) {
glDisable(GL_CULL_FACE);
glNormal3f(0, 1, 0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
RenderManager.StateSetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glAlphaFunc(GL_GREATER, 0.01f);
mc->textures->bindTexture(
@ -1811,8 +1834,8 @@ void GameRenderer::setupGuiScreen(int forceScale /*=-1*/) {
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.1f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthMask(true);
RenderManager.StateSetDepthFunc(GL_LEQUAL);
RenderManager.StateSetDepthMask(true);
RenderManager.TextureBindVertex(-1);

View file

@ -23,6 +23,16 @@
#undef glVertexPointer
#undef glGenQueriesARB
#undef glGetQueryObjectuARB
#undef glEnable
#undef glDisable
#undef glBlendFunc
#undef glDepthMask
#undef glColorMask
#undef glLineWidth
#undef glFrontFace
#undef glPolygonOffset
#undef glStencilFunc
#undef glStencilMask
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
@ -92,7 +102,45 @@ static pthread_mutex_t s_sharedMtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t s_glCallMtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_t s_mainThread;
static bool s_mainThreadSet = false;
static thread_local bool s_rs_dirty = true;
static thread_local unsigned int s_rs_dirty_mask = 0xFFFFFFFF;
struct GLShadowState {
bool blend;
bool cull;
bool depth;
bool polygon;
bool stencil;
GLint blendSrc;
GLint blendDst;
GLboolean depthMask;
GLboolean colorMask[4];
float lineWidth;
GLenum frontFace;
float polySlope;
float polyBias;
GLenum stencilFunc;
GLint stencilRef;
GLuint stencilMask;
GLuint stencilWriteMask;
};
static GLShadowState s_gl_state;
static unsigned int s_gl_shadow_mask = 0;
enum GLShadowBits {
SHADOW_BLEND = 1 << 0,
SHADOW_CULL = 1 << 1,
SHADOW_DEPTH = 1 << 2,
SHADOW_BLEND_FUNC = 1 << 3,
SHADOW_DEPTH_MASK = 1 << 4,
SHADOW_COLOR_MASK = 1 << 5,
SHADOW_LINE_WIDTH = 1 << 6,
SHADOW_FRONT_FACE = 1 << 7,
SHADOW_POLY_OFFSET = 1 << 8,
SHADOW_POLY_OFFSET_PARAMS = 1 << 9,
SHADOW_STENCIL = 1 << 10,
SHADOW_STENCIL_PARAMS = 1 << 11,
};
static void onFramebufferResize(int w, int h) {
if (w < 1) w = 1;
@ -221,7 +269,9 @@ static thread_local int s_matMode = 0; // 0=MV 1=proj 2=tex0 3=tex1
static thread_local bool s_normalMatDirty = true;
static thread_local glm::mat3 s_cachedNormalMat;
static thread_local float s_cachedNormalSign = 1.0f;
static thread_local bool s_matDirty = true;
static inline void markNormalDirty() { s_normalMatDirty = true; }
static inline void markMatrixDirty() { s_matDirty = true; }
static MatrixStack& activeStack() {
switch (s_matMode) {
@ -236,22 +286,23 @@ static MatrixStack& activeStack() {
}
static void flushMatrices() {
glm::mat4 mvp = s_proj.cur() * s_mv.cur();
glUniformMatrix4fv(s_shader.uMVP, 1, GL_FALSE, glm::value_ptr(mvp));
glUniformMatrix4fv(s_shader.uMV, 1, GL_FALSE, glm::value_ptr(s_mv.cur()));
if (s_matDirty) {
glm::mat4 mvp = s_proj.cur() * s_mv.cur();
glUniformMatrix4fv(s_shader.uMVP, 1, GL_FALSE, glm::value_ptr(mvp));
glUniformMatrix4fv(s_shader.uMV, 1, GL_FALSE,
glm::value_ptr(s_mv.cur()));
// Send the texture matrix to the depths of hell...
glUniformMatrix4fv(s_shader.uTexMat0, 1, GL_FALSE,
glm::value_ptr(s_tex[0].cur()));
// Send the texture matrix to the depths of hell...
glUniformMatrix4fv(s_shader.uTexMat0, 1, GL_FALSE,
glm::value_ptr(s_tex[0].cur()));
s_matDirty = false;
}
// if (s_shader.uLighting)
if (s_shader.uNormalMatrix >= 0) {
if (s_normalMatDirty) {
glm::mat3 m3 = glm::mat3(s_mv.cur());
s_cachedNormalMat = glm::transpose(glm::inverse(m3));
s_cachedNormalSign = glm::determinant(m3) < 0.0f ? -1.0f : 1.0f;
s_normalMatDirty = false;
}
if (s_shader.uNormalMatrix >= 0 && s_normalMatDirty) {
glm::mat3 m3 = glm::mat3(s_mv.cur());
s_cachedNormalMat = glm::transpose(glm::inverse(m3));
s_cachedNormalSign = glm::determinant(m3) < 0.0f ? -1.0f : 1.0f;
s_normalMatDirty = false;
glUniformMatrix3fv(s_shader.uNormalMatrix, 1, GL_FALSE,
glm::value_ptr(s_cachedNormalMat));
glUniform1f(s_shader.uNormalSign, s_cachedNormalSign);
@ -275,27 +326,154 @@ struct RenderState {
glm::vec4 lmt = {1, 1, 0, 0};
glm::vec2 globalLM = {240.f, 240.f}; // fullbright default
int activeTexture = 0;
// we MAKE sure everything is FINE.
bool operator!=(const RenderState& o) const {
return baseColor != o.baseColor || fogColor != o.fogColor ||
fogStart != o.fogStart || fogEnd != o.fogEnd ||
fogDensity != o.fogDensity || fogMode != o.fogMode ||
fogEnable != o.fogEnable || alphaRef != o.alphaRef ||
gamma != o.gamma || useTexture != o.useTexture ||
useLightmap != o.useLightmap || lighting != o.lighting ||
l0 != o.l0 || l1 != o.l1 || ldiff != o.ldiff || lamb != o.lamb ||
lmt != o.lmt || globalLM != o.globalLM ||
activeTexture != o.activeTexture;
}
};
enum RenderDirtyBits {
DIRTY_BASECOLOR = 1 << 0,
DIRTY_LIGHTING = 1 << 1,
DIRTY_FOG = 1 << 2,
DIRTY_ALPHA = 1 << 3,
DIRTY_GAMMA = 1 << 4,
DIRTY_TEXTURE = 1 << 5,
DIRTY_LMT = 1 << 6,
DIRTY_GLOBAL_LM = 1 << 7,
};
static inline void markDirty(unsigned int bit) { s_rs_dirty_mask |= bit; }
static thread_local RenderState s_rs;
static RenderState s_gpu_state;
static bool s_gpu_state_valid = false;
// track currently bound program to avoid iggy shitting up
static GLuint s_boundProgram = 0;
static void glShadowSetBlend(bool e) {
if (!(s_gl_shadow_mask & SHADOW_BLEND) || s_gl_state.blend != e) {
if (e)
::glEnable(GL_BLEND);
else
::glDisable(GL_BLEND);
s_gl_state.blend = e;
s_gl_shadow_mask |= SHADOW_BLEND;
}
}
static void glShadowSetCull(bool e) {
if (!(s_gl_shadow_mask & SHADOW_CULL) || s_gl_state.cull != e) {
if (e)
::glEnable(GL_CULL_FACE);
else
::glDisable(GL_CULL_FACE);
s_gl_state.cull = e;
s_gl_shadow_mask |= SHADOW_CULL;
}
}
static void glShadowSetDepthTest(bool e) {
if (!(s_gl_shadow_mask & SHADOW_DEPTH) || s_gl_state.depth != e) {
if (e)
::glEnable(GL_DEPTH_TEST);
else
::glDisable(GL_DEPTH_TEST);
s_gl_state.depth = e;
s_gl_shadow_mask |= SHADOW_DEPTH;
}
}
static void glShadowSetBlendFunc(GLint s, GLint d) {
if (!(s_gl_shadow_mask & SHADOW_BLEND_FUNC) ||
s_gl_state.blendSrc != s || s_gl_state.blendDst != d) {
::glBlendFunc(s, d);
s_gl_state.blendSrc = s;
s_gl_state.blendDst = d;
s_gl_shadow_mask |= SHADOW_BLEND_FUNC;
}
}
static void glShadowSetDepthMask(GLboolean e) {
if (!(s_gl_shadow_mask & SHADOW_DEPTH_MASK) ||
s_gl_state.depthMask != e) {
::glDepthMask(e);
s_gl_state.depthMask = e;
s_gl_shadow_mask |= SHADOW_DEPTH_MASK;
}
}
static void glShadowSetColorMask(GLboolean r, GLboolean g, GLboolean b,
GLboolean a) {
if (!(s_gl_shadow_mask & SHADOW_COLOR_MASK) ||
s_gl_state.colorMask[0] != r || s_gl_state.colorMask[1] != g ||
s_gl_state.colorMask[2] != b || s_gl_state.colorMask[3] != a) {
::glColorMask(r, g, b, a);
s_gl_state.colorMask[0] = r;
s_gl_state.colorMask[1] = g;
s_gl_state.colorMask[2] = b;
s_gl_state.colorMask[3] = a;
s_gl_shadow_mask |= SHADOW_COLOR_MASK;
}
}
static void glShadowSetLineWidth(float w) {
if (!(s_gl_shadow_mask & SHADOW_LINE_WIDTH) || s_gl_state.lineWidth != w) {
::glLineWidth(w);
s_gl_state.lineWidth = w;
s_gl_shadow_mask |= SHADOW_LINE_WIDTH;
}
}
static void glShadowSetFrontFace(GLenum mode) {
if (!(s_gl_shadow_mask & SHADOW_FRONT_FACE) ||
s_gl_state.frontFace != mode) {
::glFrontFace(mode);
s_gl_state.frontFace = mode;
s_gl_shadow_mask |= SHADOW_FRONT_FACE;
}
}
static void glShadowSetPolygonOffset(float slope, float bias) {
bool enable = (slope != 0.0f || bias != 0.0f);
if (!(s_gl_shadow_mask & SHADOW_POLY_OFFSET) ||
s_gl_state.polygon != enable) {
if (enable)
::glEnable(GL_POLYGON_OFFSET_FILL);
else
::glDisable(GL_POLYGON_OFFSET_FILL);
s_gl_state.polygon = enable;
s_gl_shadow_mask |= SHADOW_POLY_OFFSET;
}
if (enable) {
if (!(s_gl_shadow_mask & SHADOW_POLY_OFFSET_PARAMS) ||
s_gl_state.polySlope != slope || s_gl_state.polyBias != bias) {
::glPolygonOffset(slope, bias);
s_gl_state.polySlope = slope;
s_gl_state.polyBias = bias;
s_gl_shadow_mask |= SHADOW_POLY_OFFSET_PARAMS;
}
}
}
static void glShadowSetStencil(GLenum fn, uint8_t ref, uint8_t fmask,
uint8_t wmask) {
if (!(s_gl_shadow_mask & SHADOW_STENCIL) || !s_gl_state.stencil) {
::glEnable(GL_STENCIL_TEST);
s_gl_state.stencil = true;
s_gl_shadow_mask |= SHADOW_STENCIL;
}
if (!(s_gl_shadow_mask & SHADOW_STENCIL_PARAMS) ||
s_gl_state.stencilFunc != fn || s_gl_state.stencilRef != (GLint)ref ||
s_gl_state.stencilMask != fmask ||
s_gl_state.stencilWriteMask != wmask) {
::glStencilFunc(fn, ref, fmask);
::glStencilMask(wmask);
s_gl_state.stencilFunc = fn;
s_gl_state.stencilRef = (GLint)ref;
s_gl_state.stencilMask = fmask;
s_gl_state.stencilWriteMask = wmask;
s_gl_shadow_mask |= SHADOW_STENCIL_PARAMS;
}
}
static thread_local bool s_chunkOffsetValid = false;
static thread_local glm::vec3 s_chunkOffset;
static void pushRenderState() {
if (!s_shader.prog) return;
@ -303,35 +481,53 @@ static void pushRenderState() {
if (s_boundProgram != s_shader.prog) {
glUseProgram(s_shader.prog);
s_boundProgram = s_shader.prog;
s_matDirty = true;
s_normalMatDirty = true;
s_rs_dirty_mask = 0xFFFFFFFF;
}
if (!s_gpu_state_valid || s_gpu_state != s_rs) {
glUniform4fv(s_shader.uBaseColor, 1, glm::value_ptr(s_rs.baseColor));
glUniform1i(s_shader.uLighting, s_rs.lighting ? 1 : 0);
glUniform3fv(s_shader.uLight0Dir, 1, glm::value_ptr(s_rs.l0));
glUniform3fv(s_shader.uLight1Dir, 1, glm::value_ptr(s_rs.l1));
glUniform3fv(s_shader.uLightDiffuse, 1, glm::value_ptr(s_rs.ldiff));
glUniform3fv(s_shader.uLightAmbient, 1, glm::value_ptr(s_rs.lamb));
glUniform1i(s_shader.uFogMode, s_rs.fogMode);
glUniform1f(s_shader.uFogStart, s_rs.fogStart);
glUniform1f(s_shader.uFogEnd, s_rs.fogEnd);
glUniform1f(s_shader.uFogDensity, s_rs.fogDensity);
glUniform4fv(s_shader.uFogColor, 1, glm::value_ptr(s_rs.fogColor));
glUniform1i(s_shader.uFogEnable, s_rs.fogEnable ? 1 : 0);
glUniform1i(s_shader.uUseTexture, s_rs.useTexture ? 1 : 0);
glUniform1i(s_shader.uUseLightmap, s_rs.useLightmap ? 1 : 0);
glUniform1f(s_shader.uAlphaRef, s_rs.alphaRef);
glUniform1f(s_shader.uInvGamma, 1.0f / s_rs.gamma);
glUniform4fv(s_shader.uLMTransform, 1, glm::value_ptr(s_rs.lmt));
glUniform2fv(s_shader.uGlobalLM, 1, glm::value_ptr(s_rs.globalLM));
s_gpu_state = s_rs;
s_gpu_state_valid = true;
s_rs_dirty = false;
if (s_rs_dirty_mask) {
if (s_rs_dirty_mask & DIRTY_BASECOLOR)
glUniform4fv(s_shader.uBaseColor, 1,
glm::value_ptr(s_rs.baseColor));
if (s_rs_dirty_mask & DIRTY_LIGHTING) {
glUniform1i(s_shader.uLighting, s_rs.lighting ? 1 : 0);
glUniform3fv(s_shader.uLight0Dir, 1, glm::value_ptr(s_rs.l0));
glUniform3fv(s_shader.uLight1Dir, 1, glm::value_ptr(s_rs.l1));
glUniform3fv(s_shader.uLightDiffuse, 1, glm::value_ptr(s_rs.ldiff));
glUniform3fv(s_shader.uLightAmbient, 1, glm::value_ptr(s_rs.lamb));
}
if (s_rs_dirty_mask & DIRTY_FOG) {
glUniform1i(s_shader.uFogMode, s_rs.fogMode);
glUniform1f(s_shader.uFogStart, s_rs.fogStart);
glUniform1f(s_shader.uFogEnd, s_rs.fogEnd);
glUniform1f(s_shader.uFogDensity, s_rs.fogDensity);
glUniform4fv(s_shader.uFogColor, 1,
glm::value_ptr(s_rs.fogColor));
glUniform1i(s_shader.uFogEnable, s_rs.fogEnable ? 1 : 0);
}
if (s_rs_dirty_mask & DIRTY_TEXTURE) {
glUniform1i(s_shader.uUseTexture, s_rs.useTexture ? 1 : 0);
glUniform1i(s_shader.uUseLightmap, s_rs.useLightmap ? 1 : 0);
}
if (s_rs_dirty_mask & DIRTY_ALPHA)
glUniform1f(s_shader.uAlphaRef, s_rs.alphaRef);
if (s_rs_dirty_mask & DIRTY_GAMMA)
glUniform1f(s_shader.uInvGamma, 1.0f / s_rs.gamma);
if (s_rs_dirty_mask & DIRTY_LMT)
glUniform4fv(s_shader.uLMTransform, 1,
glm::value_ptr(s_rs.lmt));
if (s_rs_dirty_mask & DIRTY_GLOBAL_LM)
glUniform2fv(s_shader.uGlobalLM, 1,
glm::value_ptr(s_rs.globalLM));
s_rs_dirty_mask = 0;
}
flushMatrices();
}
static GLuint s_sVAO_std = 0, s_sVBO_std = 0;
static GLsizeiptr s_streamVBOSize = 0;
static bool s_useMapRange = false;
static void bindStdAttribs() {
glEnableVertexAttribArray(0);
@ -472,18 +668,18 @@ void C4JRender::Initialise() {
int fw, fh;
SDL_GetWindowSize(s_window, &fw, &fh);
onFramebufferResize(fw, fh);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glShadowSetDepthTest(true);
::glDepthFunc(GL_LEQUAL);
#ifdef GLES
glClearDepthf(1.0f);
#else
glClearDepth(1.0);
#endif
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glClearColor(0, 0, 0, 1);
glShadowSetBlend(true);
glShadowSetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadowSetCull(true);
::glCullFace(GL_BACK);
::glClearColor(0, 0, 0, 1);
glViewport(0, 0, s_windowWidth, s_windowHeight);
s_shader.build(VERT_SRC, FRAG_SRC);
initStreamingVAOs();
@ -548,6 +744,7 @@ void C4JRender::InitialiseContext() {
}
void C4JRender::StartFrame() {
Set_matrixDirty();
int w, h;
SDL_GetWindowSize(s_window, &w, &h);
s_windowWidth = w > 0 ? w : 1;
@ -706,11 +903,27 @@ void C4JRender::DrawVertices(ePrimitiveType ptype, int count, void* dataIn,
glBindVertexArray(s_sVAO_std);
glBindBuffer(GL_ARRAY_BUFFER, s_sVBO_std);
// orphan buffer
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)bytes, nullptr, GL_STREAM_DRAW);
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)bytes, dataIn, GL_STREAM_DRAW);
bindStdAttribs();
if ((GLsizeiptr)bytes != s_streamVBOSize) {
s_streamVBOSize = (GLsizeiptr)bytes;
glBufferData(GL_ARRAY_BUFFER, s_streamVBOSize, nullptr, GL_STREAM_DRAW);
}
if (s_useMapRange) {
void* dst = glMapBufferRange(
GL_ARRAY_BUFFER, 0, (GLsizeiptr)bytes,
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT |
GL_MAP_UNSYNCHRONIZED_BIT);
if (dst) {
memcpy(dst, dataIn, bytes);
glUnmapBuffer(GL_ARRAY_BUFFER);
} else {
s_useMapRange = false;
}
}
if (!s_useMapRange) {
glBufferSubData(GL_ARRAY_BUFFER, 0, (GLsizeiptr)bytes, dataIn);
}
glDrawArrays(glMode, 0, count);
@ -828,39 +1041,48 @@ void C4JRender::MatrixMode(int t) {
void C4JRender::MatrixSetIdentity() {
activeStack().load(glm::mat4(1.f));
markMatrixDirty();
if (s_matMode == 0) markNormalDirty();
}
void C4JRender::MatrixPush() {
activeStack().push();
// push doesn't change cur() so no dirty needed but mark anyway to be safe
// ;w;
markMatrixDirty();
if (s_matMode == 0) markNormalDirty();
}
void C4JRender::MatrixPop() {
activeStack().pop();
markMatrixDirty();
if (s_matMode == 0) markNormalDirty();
}
void C4JRender::MatrixTranslate(float x, float y, float z) {
activeStack().mul(glm::translate(glm::mat4(1.f), {x, y, z}));
markMatrixDirty();
if (s_matMode == 0) markNormalDirty();
}
void C4JRender::MatrixRotate(float a, float x, float y, float z) {
activeStack().mul(glm::rotate(glm::mat4(1.f), a, {x, y, z}));
markMatrixDirty();
if (s_matMode == 0) markNormalDirty();
}
void C4JRender::MatrixScale(float x, float y, float z) {
activeStack().mul(glm::scale(glm::mat4(1.f), {x, y, z}));
markMatrixDirty();
if (s_matMode == 0) markNormalDirty();
}
void C4JRender::MatrixPerspective(float fovy, float asp, float zn, float zf) {
s_proj.cur() = glm::perspective(glm::radians(fovy), asp, zn, zf);
markMatrixDirty();
}
void C4JRender::MatrixOrthogonal(float l, float r, float b, float t, float zn,
float zf) {
s_proj.cur() = glm::ortho(l, r, b, t, zn, zf);
markMatrixDirty();
}
void C4JRender::MatrixMult(float* m) {
activeStack().mul(glm::make_mat4(m));
markMatrixDirty();
if (s_matMode == 0) markNormalDirty();
}
const float* C4JRender::MatrixGet(int t) {
@ -875,8 +1097,11 @@ const float* C4JRender::MatrixGet(int t) {
void C4JRender::Set_matrixDirty() {
// iggy wipes opengl state
s_boundProgram = 0;
s_gpu_state_valid = false;
s_normalMatDirty = true; // normal matrix dirt after iggy reset
s_rs_dirty_mask = 0xFFFFFFFF;
s_gl_shadow_mask = 0;
s_normalMatDirty = true; // normal matrix dirt after iggy reset
s_matDirty = true;
s_chunkOffsetValid = false;
if (s_shader.prog) {
glUseProgram(s_shader.prog);
s_boundProgram = s_shader.prog;
@ -890,57 +1115,62 @@ void C4JRender::SetClearColour(const float c[4]) {
bool C4JRender::IsWidescreen() { return true; }
bool C4JRender::IsHiDef() { return true; }
void C4JRender::StateSetColour(float r, float g, float b, float a) {
s_rs.baseColor = {r, g, b, a};
glm::vec4 v = {r, g, b, a};
if (s_rs.baseColor != v) {
s_rs.baseColor = v;
markDirty(DIRTY_BASECOLOR);
}
}
void C4JRender::SetChunkOffset(float x, float y, float z) {
if (s_shader.uChunkOffset >= 0) glUniform3f(s_shader.uChunkOffset, x, y, z);
if (s_shader.uChunkOffset < 0) return;
glm::vec3 v = {x, y, z};
if (!s_chunkOffsetValid || s_chunkOffset != v) {
s_chunkOffset = v;
s_chunkOffsetValid = true;
}
if (s_boundProgram == s_shader.prog) {
glUniform3f(s_shader.uChunkOffset, x, y, z);
}
}
void C4JRender::StateSetDepthMask(bool e) {
glDepthMask(e ? GL_TRUE : GL_FALSE);
glShadowSetDepthMask(e ? GL_TRUE : GL_FALSE);
}
void C4JRender::StateSetBlendEnable(bool e) {
if (e)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
void C4JRender::StateSetBlendEnable(bool e) { glShadowSetBlend(e); }
void C4JRender::StateSetBlendFunc(int s, int d) {
glShadowSetBlendFunc(s, d);
}
void C4JRender::StateSetBlendFunc(int s, int d) { glBlendFunc(s, d); }
void C4JRender::StateSetDepthFunc(int f) { glDepthFunc(f); }
void C4JRender::StateSetFaceCull(bool e) {
if (e)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
void C4JRender::StateSetDepthFunc(int f) { ::glDepthFunc(f); }
void C4JRender::StateSetFaceCull(bool e) { glShadowSetCull(e); }
void C4JRender::StateSetFaceCullCW(bool e) {
glShadowSetFrontFace(e ? GL_CW : GL_CCW);
}
void C4JRender::StateSetFaceCullCW(bool e) { glFrontFace(e ? GL_CW : GL_CCW); }
void C4JRender::StateSetLineWidth(float w) {
#ifndef GLES
glLineWidth(w);
glShadowSetLineWidth(w);
#else
(void)w;
#endif
}
void C4JRender::StateSetWriteEnable(bool r, bool g, bool b, bool a) {
glColorMask(r, g, b, a);
}
void C4JRender::StateSetDepthTestEnable(bool e) {
if (e)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
glShadowSetColorMask(r, g, b, a);
}
void C4JRender::StateSetDepthTestEnable(bool e) { glShadowSetDepthTest(e); }
void C4JRender::StateSetAlphaTestEnable(bool e) {
s_rs.alphaRef = e ? 0.1f : 0.f;
}
void C4JRender::StateSetAlphaFunc(int, float p) { s_rs.alphaRef = p; }
void C4JRender::StateSetDepthSlopeAndBias(float s, float b) {
if (s || b) {
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(s, b);
} else {
glDisable(GL_POLYGON_OFFSET_FILL);
float v = e ? 0.1f : 0.f;
if (s_rs.alphaRef != v) {
s_rs.alphaRef = v;
markDirty(DIRTY_ALPHA);
}
}
void C4JRender::StateSetAlphaFunc(int, float p) {
if (s_rs.alphaRef != p) {
s_rs.alphaRef = p;
markDirty(DIRTY_ALPHA);
}
}
void C4JRender::StateSetDepthSlopeAndBias(float s, float b) {
glShadowSetPolygonOffset(s, b);
}
void C4JRender::StateSetBlendFactor(unsigned int col) {
float a = ((col >> 24) & 0xFF) / 255.f;
float r = ((col >> 16) & 0xFF) / 255.f;
@ -948,58 +1178,96 @@ void C4JRender::StateSetBlendFactor(unsigned int col) {
float b = (col & 0xFF) / 255.f;
glBlendColor(r, g, b, a);
}
void C4JRender::StateSetFogEnable(bool e) { s_rs.fogEnable = e; }
void C4JRender::StateSetFogMode(int mode) {
s_rs.fogMode = (mode == GL_LINEAR) ? 1
: (mode == GL_EXP) ? 2
: (mode == 0x0801) ? 3
: 0;
void C4JRender::StateSetFogEnable(bool e) {
if (s_rs.fogEnable != e) {
s_rs.fogEnable = e;
markDirty(DIRTY_FOG);
}
}
void C4JRender::StateSetFogMode(int mode) {
int v = (mode == GL_LINEAR) ? 1 : (mode == GL_EXP) ? 2 : (mode == 0x0801) ? 3 : 0;
if (s_rs.fogMode != v) {
s_rs.fogMode = v;
markDirty(DIRTY_FOG);
}
}
void C4JRender::StateSetFogNearDistance(float d) {
if (s_rs.fogStart != d) {
s_rs.fogStart = d;
markDirty(DIRTY_FOG);
}
}
void C4JRender::StateSetFogFarDistance(float d) {
if (s_rs.fogEnd != d) {
s_rs.fogEnd = d;
markDirty(DIRTY_FOG);
}
}
void C4JRender::StateSetFogDensity(float d) {
if (s_rs.fogDensity != d) {
s_rs.fogDensity = d;
markDirty(DIRTY_FOG);
}
}
void C4JRender::StateSetFogNearDistance(float d) { s_rs.fogStart = d; }
void C4JRender::StateSetFogFarDistance(float d) { s_rs.fogEnd = d; }
void C4JRender::StateSetFogDensity(float d) { s_rs.fogDensity = d; }
void C4JRender::StateSetFogColour(float r, float g, float b) {
s_rs.fogColor = {r, g, b, 1};
glm::vec4 v = {r, g, b, 1};
if (s_rs.fogColor != v) {
s_rs.fogColor = v;
markDirty(DIRTY_FOG);
}
}
void C4JRender::StateSetLightingEnable(bool e) {
s_rs.lighting = e;
s_rs_dirty = true;
if (s_rs.lighting != e) {
s_rs.lighting = e;
markDirty(DIRTY_LIGHTING);
}
}
void C4JRender::StateSetLightColour(int, float r, float g, float b) {
s_rs.ldiff = {r, g, b};
s_rs_dirty = true;
glm::vec3 v = {r, g, b};
if (s_rs.ldiff != v) {
s_rs.ldiff = v;
markDirty(DIRTY_LIGHTING);
}
}
void C4JRender::StateSetLightAmbientColour(float r, float g, float b) {
s_rs.lamb = {r, g, b};
s_rs_dirty = true;
glm::vec3 v = {r, g, b};
if (s_rs.lamb != v) {
s_rs.lamb = v;
markDirty(DIRTY_LIGHTING);
}
}
void C4JRender::StateSetLightDirection(int light, float x, float y, float z) {
glm::vec3 d = glm::normalize(glm::mat3(s_mv.cur()) * glm::vec3(x, y, z));
if (light == 0)
s_rs.l0 = d;
else
s_rs.l1 = d;
if (light == 0) {
if (s_rs.l0 != d) {
s_rs.l0 = d;
markDirty(DIRTY_LIGHTING);
}
} else {
if (s_rs.l1 != d) {
s_rs.l1 = d;
markDirty(DIRTY_LIGHTING);
}
}
}
void C4JRender::StateSetViewport(eViewportType) {
glViewport(0, 0, s_windowWidth, s_windowHeight);
}
void C4JRender::StateSetVertexTextureUV(float u, float v) {
s_rs.globalLM = {u, v};
glm::vec2 val = {u, v};
if (s_rs.globalLM != val) {
s_rs.globalLM = val;
markDirty(DIRTY_GLOBAL_LM);
}
}
void C4JRender::StateSetStencil(int fn, uint8_t ref, uint8_t fmask,
uint8_t wmask) {
glEnable(GL_STENCIL_TEST);
glStencilFunc(fn, ref, fmask);
glStencilMask(wmask);
glShadowSetStencil(fn, ref, fmask, wmask);
}
void C4JRender::StateSetTextureEnable(bool e) {
if (s_rs.activeTexture == 0) {
if (s_rs.activeTexture == 0 && s_rs.useTexture != e) {
s_rs.useTexture = e;
if (s_shader.prog) {
glUseProgram(s_shader.prog);
s_boundProgram = s_shader.prog;
glUniform1i(s_shader.uUseTexture, e ? 1 : 0);
}
markDirty(DIRTY_TEXTURE);
}
}
void C4JRender::StateSetActiveTexture(int tex) {
@ -1021,7 +1289,10 @@ void C4JRender::TextureBind(int idx) {
}
void C4JRender::TextureBindVertex(int idx, bool scaleLight) {
if (idx < 0) {
s_rs.useLightmap = false;
if (s_rs.useLightmap) {
s_rs.useLightmap = false;
markDirty(DIRTY_TEXTURE);
}
glActiveTexture(GL_TEXTURE0);
return;
}
@ -1032,9 +1303,17 @@ void C4JRender::TextureBindVertex(int idx, bool scaleLight) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glActiveTexture(GL_TEXTURE0);
s_rs.useLightmap = true;
s_rs.lmt = scaleLight ? glm::vec4{1.f, 1.f, 8.f / 256.f, 8.f / 256.f}
: glm::vec4{1.f, 1.f, 0.f, 0.f};
if (!s_rs.useLightmap) {
s_rs.useLightmap = true;
markDirty(DIRTY_TEXTURE);
}
glm::vec4 newLmt =
scaleLight ? glm::vec4{1.f, 1.f, 8.f / 256.f, 8.f / 256.f}
: glm::vec4{1.f, 1.f, 0.f, 0.f};
if (s_rs.lmt != newLmt) {
s_rs.lmt = newLmt;
markDirty(DIRTY_LMT);
}
}
void C4JRender::TextureSetTextureLevels(int l) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, l > 0 ? l - 1 : 0);
@ -1098,6 +1377,7 @@ int C4JRender::LoadTextureData(uint8_t* pb, uint32_t nb, D3DXIMAGE_INFO* i,
return hr;
}
// TODO: TO REMOVE SOON.
void C4JRender::UpdateGamma(unsigned short usGamma) {
constexpr unsigned short GAMMA_MAX = 32768;
s_rs.gamma = 0.5f + ((float)(usGamma) * (1.0f / GAMMA_MAX));
@ -1194,4 +1474,4 @@ void glLightModelfv(GLenum pname, const GLfloat* params) {
void glShadeModel(GLenum) {}
void glColorMaterial(GLenum, GLenum) {}
void glNormal3f(GLfloat, GLfloat, GLfloat) {}
}
}

View file

@ -490,6 +490,12 @@ extern C4JRender RenderManager;
RenderManager.StateSetAlphaTestEnable(true); \
else if ((cap) == 0x0DE1 /*GL_TEXTURE_2D*/) \
RenderManager.StateSetTextureEnable(true); \
else if ((cap) == 0x0BE2 /*GL_BLEND*/) \
RenderManager.StateSetBlendEnable(true); \
else if ((cap) == 0x0B44 /*GL_CULL_FACE*/) \
RenderManager.StateSetFaceCull(true); \
else if ((cap) == 0x0B71 /*GL_DEPTH_TEST*/) \
RenderManager.StateSetDepthTestEnable(true); \
else if ((cap) == 0x4000 /*GL_LIGHT0*/) \
RenderManager.StateSetLightEnable(0, true); \
else if ((cap) == 0x4001 /*GL_LIGHT1*/) \
@ -516,6 +522,12 @@ extern C4JRender RenderManager;
RenderManager.StateSetAlphaTestEnable(false); \
else if ((cap) == 0x0DE1 /*GL_TEXTURE_2D*/) \
RenderManager.StateSetTextureEnable(false); \
else if ((cap) == 0x0BE2 /*GL_BLEND*/) \
RenderManager.StateSetBlendEnable(false); \
else if ((cap) == 0x0B44 /*GL_CULL_FACE*/) \
RenderManager.StateSetFaceCull(false); \
else if ((cap) == 0x0B71 /*GL_DEPTH_TEST*/) \
RenderManager.StateSetDepthTestEnable(false); \
else if ((cap) == 0x4000 /*GL_LIGHT0*/) \
RenderManager.StateSetLightEnable(0, false); \
else if ((cap) == 0x4001 /*GL_LIGHT1*/) \