2018-02-08 23:40:26 +00:00
|
|
|
// Hyperbolic Rogue -- basic GL transformations
|
|
|
|
// If CAP_SHADER is 0, OpenGL 1.0 is used.
|
|
|
|
// If CAP_SHADER is 1, GLSL is used.
|
|
|
|
|
2018-06-10 23:58:31 +00:00
|
|
|
namespace hr {
|
|
|
|
|
2018-02-12 12:12:48 +00:00
|
|
|
#ifndef DEBUG_GL
|
|
|
|
#define DEBUG_GL 0
|
|
|
|
#endif
|
2018-02-10 17:21:19 +00:00
|
|
|
|
2018-02-08 23:40:26 +00:00
|
|
|
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
|
2018-02-08 23:29:20 +00:00
|
|
|
|
2018-02-09 02:40:46 +00:00
|
|
|
void glError(const char* GLcall, const char* file, const int line) {
|
|
|
|
GLenum errCode = glGetError();
|
|
|
|
if(errCode!=GL_NO_ERROR) {
|
|
|
|
fprintf(stderr, "OPENGL ERROR #%i: in file %s on line %i :: %s\n",errCode,file, line, GLcall);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-12 12:12:48 +00:00
|
|
|
#ifndef CAP_VERTEXBUFFER
|
2018-02-11 20:39:47 +00:00
|
|
|
#define CAP_VERTEXBUFFER (ISWEB)
|
2018-02-12 12:12:48 +00:00
|
|
|
#endif
|
2018-02-11 18:08:17 +00:00
|
|
|
|
2018-02-08 23:29:20 +00:00
|
|
|
namespace glhr {
|
|
|
|
|
2018-02-10 14:18:44 +00:00
|
|
|
bool glew = false;
|
|
|
|
|
2018-02-11 18:08:17 +00:00
|
|
|
typedef const void *constvoidptr;
|
|
|
|
|
|
|
|
constvoidptr current_vertices, buffered_vertices;
|
|
|
|
|
|
|
|
GLuint buf_current, buf_buffered;
|
|
|
|
|
2018-02-09 00:46:14 +00:00
|
|
|
enum eMode { gmColored, gmTextured, gmVarColored, gmLightFog, gmMAX};
|
|
|
|
|
|
|
|
static const flagtype GF_TEXTURE = 1;
|
|
|
|
static const flagtype GF_VARCOLOR = 2;
|
|
|
|
static const flagtype GF_LIGHTFOG = 4;
|
|
|
|
|
2018-03-02 12:08:14 +00:00
|
|
|
flagtype flags[gmMAX] = { 0, GF_TEXTURE, GF_VARCOLOR, GF_TEXTURE | GF_LIGHTFOG | GF_VARCOLOR
|
2018-02-09 02:40:46 +00:00
|
|
|
};
|
2018-02-09 00:46:14 +00:00
|
|
|
|
|
|
|
eMode mode;
|
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
shader_projection current_shader_projection, new_shader_projection;
|
|
|
|
|
|
|
|
void switch_mode(eMode m, shader_projection sp);
|
2018-02-08 23:29:20 +00:00
|
|
|
|
2018-02-09 02:40:46 +00:00
|
|
|
void display(const glmatrix& m) {
|
|
|
|
for(int i=0; i<4; i++) {
|
|
|
|
for(int j=0; j<4; j++)
|
|
|
|
printf("%10.5f", m[i][j]);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
2018-02-08 23:29:20 +00:00
|
|
|
glmatrix operator * (glmatrix m1, glmatrix m2) {
|
|
|
|
glmatrix res;
|
|
|
|
for(int i=0; i<4; i++)
|
|
|
|
for(int j=0; j<4; j++) {
|
|
|
|
res[i][j] = 0;
|
|
|
|
for(int k=0; k<4; k++)
|
|
|
|
res[i][j] += m1[i][k] * m2[k][j];
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2018-02-20 10:30:39 +00:00
|
|
|
glmatrix id = {{{1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1}}};
|
2018-02-08 23:29:20 +00:00
|
|
|
|
|
|
|
glmatrix scale(ld x, ld y, ld z) {
|
|
|
|
glmatrix tmp;
|
|
|
|
for(int i=0; i<4; i++)
|
|
|
|
for(int j=0; j<4; j++)
|
|
|
|
tmp[i][j] = (i==j);
|
|
|
|
tmp[0][0] = x;
|
|
|
|
tmp[1][1] = y;
|
|
|
|
tmp[2][2] = z;
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
2018-02-09 02:40:46 +00:00
|
|
|
glmatrix ortho(ld x, ld y, ld z) {
|
|
|
|
return scale(1/x, 1/y, 1/z);
|
|
|
|
}
|
|
|
|
|
|
|
|
glmatrix& as_glmatrix(GLfloat o[16]) {
|
|
|
|
glmatrix& tmp = (glmatrix&) (o[0]);
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
glmatrix frustum(ld x, ld y, ld vnear = 1e-3, ld vfar = 1e9) {
|
|
|
|
GLfloat frustum[16] = {
|
|
|
|
GLfloat(1 / x), 0, 0, 0,
|
|
|
|
0, GLfloat(1 / y), 0, 0,
|
|
|
|
0, 0, GLfloat(-(vnear+vfar)/(vfar-vnear)), -1,
|
|
|
|
0, 0, GLfloat(-2*vnear*vfar/(vfar-vnear)), 0};
|
|
|
|
return as_glmatrix(frustum);
|
|
|
|
}
|
|
|
|
|
2018-02-08 23:29:20 +00:00
|
|
|
glmatrix translate(ld x, ld y, ld z) {
|
|
|
|
glmatrix tmp;
|
|
|
|
for(int i=0; i<4; i++)
|
|
|
|
for(int j=0; j<4; j++)
|
|
|
|
tmp[i][j] = (i==j);
|
|
|
|
tmp[3][0] = x;
|
|
|
|
tmp[3][1] = y;
|
|
|
|
tmp[3][2] = z;
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ** legacy **
|
|
|
|
|
|
|
|
#if !CAP_SHADER
|
|
|
|
|
|
|
|
void new_projection() {
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
}
|
|
|
|
|
|
|
|
void projection_multiply(const glmatrix& m) {
|
|
|
|
glMultMatrixf(m.as_array());
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_modelview(const glmatrix& m) {
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadMatrixf(m.as_array());
|
|
|
|
}
|
|
|
|
|
2018-02-20 10:30:39 +00:00
|
|
|
void id_modelview() {
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
}
|
|
|
|
|
2018-02-08 23:29:20 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// /* shaders */
|
|
|
|
|
|
|
|
#if CAP_SHADER
|
|
|
|
|
|
|
|
glmatrix projection;
|
|
|
|
|
|
|
|
void new_projection() {
|
2018-02-20 10:30:39 +00:00
|
|
|
projection = id;
|
2018-02-08 23:29:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void projection_multiply(const glmatrix& m) {
|
|
|
|
projection = m * projection;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define glMatrixMode DISABLED
|
|
|
|
#define glLoadIdentity DISABLED
|
|
|
|
#define glMultMatrixf DISABLED
|
|
|
|
#define glScalef DISABLED
|
|
|
|
#define glTranslatef DISABLED
|
|
|
|
#define glPushMatrix DISABLED
|
|
|
|
#define glPopMatrix DISABLED
|
|
|
|
|
|
|
|
void init();
|
|
|
|
|
2018-02-09 02:40:46 +00:00
|
|
|
int compileShader(int type, const string& s) {
|
2018-02-08 23:29:20 +00:00
|
|
|
GLint status;
|
2018-02-10 17:21:19 +00:00
|
|
|
|
|
|
|
#if DEBUG_GL
|
|
|
|
printf("===\n%s\n===\n", s.c_str());
|
|
|
|
#endif
|
2018-02-09 02:40:46 +00:00
|
|
|
|
2018-02-08 23:29:20 +00:00
|
|
|
GLint shader = glCreateShader(type);
|
2018-02-09 02:40:46 +00:00
|
|
|
const char *ss = s.c_str();
|
|
|
|
glShaderSource(shader, 1, &ss, NULL);
|
2018-02-08 23:29:20 +00:00
|
|
|
glCompileShader(shader);
|
|
|
|
|
|
|
|
GLint logLength;
|
|
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
|
|
|
|
if (logLength > 0) {
|
2018-06-27 22:35:45 +00:00
|
|
|
std::vector<char> log(logLength);
|
|
|
|
glGetShaderInfoLog(shader, logLength, &logLength, log.data());
|
2018-02-08 23:29:20 +00:00
|
|
|
if(logLength > 0)
|
2018-06-27 22:35:45 +00:00
|
|
|
printf("compiler log (%d): '%s'\n", logLength, log.data());
|
2018-02-08 23:29:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
|
|
|
if (status == 0) {
|
|
|
|
glDeleteShader(shader);
|
|
|
|
printf("failed to compile shader\n");
|
|
|
|
shader = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/attributes.php
|
|
|
|
|
|
|
|
struct GLprogram *current = NULL;
|
|
|
|
|
2018-02-10 17:21:19 +00:00
|
|
|
static const int aPosition = 0;
|
|
|
|
static const int aColor = 3;
|
|
|
|
static const int aTexture = 8;
|
2018-02-08 23:29:20 +00:00
|
|
|
|
|
|
|
struct GLprogram {
|
|
|
|
GLuint _program;
|
|
|
|
GLuint vertShader, fragShader;
|
2018-02-10 17:21:19 +00:00
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
GLint uMVP, uFog, uColor, tTexture, uMV, uProjection;
|
2018-02-08 23:29:20 +00:00
|
|
|
|
|
|
|
GLprogram(string vsh, string fsh) {
|
|
|
|
_program = glCreateProgram();
|
2018-02-11 01:19:49 +00:00
|
|
|
|
|
|
|
#ifndef GLES_ONLY
|
|
|
|
while(vsh.find("mediump ") != string::npos)
|
|
|
|
vsh.replace(vsh.find("mediump "), 7, "");
|
|
|
|
while(fsh.find("mediump ") != string::npos)
|
|
|
|
fsh.replace(fsh.find("mediump "), 7, "");
|
|
|
|
#endif
|
|
|
|
|
2018-02-10 14:18:44 +00:00
|
|
|
// printf("creating program %d\n", _program);
|
2018-02-08 23:29:20 +00:00
|
|
|
vertShader = compileShader(GL_VERTEX_SHADER, vsh.c_str());
|
|
|
|
fragShader = compileShader(GL_FRAGMENT_SHADER, fsh.c_str());
|
|
|
|
|
|
|
|
// Attach vertex shader to program.
|
|
|
|
glAttachShader(_program, vertShader);
|
|
|
|
|
|
|
|
// Attach fragment shader to program.
|
|
|
|
glAttachShader(_program, fragShader);
|
|
|
|
|
2018-02-10 17:21:19 +00:00
|
|
|
glBindAttribLocation(_program, aPosition, "aPosition");
|
|
|
|
glBindAttribLocation(_program, aTexture, "aTexture");
|
|
|
|
glBindAttribLocation(_program, aColor, "aColor");
|
|
|
|
|
2018-02-08 23:29:20 +00:00
|
|
|
GLint status;
|
|
|
|
glLinkProgram(_program);
|
|
|
|
|
|
|
|
GLint logLength;
|
|
|
|
glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &logLength);
|
|
|
|
if (logLength > 0) {
|
2018-06-27 22:35:45 +00:00
|
|
|
std::vector<char> log(logLength);
|
|
|
|
glGetProgramInfoLog(_program, logLength, &logLength, log.data());
|
2018-02-08 23:29:20 +00:00
|
|
|
if(logLength > 0)
|
2018-06-27 22:35:45 +00:00
|
|
|
printf("linking log (%d): %s\n", logLength, log.data());
|
2018-02-08 23:29:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
glGetProgramiv(_program, GL_LINK_STATUS, &status);
|
|
|
|
if (status == 0) {
|
|
|
|
printf("failed to link shader\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// glBindAttribLocation(_program, GLKVertexAttribPosition, "position"); ??
|
|
|
|
// glBindAttribLocation(_program, GLKVertexAttribNormal, "normal"); ??
|
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
uMV = glGetUniformLocation(_program, "uMV");
|
|
|
|
uProjection = glGetUniformLocation(_program, "uP");
|
2018-02-10 17:21:19 +00:00
|
|
|
uMVP = glGetUniformLocation(_program, "uMVP");
|
|
|
|
uFog = glGetUniformLocation(_program, "uFog");
|
|
|
|
uColor = glGetUniformLocation(_program, "uColor");
|
|
|
|
tTexture = glGetUniformLocation(_program, "tTexture");
|
|
|
|
|
|
|
|
#if DEBUG_GL
|
|
|
|
printf("uniforms: %d %d %d %d\n", uMVP, uFog, uColor, tTexture);
|
|
|
|
#endif
|
|
|
|
// printf("attributes: %d\n", position_index);
|
2018-02-08 23:29:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~GLprogram() {
|
|
|
|
glDeleteProgram(_program);
|
|
|
|
if(vertShader) glDeleteShader(vertShader), vertShader = 0;
|
|
|
|
if(fragShader) glDeleteShader(fragShader), fragShader = 0;
|
|
|
|
current = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void enable() {
|
|
|
|
if(this != current) {
|
|
|
|
glUseProgram(_program);
|
|
|
|
current = this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
GLprogram *programs[gmMAX][int(shader_projection::MAX)];
|
2018-02-08 23:29:20 +00:00
|
|
|
|
2018-02-09 03:18:39 +00:00
|
|
|
string stringbuilder() { return ""; }
|
2018-02-09 02:40:46 +00:00
|
|
|
|
2018-02-09 03:18:39 +00:00
|
|
|
template<class... T> string stringbuilder(bool i, const string& s, T... t) {
|
2018-02-10 17:21:19 +00:00
|
|
|
if(i) return s +
|
|
|
|
#if DEBUG_GL
|
|
|
|
"\n" +
|
|
|
|
#endif
|
|
|
|
stringbuilder(t...);
|
2018-02-09 03:18:39 +00:00
|
|
|
else return stringbuilder(t...);
|
|
|
|
}
|
2018-02-09 02:40:46 +00:00
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
glmatrix current_matrix, current_modelview, current_projection;
|
2018-09-04 21:27:27 +00:00
|
|
|
|
|
|
|
bool operator == (const glmatrix& m1, const glmatrix& m2) {
|
|
|
|
for(int i=0; i<4; i++)
|
|
|
|
for(int j=0; j<4; j++)
|
|
|
|
if(m1[i][j] != m2[i][j]) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
bool operator != (const glmatrix& m1, const glmatrix& m2) {
|
|
|
|
return !(m1 == m2);
|
|
|
|
}
|
|
|
|
|
2018-02-08 23:29:20 +00:00
|
|
|
void set_modelview(const glmatrix& modelview) {
|
2019-01-24 13:48:53 +00:00
|
|
|
if(!current) return;
|
2018-11-17 16:59:57 +00:00
|
|
|
if(current_shader_projection != shader_projection::standard) {
|
|
|
|
if(modelview != current_modelview) {
|
|
|
|
current_modelview = modelview;
|
|
|
|
glUniformMatrix4fv(current->uMV, 1, 0, modelview.as_array());
|
|
|
|
}
|
|
|
|
if(projection != current_projection) {
|
|
|
|
current_projection = projection;
|
|
|
|
glUniformMatrix4fv(current->uProjection, 1, 0, projection.as_array());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
glmatrix mvp = modelview * projection;
|
|
|
|
#if MINIMIZE_GL_CALLS
|
|
|
|
if(mvp == current_matrix) return;
|
|
|
|
current_matrix = mvp;
|
|
|
|
#endif
|
|
|
|
glUniformMatrix4fv(current->uMVP, 1, 0, mvp.as_array());
|
|
|
|
}
|
2018-02-08 23:29:20 +00:00
|
|
|
// glmatrix nm = modelview;
|
|
|
|
// glUniformMatrix3fv(current->uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, nm[0]);
|
|
|
|
}
|
|
|
|
|
2018-02-20 10:30:39 +00:00
|
|
|
void id_modelview() {
|
2019-01-24 13:48:53 +00:00
|
|
|
if(!current) return;
|
2018-11-17 16:59:57 +00:00
|
|
|
if(current_shader_projection != shader_projection::standard) { set_modelview(id); return; }
|
2018-09-04 21:27:27 +00:00
|
|
|
#if MINIMIZE_GL_CALLS
|
|
|
|
if(projection == current_matrix) return;
|
|
|
|
current_matrix = projection;
|
|
|
|
#endif
|
2018-02-20 10:30:39 +00:00
|
|
|
glUniformMatrix4fv(current->uMVP, 1, 0, projection.as_array());
|
|
|
|
}
|
|
|
|
|
2018-02-08 23:29:20 +00:00
|
|
|
#endif
|
2018-02-09 00:46:14 +00:00
|
|
|
|
2019-02-06 17:39:53 +00:00
|
|
|
void color2(color_t color, ld scale) {
|
2018-02-10 17:21:19 +00:00
|
|
|
GLfloat cols[4];
|
2019-01-16 22:15:40 +00:00
|
|
|
for(int i=0; i<4; i++)
|
2019-02-06 17:39:53 +00:00
|
|
|
cols[i] = part(color, 3-i) / 255.0 * scale;
|
2018-02-10 17:21:19 +00:00
|
|
|
#if CAP_SHADER
|
|
|
|
// glUniform4fv(current->uFog, 4, cols);
|
2019-01-24 13:48:53 +00:00
|
|
|
if(!current) return;
|
2018-02-10 17:21:19 +00:00
|
|
|
glUniform4f(current->uColor, cols[0], cols[1], cols[2], cols[3]);
|
|
|
|
#else
|
|
|
|
glColor4f(cols[0], cols[1], cols[2], cols[3]);
|
|
|
|
#endif
|
2018-02-09 02:40:46 +00:00
|
|
|
}
|
|
|
|
|
2018-09-04 17:53:42 +00:00
|
|
|
void colorClear(color_t color) {
|
2019-02-06 17:39:53 +00:00
|
|
|
glClearColor(part(color, 3) / 255.0, part(color, 2) / 255.0, part(color, 1) / 255.0, part(color, 0) / 255.0);
|
2019-01-16 22:15:40 +00:00
|
|
|
}
|
2018-02-09 00:46:14 +00:00
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
void be_nontextured(shader_projection sp) { switch_mode(gmColored, sp); }
|
|
|
|
void be_textured(shader_projection sp) { switch_mode(gmTextured, sp); }
|
2018-02-09 00:46:14 +00:00
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
void switch_mode(eMode m, shader_projection sp) {
|
|
|
|
if(m == mode && current_shader_projection == sp) return;
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("pre_switch_mode");
|
2018-02-09 00:46:14 +00:00
|
|
|
#if CAP_SHADER
|
2018-11-17 16:59:57 +00:00
|
|
|
programs[m][int(sp)]->enable();
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("after_enable");
|
2018-02-09 00:46:14 +00:00
|
|
|
#endif
|
|
|
|
flagtype newflags = flags[m] &~ flags[mode];
|
|
|
|
flagtype oldflags = flags[mode] &~ flags[m];
|
|
|
|
if(newflags & GF_TEXTURE) {
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("xsm");
|
2018-02-10 17:21:19 +00:00
|
|
|
#if CAP_SHADER
|
|
|
|
glEnableVertexAttribArray(aTexture);
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("xsm");
|
2018-02-10 17:21:19 +00:00
|
|
|
#else
|
2018-02-11 01:19:49 +00:00
|
|
|
glEnable(GL_TEXTURE_2D);
|
2018-02-09 00:46:14 +00:00
|
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("xsm");
|
2018-02-10 17:21:19 +00:00
|
|
|
#endif
|
2018-02-09 00:46:14 +00:00
|
|
|
}
|
|
|
|
if(oldflags & GF_TEXTURE) {
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("xsm");
|
2018-02-10 17:21:19 +00:00
|
|
|
#if CAP_SHADER
|
|
|
|
glDisableVertexAttribArray(aTexture);
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("xsm");
|
2018-02-10 17:21:19 +00:00
|
|
|
#else
|
2018-02-09 00:46:14 +00:00
|
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
2018-02-11 01:19:49 +00:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
GLERR("xsm");
|
2018-02-10 17:21:19 +00:00
|
|
|
#endif
|
2018-02-09 00:46:14 +00:00
|
|
|
}
|
2018-02-10 17:21:19 +00:00
|
|
|
if(newflags & GF_VARCOLOR) {
|
|
|
|
#if CAP_SHADER
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("xsm");
|
2018-02-10 17:21:19 +00:00
|
|
|
glEnableVertexAttribArray(aColor);
|
|
|
|
#else
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("xsm");
|
2018-02-09 00:46:14 +00:00
|
|
|
glEnableClientState(GL_COLOR_ARRAY);
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("xsm");
|
2018-02-10 17:21:19 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
if(oldflags & GF_VARCOLOR) {
|
|
|
|
#if CAP_SHADER
|
|
|
|
glDisableVertexAttribArray(aColor);
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("xsm");
|
2018-02-10 17:21:19 +00:00
|
|
|
#else
|
2018-02-09 00:46:14 +00:00
|
|
|
glDisableClientState(GL_COLOR_ARRAY);
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("xsm");
|
2018-02-10 17:21:19 +00:00
|
|
|
#endif
|
|
|
|
}
|
2018-02-09 00:46:14 +00:00
|
|
|
if(newflags & GF_LIGHTFOG) {
|
2018-02-09 02:40:46 +00:00
|
|
|
#if !CAP_SHADER
|
2018-02-12 15:21:42 +00:00
|
|
|
/*GLfloat light_ambient[] = { 3.5, 3.5, 3.5, 1.0 };
|
2018-02-09 00:46:14 +00:00
|
|
|
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
|
|
|
|
GLfloat light_position[] = { 0.0, 0.0, 0.0, 1.0 };
|
|
|
|
|
|
|
|
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
|
|
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
|
|
|
|
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
|
|
|
|
|
|
|
|
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
|
|
|
|
GLERR("lighting");
|
|
|
|
|
|
|
|
glEnable(GL_LIGHTING);
|
2018-02-12 15:21:42 +00:00
|
|
|
glEnable(GL_LIGHT0); */
|
|
|
|
|
2018-02-09 00:46:14 +00:00
|
|
|
glEnable(GL_FOG);
|
2018-02-12 15:21:42 +00:00
|
|
|
#ifdef GLES_ONLY
|
|
|
|
glFogx(GL_FOG_MODE, GL_LINEAR);
|
|
|
|
#else
|
2018-02-09 00:46:14 +00:00
|
|
|
glFogi(GL_FOG_MODE, GL_LINEAR);
|
2018-02-12 15:21:42 +00:00
|
|
|
#endif
|
2018-02-09 00:46:14 +00:00
|
|
|
glFogf(GL_FOG_START, 0);
|
2018-02-09 02:40:46 +00:00
|
|
|
#endif
|
2018-02-09 00:46:14 +00:00
|
|
|
}
|
|
|
|
if(oldflags & GF_LIGHTFOG) {
|
2018-02-09 02:40:46 +00:00
|
|
|
#if !CAP_SHADER
|
2018-02-09 00:46:14 +00:00
|
|
|
glDisable(GL_FOG);
|
2018-03-02 12:08:14 +00:00
|
|
|
|
2018-02-12 15:21:42 +00:00
|
|
|
/*
|
|
|
|
glDisable(GL_LIGHTING); */
|
2018-02-09 02:40:46 +00:00
|
|
|
#endif
|
2018-02-09 00:46:14 +00:00
|
|
|
}
|
|
|
|
mode = m;
|
2018-11-17 16:59:57 +00:00
|
|
|
current_shader_projection = sp;
|
2018-02-11 01:19:49 +00:00
|
|
|
GLERR("after_switch_mode");
|
2018-02-11 18:08:17 +00:00
|
|
|
current_vertices = NULL;
|
2018-09-04 21:27:27 +00:00
|
|
|
current_matrix[0][0] = -1e8; // invalid
|
2018-11-17 16:59:57 +00:00
|
|
|
current_modelview[0][0] = -1e8;
|
|
|
|
current_projection[0][0] = -1e8;
|
2018-07-21 22:39:57 +00:00
|
|
|
id_modelview();
|
2018-02-09 00:46:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void fog_max(ld fogmax) {
|
2018-02-09 02:40:46 +00:00
|
|
|
#if CAP_SHADER
|
2018-02-10 17:21:19 +00:00
|
|
|
glUniform1f(current->uFog, 1 / fogmax);
|
2018-02-09 02:40:46 +00:00
|
|
|
#else
|
2018-02-09 00:46:14 +00:00
|
|
|
glFogf(GL_FOG_END, fogmax);
|
2018-02-09 02:40:46 +00:00
|
|
|
#endif
|
2018-02-09 00:46:14 +00:00
|
|
|
}
|
|
|
|
|
2018-02-10 14:18:44 +00:00
|
|
|
void init() {
|
|
|
|
#if CAP_GLEW
|
|
|
|
if(!glew) {
|
|
|
|
glew = true;
|
|
|
|
printf("Initializing GLEW\n");
|
|
|
|
GLenum err = glewInit();
|
|
|
|
if (GLEW_OK != err) {
|
|
|
|
addMessage("Failed to initialize GLEW");
|
|
|
|
printf("Failed to initialize GLEW\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if CAP_SHADER
|
2018-02-20 10:30:39 +00:00
|
|
|
projection = id;
|
2018-02-10 14:18:44 +00:00
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
for(int i=0; i<gmMAX; i++)
|
|
|
|
for(int j=0; j<int(shader_projection::MAX); j++) {
|
2018-02-10 14:18:44 +00:00
|
|
|
flagtype f = flags[i];
|
|
|
|
|
|
|
|
bool texture = f & GF_TEXTURE;
|
2018-02-10 17:21:19 +00:00
|
|
|
bool lfog = f & GF_LIGHTFOG;
|
|
|
|
bool varcol = f & GF_VARCOLOR;
|
2018-02-10 14:18:44 +00:00
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
shader_projection sp = shader_projection(j);
|
|
|
|
|
|
|
|
bool mps = j != 0;
|
|
|
|
bool band = (sp == shader_projection::band);
|
2018-11-19 19:52:01 +00:00
|
|
|
bool hp = (sp == shader_projection::halfplane);
|
2019-02-22 20:01:01 +00:00
|
|
|
bool s3 = (sp == shader_projection::standard3);
|
2018-11-17 16:59:57 +00:00
|
|
|
|
|
|
|
programs[i][j] = new GLprogram(stringbuilder(
|
2018-02-11 01:19:49 +00:00
|
|
|
|
|
|
|
1, "attribute mediump vec4 aPosition;",
|
|
|
|
texture, "attribute mediump vec2 aTexture;",
|
|
|
|
varcol, "attribute mediump vec4 aColor;",
|
2018-02-10 14:18:44 +00:00
|
|
|
// "attribute vec3 normal;"
|
|
|
|
|
2018-02-11 01:19:49 +00:00
|
|
|
1, "varying mediump vec4 vColor;",
|
|
|
|
texture, "varying mediump vec2 vTexCoord;",
|
2018-02-10 14:18:44 +00:00
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
!mps, "uniform mediump mat4 uMVP;",
|
|
|
|
mps, "uniform mediump mat4 uMV;",
|
|
|
|
mps, "uniform mediump mat4 uP;",
|
2018-02-11 01:19:49 +00:00
|
|
|
1, "uniform mediump float uFog;",
|
|
|
|
!varcol, "uniform mediump vec4 uColor;",
|
2018-11-17 16:59:57 +00:00
|
|
|
|
|
|
|
1, "float sinh(float x) {",
|
|
|
|
1, " return (exp(x) - exp(-x)) / 2.0;",
|
|
|
|
1, " }",
|
|
|
|
|
|
|
|
1, "float cosh(float x) {",
|
|
|
|
1, " return (exp(x) + exp(-x)) / 2.0;",
|
|
|
|
1, " }",
|
|
|
|
|
|
|
|
1, "float tanh(float x) {",
|
|
|
|
1, " return sinh(x) / cosh(x);",
|
|
|
|
1, " }",
|
|
|
|
|
|
|
|
1, "float asinh(float x) {",
|
2019-02-22 20:01:01 +00:00
|
|
|
1, " return log(sqrt(x*x + 1.0) + x);",
|
2018-11-17 16:59:57 +00:00
|
|
|
1, " }",
|
2019-02-22 20:01:01 +00:00
|
|
|
|
|
|
|
1, "float acosh(float x) {",
|
|
|
|
1, " return log(sqrt(x*x - 1.0) + x);",
|
|
|
|
1, " }",
|
|
|
|
|
2018-11-18 16:27:27 +00:00
|
|
|
1, "float zlevel(vec4 h) {",
|
|
|
|
1, " return (h[2] < 0.0 ? -1.0 : 1.0) * sqrt(h[2]*h[2] - h[0]*h[0] - h[1]*h[1]);",
|
|
|
|
1, " }",
|
|
|
|
|
2018-02-10 14:18:44 +00:00
|
|
|
1, "void main() {",
|
2018-02-10 17:21:19 +00:00
|
|
|
texture, "vTexCoord = aTexture;",
|
|
|
|
varcol, "vColor = aColor;",
|
|
|
|
!varcol, "vColor = uColor;",
|
|
|
|
lfog, "vColor = vColor * clamp(1.0 + aPosition.z * uFog, 0.0, 1.0);",
|
2018-11-17 16:59:57 +00:00
|
|
|
!mps, "gl_Position = uMVP * aPosition;",
|
|
|
|
mps&&!band,"gl_Position = uP * (uMV * aPosition);",
|
2018-11-19 19:52:01 +00:00
|
|
|
|
|
|
|
band||hp, "vec4 t = uMV * aPosition;",
|
|
|
|
band||hp, "float zlev = zlevel(t);",
|
|
|
|
band||hp, "t /= zlev;",
|
2018-11-18 16:27:27 +00:00
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
band, "float ty = asinh(t.y);",
|
|
|
|
band, "float tx = asinh(t.x / cosh(ty));",
|
|
|
|
band, "ty = 2.0 * atan(tanh(ty/2.0));",
|
|
|
|
band, "t[0] = tx; t[1] = ty; t[2] = 1.0; t[3] = 1.0;",
|
2018-11-19 19:52:01 +00:00
|
|
|
|
|
|
|
hp, "t.x /= t.z; t.y /= t.z; t.y = t.y + 1.0; ",
|
|
|
|
hp, "float rads = t.x * t.x + t.y * t.y; ",
|
|
|
|
hp, "t.x /= -rads; t.y /= -rads; t.z = 1.0; t[3] = 1.0;",
|
|
|
|
|
2019-02-22 20:01:01 +00:00
|
|
|
s3, "vec4 t = uMV * aPosition;",
|
|
|
|
s3, "vColor.xyz = vColor.xyz * (1.0 - acosh(t[3]) / uFog);",
|
|
|
|
s3, "t[3] = 1.0;",
|
|
|
|
|
2018-11-19 19:52:01 +00:00
|
|
|
band || hp,"gl_Position = uP * t;",
|
2018-02-10 14:18:44 +00:00
|
|
|
1, "}"),
|
|
|
|
|
|
|
|
stringbuilder(
|
|
|
|
|
2018-02-11 01:19:49 +00:00
|
|
|
1, "uniform mediump sampler2D tTexture;",
|
|
|
|
1, "varying mediump vec4 vColor;",
|
|
|
|
texture, "varying mediump vec2 vTexCoord;",
|
2018-02-10 14:18:44 +00:00
|
|
|
1, "void main() {",
|
2018-02-10 17:21:19 +00:00
|
|
|
texture, "gl_FragColor = vColor * texture2D(tTexture, vTexCoord);",
|
2018-02-10 14:18:44 +00:00
|
|
|
!texture, "gl_FragColor = vColor;",
|
|
|
|
1, "}"
|
2018-11-17 16:59:57 +00:00
|
|
|
));
|
2018-02-10 14:18:44 +00:00
|
|
|
}
|
|
|
|
|
2018-11-17 16:59:57 +00:00
|
|
|
switch_mode(gmColored, shader_projection::standard);
|
|
|
|
programs[gmColored][0]->enable();
|
2018-02-10 14:18:44 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !CAP_SHADER
|
2018-11-17 16:59:57 +00:00
|
|
|
switch_mode(gmColored, 0);
|
2018-02-10 14:18:44 +00:00
|
|
|
#endif
|
|
|
|
|
2018-02-10 17:21:19 +00:00
|
|
|
#if CAP_SHADER
|
|
|
|
glEnableVertexAttribArray(aPosition);
|
|
|
|
#else
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
|
|
#endif
|
|
|
|
// #endif
|
2018-02-11 18:08:17 +00:00
|
|
|
|
|
|
|
#if CAP_VERTEXBUFFER
|
|
|
|
glGenBuffers(1, &buf_current);
|
|
|
|
glGenBuffers(1, &buf_buffered);
|
|
|
|
current_vertices = NULL;
|
|
|
|
buffered_vertices = (void*) &buffered_vertices; // point to nothing
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, buf_current);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
hyperpoint gltopoint(const glvertex& t) {
|
|
|
|
hyperpoint h;
|
2019-02-24 18:40:01 +00:00
|
|
|
h[0] = t[0]; h[1] = t[1]; h[2] = t[2];
|
|
|
|
if(SHDIM == 4 && MAXDIM == 4) h[3] = t[3];
|
2018-02-11 18:08:17 +00:00
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
glvertex pointtogl(const hyperpoint& t) {
|
|
|
|
glvertex h;
|
2019-02-24 18:40:01 +00:00
|
|
|
h[0] = t[0]; h[1] = t[1]; h[2] = t[2];
|
|
|
|
if(SHDIM == 4) h[3] = (DIM == 3) ? t[3] : 1;
|
2018-02-11 18:08:17 +00:00
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if CAP_VERTEXBUFFER
|
|
|
|
template<class T> void bindbuffer(T& v) {
|
2018-02-20 20:11:32 +00:00
|
|
|
if(current_vertices == buffered_vertices || current_vertices == nullptr) {
|
2018-02-11 18:08:17 +00:00
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, buf_current);
|
|
|
|
}
|
|
|
|
current_vertices = &v[0];
|
2018-06-22 12:47:24 +00:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, isize(v) * sizeof(v[0]), &v[0], GL_DYNAMIC_DRAW);
|
2018-02-11 18:08:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define PTR(attrib, q, field) \
|
|
|
|
glVertexAttribPointer(attrib, q, GL_FLOAT, GL_FALSE, sizeof(v[0]), (void*) ((char*) &v[0].field - (char*) &v[0]));
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void vertices(const vector<glvertex>& v) {
|
|
|
|
#if CAP_VERTEXBUFFER
|
|
|
|
if(&v[0] == buffered_vertices) {
|
|
|
|
if(&v[0] == current_vertices) return;
|
|
|
|
current_vertices = buffered_vertices;
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, buf_buffered);
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexAttribPointer(glhr::aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), 0);
|
2018-02-11 18:08:17 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
bindbuffer(v);
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexAttribPointer(glhr::aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), 0);
|
2018-02-11 18:08:17 +00:00
|
|
|
#else
|
|
|
|
if(current_vertices == &v[0]) return;
|
|
|
|
current_vertices = &v[0];
|
|
|
|
#if CAP_SHADER
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), &v[0]);
|
2018-02-11 18:08:17 +00:00
|
|
|
#else
|
|
|
|
glVertexPointer(3, GL_FLOAT, sizeof(glvertex), &v[0]);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void vertices_texture(const vector<glvertex>& v, const vector<glvertex>& t) {
|
2018-02-12 15:21:42 +00:00
|
|
|
#if CAP_VERTEXBUFFER
|
|
|
|
// not implemented!
|
|
|
|
#else
|
2018-02-11 18:08:17 +00:00
|
|
|
vertices(v);
|
|
|
|
#if CAP_SHADER
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexAttribPointer(aTexture, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), &t[0]);
|
2018-02-11 18:08:17 +00:00
|
|
|
#else
|
2019-02-22 19:58:40 +00:00
|
|
|
glTexCoordPointer(SHDIM, GL_FLOAT, 0, &v[0]);
|
2018-02-11 18:08:17 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void prepare(vector<colored_vertex>& v) {
|
|
|
|
#if CAP_VERTEXBUFFER
|
|
|
|
bindbuffer(v);
|
2019-02-22 19:58:40 +00:00
|
|
|
PTR(glhr::aPosition, SHDIM, coords);
|
2018-02-11 18:08:17 +00:00
|
|
|
PTR(glhr::aColor, 4, color);
|
|
|
|
#else
|
|
|
|
if(current_vertices == &v[0]) return;
|
|
|
|
current_vertices = &v[0];
|
|
|
|
#if CAP_SHADER
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(colored_vertex), &v[0].coords);
|
2018-02-11 18:08:17 +00:00
|
|
|
glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, sizeof(colored_vertex), &v[0].color);
|
|
|
|
#else
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexPointer(SHDIM, GL_FLOAT, sizeof(colored_vertex), &v[0].coords);
|
2018-03-02 12:11:53 +00:00
|
|
|
glColorPointer(4, GL_FLOAT, sizeof(colored_vertex), &v[0].color);
|
2018-02-11 18:08:17 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void prepare(vector<textured_vertex>& v) {
|
|
|
|
#if CAP_VERTEXBUFFER
|
|
|
|
bindbuffer(v);
|
2019-02-22 19:58:40 +00:00
|
|
|
PTR(glhr::aPosition, SHDIM, coords);
|
2018-02-11 18:08:17 +00:00
|
|
|
PTR(glhr::aTexture, 2, texture);
|
|
|
|
#else
|
|
|
|
if(current_vertices == &v[0]) return;
|
|
|
|
current_vertices = &v[0];
|
|
|
|
#if CAP_SHADER
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(textured_vertex), &v[0].coords);
|
|
|
|
glVertexAttribPointer(aTexture, SHDIM, GL_FLOAT, GL_FALSE, sizeof(textured_vertex), &v[0].texture);
|
2018-02-11 18:08:17 +00:00
|
|
|
#else
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexPointer(SHDIM, GL_FLOAT, sizeof(textured_vertex), &v[0].coords);
|
|
|
|
glTexCoordPointer(2, GL_FLOAT, sizeof(textured_vertex), &v[0].texture);
|
2018-02-11 18:08:17 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
// color2(col);
|
|
|
|
}
|
|
|
|
|
|
|
|
void prepare(vector<ct_vertex>& v) {
|
|
|
|
#if CAP_VERTEXBUFFER
|
|
|
|
bindbuffer(v);
|
2019-02-22 19:58:40 +00:00
|
|
|
PTR(glhr::aPosition, SHDIM, coords);
|
2018-02-11 18:08:17 +00:00
|
|
|
PTR(glhr::aColor, 4, color);
|
|
|
|
PTR(glhr::aTexture, 2, texture);
|
|
|
|
#else
|
|
|
|
if(current_vertices == &v[0]) return;
|
|
|
|
current_vertices = &v[0];
|
|
|
|
#if CAP_SHADER
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(ct_vertex), &v[0].coords);
|
2018-02-11 18:08:17 +00:00
|
|
|
glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, sizeof(ct_vertex), &v[0].color);
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexAttribPointer(aTexture, 2, GL_FLOAT, GL_FALSE, sizeof(ct_vertex), &v[0].texture);
|
2018-02-11 18:08:17 +00:00
|
|
|
#else
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexPointer(SHDIM, GL_FLOAT, sizeof(ct_vertex), &v[0].coords);
|
|
|
|
glTexCoordPointer(2, GL_FLOAT, sizeof(ct_vertex), &v[0].texture);
|
2018-03-02 12:08:14 +00:00
|
|
|
glColorPointer(4, GL_FLOAT, sizeof(ct_vertex), &v[0].color);
|
2018-02-11 18:08:17 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void store_in_buffer(vector<glvertex>& v) {
|
|
|
|
#if CAP_VERTEXBUFFER
|
|
|
|
if(!buf_buffered) {
|
|
|
|
printf("no buffer yet\n");
|
|
|
|
return;
|
|
|
|
}
|
2018-06-22 12:47:24 +00:00
|
|
|
printf("storing %d in buffer: %p\n", isize(v), &v[0]);
|
2018-02-11 18:08:17 +00:00
|
|
|
current_vertices = buffered_vertices = &v[0];
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, buf_buffered);
|
2019-02-22 19:58:40 +00:00
|
|
|
glVertexAttribPointer(glhr::aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), 0);
|
2018-06-22 12:47:24 +00:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, isize(v) * sizeof(glvertex), &v[0], GL_STATIC_DRAW);
|
2018-02-11 18:08:17 +00:00
|
|
|
printf("Stored.\n");
|
|
|
|
#endif
|
2018-02-10 17:21:19 +00:00
|
|
|
}
|
2018-02-10 14:18:44 +00:00
|
|
|
|
2018-03-24 14:15:30 +00:00
|
|
|
bool current_depthtest;
|
|
|
|
|
|
|
|
void set_depthtest(bool b) {
|
|
|
|
if(b != current_depthtest) {
|
|
|
|
current_depthtest = b;
|
|
|
|
if(b) glEnable(GL_DEPTH_TEST);
|
|
|
|
else glDisable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
}
|
2018-02-08 23:29:20 +00:00
|
|
|
}
|
2018-06-10 23:58:31 +00:00
|
|
|
}
|