
static GLuint EnsureVAOShader() {
if (gVAOProg) return gVAOProg;
const char* vsSrc =
"#version 120\n"
"attribute vec3 aPos;\n"
"attribute vec2 aTex;\n"
"attribute vec3 aCol;\n"
"varying vec2 vUV;\n"
"varying vec3 vCol;\n"
"uniform mat4 view, projection;\n"
"uniform int uHasShift;\n"
"uniform float uShiftU, uShiftV;\n"
"uniform int uUseColors;\n"
"void main(){\n"
" gl_Position = projection * view * vec4(aPos,1.0);\n"
" vUV = aTex;\n"
" if(uHasShift==1){ vUV.x += uShiftU; vUV.y += uShiftV; }\n"
" vCol = (uUseColors!=0) ? clamp(aCol,0.0,1.0) : vec3(1.0);\n"
"}\n";
// uMode: 0=base(textured), 1=bright(masked by texture alpha), 2=dark(subtractive), 3=bright(solid, no texture)
const char* fsSrc =
"#version 120\n"
"varying vec2 vUV;\n"
"varying vec3 vCol;\n"
"uniform sampler2D texture1;\n"
"uniform float Alpha;\n"
"uniform int uMode;\n"
"uniform vec3 uBodyLight;\n"
"uniform float uBrightScale;\n"
"uniform float uAlphaCut;\n"
"void main(){\n"
" if (uMode==3) {\n"
" // BRIGHT solid: вообще не семплим текстуру\n"
" gl_FragColor = vec4(uBodyLight * uBrightScale, 1.0);\n"
" return;\n"
" }\n"
" vec4 t = texture2D(texture1, vUV);\n"
" if (uMode==1) {\n"
" // BRIGHT masked по альфе текстуры\n"
" if (t.a <= uAlphaCut) discard;\n"
" vec3 col = t.rgb * uBodyLight * uBrightScale * t.a;\n"
" gl_FragColor = vec4(col, 1.0);\n"
" } else if (uMode==2) {\n"
" // DARK (subtractive). Альфа в базовом FFP не всегда влияла, оставим как есть\n"
" gl_FragColor = vec4(t.rgb, t.a * Alpha);\n"
" } else {\n"
" // BASE textured\n"
" if (t.a <= uAlphaCut) discard;\n"
" gl_FragColor = vec4(t.rgb * vCol, t.a * Alpha);\n"
" }\n"
"}\n";
GLuint vs = CompileGLSL(GL_VERTEX_SHADER, vsSrc);
GLuint fs = CompileGLSL(GL_FRAGMENT_SHADER, fsSrc);
gVAOProg = LinkProgram(vs, fs, "aPos", "aTex", "aCol");
return gVAOProg;
}
The only one place where i call func now it's :
void BMD::RenderMesh(int meshIndex, int renderFlags, float alpha, int blendMeshIndex, float blendMeshAlpha, float blendMeshTextureCoordU, float blendMeshTextureCoordV, int explicitTextureIndex)
{
#ifdef USE_VAO
if ((renderFlags & RENDER_TEXTURE) == RENDER_TEXTURE) {
RenderMesh_VAO(meshIndex, renderFlags, alpha,
blendMeshIndex, blendMeshAlpha,
blendMeshTextureCoordU, blendMeshTextureCoordV,
explicitTextureIndex);
return;
}
#endif
if (meshIndex >= NumMeshs || meshIndex < 0) return;
Mesh_t* m = &Meshs[meshIndex];
if (m->NumTriangles == 0) return;
Tell me guys, which functions I need to replace to make this VAO works great ?
void BMD::RenderMesh_VAO(int i,
int renderFlags, float alpha,
int /*blendMeshIndex*/, float blendMeshLight,
float blendMeshTexCoordU, float blendMeshTexCoordV,
int explicitTextureIndex)
{
if (i < 0 || i >= NumMeshs) return;
Mesh_t* m = &Meshs[i];
if (m->NumTriangles <= 0) return;
UpdateMeshVAO(i, *m);
GLStateGuard guard; guard.capture();
GLMini_Log("AFTER_CLEAN", i, renderFlags, -1, -1, alpha,
BodyLight[0], BodyLight[1], BodyLight[2]);
int tex = (explicitTextureIndex != -1) ? explicitTextureIndex : IndexTexture[m->Texture];
if (tex == BITMAP_HIDE) { guard.restore(); return; }
if (tex == BITMAP_SKIN) { if (HideSkin) { guard.restore(); return; } tex = BITMAP_SKIN + Skin; }
BindTexture(tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GLuint prog = GetVAOShader();
glUseProgram(prog);
GLfloat mv[16], pr[16];
glGetFloatv(GL_MODELVIEW_MATRIX, mv);
glGetFloatv(GL_PROJECTION_MATRIX, pr);
glUniformMatrix4fv(glGetUniformLocation(prog, "view"), 1, GL_FALSE, mv);
glUniformMatrix4fv(glGetUniformLocation(prog, "projection"), 1, GL_FALSE, pr);
const int hasShift =
((renderFlags & RENDER_TEXTURE) &&
(blendMeshTexCoordU != 0.f || blendMeshTexCoordV != 0.f)) ? 1 : 0;
glUniform1i(glGetUniformLocation(prog, "uHasShift"), hasShift);
glUniform1f(glGetUniformLocation(prog, "uShiftU"), blendMeshTexCoordU);
glUniform1f(glGetUniformLocation(prog, "uShiftV"), blendMeshTexCoordV);
glUniform1i(glGetUniformLocation(prog, "texture1"), 0);
glUniform1f(glGetUniformLocation(prog, "Alpha"), alpha);
const int hasSpecialColor =
(renderFlags & (RENDER_COLOR | RENDER_CHROME | RENDER_OIL)) != 0;
const int isWorldBase =
((renderFlags & RENDER_TEXTURE) != 0) && !hasSpecialColor;
const int useColors = isWorldBase ? 0 : ((LightEnable != 0) ? 1 : 0);
glUniform1i(glGetUniformLocation(prog, "uUseColors"), useColors);
const bool nodepth = (renderFlags & RENDER_NODEPTH) != 0;
if (nodepth) glDisable(GL_DEPTH_TEST); else glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
const bool wantsBright = (renderFlags & RENDER_BRIGHT) != 0;
const bool wantsDark = (renderFlags & RENDER_DARK) != 0;
glBindVertexArray(m->VAO);
// ===== BASE PASS =====
if (!wantsBright) {
glDisable(GL_BLEND);
if (alpha < 0.999f) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
glUniform1i(glGetUniformLocation(prog, "uMode"), 0);
glUniform1f(glGetUniformLocation(prog, "uAlphaCut"), 0.25f);
GLMini_Log("BASE", i, renderFlags, 0, useColors, alpha,
BodyLight[0], BodyLight[1], BodyLight[2]);
glDrawElements(GL_TRIANGLES, m->drawIndexCount, GL_UNSIGNED_SHORT, (void*)0);
}
else {
GLMini_Log("SKIP_BASE_BRIGHT", i, renderFlags, 0, useColors, alpha,
BodyLight[0], BodyLight[1], BodyLight[2]);
}
// ===== BRIGHT (additive) =====
if (wantsBright) {
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glUniform1i(glGetUniformLocation(prog, "uMode"), 1);
glUniform1f(glGetUniformLocation(prog, "uBrightScale"),
(blendMeshLight > 0.f ? blendMeshLight : 1.f));
glUniform3f(glGetUniformLocation(prog, "uBodyLight"),
clamp01f(BodyLight[0]), clamp01f(BodyLight[1]), clamp01f(BodyLight[2]));
glUniform1f(glGetUniformLocation(prog, "uAlphaCut"), 0.01f);
GLMini_Log("BRIGHT", i, renderFlags, 1, useColors, alpha,
BodyLight[0], BodyLight[1], BodyLight[2]);
glDrawElements(GL_TRIANGLES, m->drawIndexCount, GL_UNSIGNED_SHORT, (void*)0);
glDepthMask(GL_TRUE);
}
// ===== DARK (subtractive) =====
if (wantsDark) {
glEnable(GL_BLEND);
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
glUniform1i(glGetUniformLocation(prog, "uMode"), 2);
glUniform1f(glGetUniformLocation(prog, "uAlphaCut"), 0.0f);
GLMini_Log("DARK", i, renderFlags, 2, useColors, alpha,
BodyLight[0], BodyLight[1], BodyLight[2]);
glDrawElements(GL_TRIANGLES, m->drawIndexCount, GL_UNSIGNED_SHORT, (void*)0);
}
glBindVertexArray(0);
glDisable(GL_BLEND);
glUseProgram(0);
guard.restore();
}
void BMD::UpdateMeshVAO(int meshIndex, Mesh_t& m)
{
if (!m.gpuReady) BuildMeshVAO(meshIndex, m);
const size_t N = m.remapV.size();
const int useLight = (LightEnable != 0); // включён ли пер-вершинный свет
for (size_t i = 0; i < N; ++i)
{
const int sv = m.remapV[i];
const size_t base = i * 3;
// позиции — из анимированных вершин
m.cpuPositions[base + 0] = VertexTransform[meshIndex][sv][0];
m.cpuPositions[base + 1] = VertexTransform[meshIndex][sv][1];
m.cpuPositions[base + 2] = VertexTransform[meshIndex][sv][2];
// цвет вершины — ТОЛЬКО LightTransform при включенном лайтинге
float r = 1.f, g = 1.f, b = 1.f;
if (useLight) {
const int sn = m.remapN[i];
r = LightTransform[meshIndex][sn][0];
g = LightTransform[meshIndex][sn][1];
b = LightTransform[meshIndex][sn][2];
// возможный диапазон 0..255 — нормализуем
if (r > 1.f || g > 1.f || b > 1.f) {
r *= (1.f / 255.f);
g *= (1.f / 255.f);
b *= (1.f / 255.f);
}
// защита от NaN/мусора
if (!(r == r)) r = 1.f;
if (!(g == g)) g = 1.f;
if (!(b == b)) b = 1.f;
// мягкий clamp
r = clamp01f(r); g = clamp01f(g); b = clamp01f(b);
}
m.cpuColors[base + 0] = r;
m.cpuColors[base + 1] = g;
m.cpuColors[base + 2] = b;
}
glBindBuffer(GL_ARRAY_BUFFER, m.VBO_Vertices);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * 3 * N, m.cpuPositions.data());
glBindBuffer(GL_ARRAY_BUFFER, m.VBO_Colors);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * 3 * N, m.cpuColors.data());
}
void BMD::BuildMeshVAO(int meshIndex, Mesh_t& m)
{
if (m.gpuReady) return;
m.indices.clear();
m.remapV.clear();
m.remapN.clear();
m.remapT.clear();
m.cpuUVs.clear();
m.indices.reserve(m.NumTriangles * 3);
m.remapV.reserve(m.NumTriangles * 3);
m.remapN.reserve(m.NumTriangles * 3);
m.remapT.reserve(m.NumTriangles * 3);
m.cpuUVs.reserve(m.NumTriangles * 3);
for (int t = 0; t < m.NumTriangles; ++t) {
const Triangle_t& tri = m.Triangles[t];
// MU-модели тут треугольники — берём первые 3 индекса
for (int k = 0; k < 3; ++k) {
const int sv = tri.VertexIndex[k];
const int sn = tri.NormalIndex[k];
const int st = tri.TexCoordIndex[k];
m.remapV.push_back((unsigned short)sv);
m.remapN.push_back((unsigned short)sn);
m.remapT.push_back((unsigned short)st);
m.cpuUVs.push_back(m.TexCoords[st]);
m.indices.push_back((unsigned short)m.indices.size());
}
}
const size_t N = m.remapV.size();
m.drawVertexCount = (GLsizei)N;
m.drawIndexCount = (int)N;
m.cpuPositions.resize(N * 3);
m.cpuColors.resize(N * 3);
glGenVertexArrays(1, &m.VAO);
glBindVertexArray(m.VAO);
// позиции
glGenBuffers(1, &m.VBO_Vertices);
glBindBuffer(GL_ARRAY_BUFFER, m.VBO_Vertices);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * N, 0, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
// цвета
glGenBuffers(1, &m.VBO_Colors);
glBindBuffer(GL_ARRAY_BUFFER, m.VBO_Colors);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * N, 0, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
// UV
glGenBuffers(1, &m.VBO_TexCoords);
glBindBuffer(GL_ARRAY_BUFFER, m.VBO_TexCoords);
glBufferData(GL_ARRAY_BUFFER, sizeof(TexCoord_t) * N, m.cpuUVs.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(TexCoord_t), (void*)0);
// индексы
glGenBuffers(1, &m.EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m.EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * N, m.indices.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
m.gpuReady = true;
}
// ===== Guard для GL-состояний, чтобы VAO не ломал FFP =======================
struct GLStateGuard {
GLboolean blend, alpha, depth, depthMask;
GLint src, dst;
GLint activeTex;
GLboolean tex2D0;
GLint texEnv0;
void capture() {
blend = glIsEnabled(GL_BLEND);
alpha = glIsEnabled(GL_ALPHA_TEST);
depth = glIsEnabled(GL_DEPTH_TEST);
glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask);
glGetIntegerv(GL_BLEND_SRC, &src);
glGetIntegerv(GL_BLEND_DST, &dst);
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
glActiveTexture(GL_TEXTURE0);
tex2D0 = glIsEnabled(GL_TEXTURE_2D);
glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &texEnv0);
glActiveTexture(activeTex);
}
void restore() {
if (blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (alpha) glEnable(GL_ALPHA_TEST); else glDisable(GL_ALPHA_TEST);
if (depth) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
glDepthMask(depthMask);
glBlendFunc(src, dst);
GLint was = 0; glGetIntegerv(GL_ACTIVE_TEXTURE, &was);
glActiveTexture(GL_TEXTURE0);
if (tex2D0) glEnable(GL_TEXTURE_2D); else glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texEnv0);
glActiveTexture(was);
}
};
// ZzzBMD.cpp
static void CleanFixedStatesForShader()
{
glDisable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_FOG);
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
GLint maxTU = 0;
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTU);
for (int u = 0; u < maxTU; ++u) {
glActiveTexture(GL_TEXTURE0 + u);
if (u == 0) glEnable(GL_TEXTURE_2D); else glDisable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
glActiveTexture(GL_TEXTURE0);
}
What I am doing wrong?
@takumi12