1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-26 10:00:42 +00:00
hyperrogue/shaders.cpp

1061 lines
31 KiB
C++
Raw Normal View History

// Hyperbolic Rogue -- low-level OpenGL routines
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
/** \file shaders.cpp
* \brief low-level OpenGL routines
*
* If CAP_SHADER is 0, OpenGL 1.0 is used.
* If CAP_SHADER is 1, we are using GLSL shaders.
*/
#include "hyper.h"
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
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
2018-02-08 23:29:20 +00:00
EX 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
#define CAP_VERTEXBUFFER (ISWEB)
2018-02-12 12:12:48 +00:00
#endif
2018-02-11 18:08:17 +00:00
2019-07-12 21:16:54 +00:00
#if CAP_SHADER && CAP_NOSHADER
#define WITHSHADER(x, y) if(glhr::noshaders) y else x
2019-07-03 05:51:30 +00:00
#else
2019-07-12 21:16:54 +00:00
#if CAP_NOSHADER
#define WITHSHADER(x, y) if(1) y
#else
#define WITHSHADER(x, y) if(1) x
#endif
2019-07-03 05:51:30 +00:00
#endif
2019-08-09 20:07:03 +00:00
EX namespace glhr {
#if HDR
struct glmatrix {
GLfloat a[4][4];
GLfloat* operator[] (int i) { return a[i]; }
const GLfloat* operator[] (int i) const { return a[i]; }
GLfloat* as_array() { return a[0]; }
const GLfloat* as_array() const { return a[0]; }
};
glvertex pointtogl(const hyperpoint& t);
enum class shader_projection { standard, band, halfplane, standardH3, standardR3,
standardS30, standardS31, standardS32, standardS33,
ball, halfplane3, band3, flatten, standardSolv, standardNil,
2019-08-24 09:55:45 +00:00
standardEH2, standardSL2,
2019-08-09 20:07:03 +00:00
MAX
};
inline glvertex makevertex(GLfloat x, GLfloat y, GLfloat z) {
#if SHDIM == 3
return make_array(x, y, z);
#else
return make_array<GLfloat>(x, y, z, 1);
#endif
}
struct colored_vertex {
glvertex coords;
glvec4 color;
colored_vertex(GLfloat x, GLfloat y, GLfloat r, GLfloat g, GLfloat b) {
coords[0] = x;
coords[1] = y;
coords[2] = current_display->scrdist;
coords[3] = 1;
color[0] = r;
color[1] = g;
color[2] = b;
color[3] = 1;
}
colored_vertex(hyperpoint h, color_t col) {
coords = pointtogl(h);
for(int i=0; i<4; i++)
color[i] = part(col, 3-i) / 255.0;
}
};
struct textured_vertex {
glvertex coords;
glvec2 texture;
};
struct ct_vertex {
glvertex coords;
glvec4 color;
glvec2 texture;
ct_vertex(const hyperpoint& h, ld x1, ld y1, ld col) {
coords = pointtogl(h);
texture[0] = x1;
texture[1] = y1;
color[0] = color[1] = color[2] = col;
color[3] = 1;
}
};
#endif
2018-02-08 23:29:20 +00:00
2019-07-03 05:51:30 +00:00
#if CAP_SHADER
EX bool noshaders = false;
2019-07-03 05:51:30 +00:00
#else
EX bool noshaders = true;
2019-07-03 05:51:30 +00:00
#endif
2018-02-10 14:18:44 +00:00
bool glew = false;
bool current_depthtest, current_depthwrite;
2019-05-20 11:40:56 +00:00
ld fogbase;
#if HDR
2018-02-11 18:08:17 +00:00
typedef const void *constvoidptr;
#endif
2018-02-11 18:08:17 +00:00
EX constvoidptr current_vertices, buffered_vertices;
ld current_linewidth;
2018-02-11 18:08:17 +00:00
GLuint buf_current, buf_buffered;
#if HDR
2018-02-09 00:46:14 +00:00
enum eMode { gmColored, gmTextured, gmVarColored, gmLightFog, gmMAX};
#endif
2018-02-09 00:46:14 +00:00
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 00:46:14 +00:00
eMode mode;
2019-08-09 20:07:03 +00:00
EX shader_projection current_shader_projection, new_shader_projection;
2018-11-17 16:59:57 +00:00
EX void switch_mode(eMode m, shader_projection sp);
2018-02-08 23:29:20 +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;
}
EX 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
EX glmatrix scale(ld x, ld y, ld z) {
2018-02-08 23:29:20 +00:00
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;
}
2019-08-09 20:07:03 +00:00
EX glmatrix tmtogl(const transmatrix& T) {
glmatrix tmp;
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
tmp[i][j] = T[i][j];
return tmp;
}
EX glmatrix tmtogl_transpose(const transmatrix& T) {
2019-07-28 09:07:21 +00:00
glmatrix tmp;
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
tmp[i][j] = T[j][i];
return tmp;
}
EX glmatrix ortho(ld x, ld y, ld z) {
return scale(1/x, 1/y, 1/z);
}
EX glmatrix& as_glmatrix(GLfloat o[16]) {
glmatrix& tmp = (glmatrix&) (o[0]);
return tmp;
}
EX glmatrix frustum(ld x, ld y, ld vnear IS(1e-3), ld vfar IS(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);
}
2019-08-09 20:07:03 +00:00
EX glmatrix translate(ld x, ld y, ld z) {
2018-02-08 23:29:20 +00:00
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 **
// /* shaders */
glmatrix projection;
EX void new_projection() {
2019-07-03 05:51:30 +00:00
WITHSHADER({
projection = id;
}, {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
return;
2019-07-12 21:16:54 +00:00
})
2018-02-08 23:29:20 +00:00
}
EX void projection_multiply(const glmatrix& m) {
2019-07-03 05:51:30 +00:00
WITHSHADER({
projection = m * projection;
}, {
glMatrixMode(GL_PROJECTION);
glMultMatrixf(m.as_array());
2019-07-12 21:16:54 +00:00
})
2018-02-08 23:29:20 +00:00
}
EX void init();
2018-02-08 23:29:20 +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-08 23:29:20 +00:00
GLint shader = glCreateShader(type);
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) {
std::vector<char> log(logLength);
glGetShaderInfoLog(shader, logLength, &logLength, log.data());
2018-02-08 23:29:20 +00:00
if(logLength > 0)
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
#if HDR
struct GLprogram;
#endif
EX struct GLprogram *current = NULL;
2018-02-08 23:29:20 +00:00
#if HDR
2018-02-10 17:21:19 +00:00
static const int aPosition = 0;
static const int aColor = 3;
static const int aTexture = 8;
#endif
2018-02-08 23:29:20 +00:00
#if HDR
constexpr int INVERSE_EXP_BINDING = 2;
#endif
2019-07-28 09:07:21 +00:00
2018-02-08 23:29:20 +00:00
struct GLprogram {
GLuint _program;
GLuint vertShader, fragShader;
2018-02-10 17:21:19 +00:00
GLint uMVP, uFog, uFogColor, uColor, tTexture, tInvExpTable, uMV, uProjection, uAlpha, uFogBase;
GLint uPRECX, uPRECY, uPRECZ, uIndexSL, uIterations;
2018-02-08 23:29:20 +00:00
2019-08-25 17:14:28 +00:00
string _vsh, _fsh;
2018-02-08 23:29:20 +00:00
GLprogram(string vsh, string fsh) {
2019-08-25 17:14:28 +00:00
_vsh = vsh; _fsh = fsh;
2018-02-08 23:29:20 +00:00
_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) {
std::vector<char> log(logLength);
glGetProgramInfoLog(_program, logLength, &logLength, log.data());
2018-02-08 23:29:20 +00:00
if(logLength > 0)
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");
uFogColor = glGetUniformLocation(_program, "uFogColor");
2019-05-20 11:40:56 +00:00
uFogBase = glGetUniformLocation(_program, "uFogBase");
uAlpha = glGetUniformLocation(_program, "uAlpha");
2018-02-10 17:21:19 +00:00
uColor = glGetUniformLocation(_program, "uColor");
tTexture = glGetUniformLocation(_program, "tTexture");
2019-07-28 09:07:21 +00:00
tInvExpTable = glGetUniformLocation(_program, "tInvExpTable");
2019-07-30 10:56:18 +00:00
uPRECX = glGetUniformLocation(_program, "PRECX");
uPRECY = glGetUniformLocation(_program, "PRECY");
uPRECZ = glGetUniformLocation(_program, "PRECZ");
uIndexSL = glGetUniformLocation(_program, "uIndexSL");
uIterations = glGetUniformLocation(_program, "uIterations");
2019-07-28 09:07:21 +00:00
2018-02-10 17:21:19 +00:00
#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;
}
}
};
2019-09-05 09:58:47 +00:00
EX void set_index_sl(ld x) {
glUniform1f(glhr::current->uIndexSL, x);
}
EX void set_sl_iterations(int steps) {
glUniform1i(glhr::current->uIterations, steps);
}
EX void set_solv_prec(int x, int y, int z) {
glUniform1i(glhr::current->tInvExpTable, glhr::INVERSE_EXP_BINDING);
glUniform1f(glhr::current->uPRECX, x);
glUniform1f(glhr::current->uPRECY, y);
glUniform1f(glhr::current->uPRECZ, z);
}
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 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-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);
}
2019-05-12 12:35:14 +00:00
bool uses_mvp(shader_projection sp) { return among(sp, shader_projection::standard, shader_projection::flatten); }
EX glmatrix eyeshift;
EX bool using_eyeshift;
2019-08-09 20:07:03 +00:00
EX void set_modelview(const glmatrix& modelview) {
2019-07-12 21:16:54 +00:00
#if CAP_NOSHADER
2019-07-03 05:51:30 +00:00
if(noshaders) {
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(modelview.as_array());
return;
}
2019-07-12 21:16:54 +00:00
#endif
if(!current) return;
2019-05-12 12:35:14 +00:00
if(!uses_mvp(current_shader_projection)) {
if(using_eyeshift) {
glmatrix mvp = modelview * eyeshift;
#if MINIMIZE_GL_CALLS
if(mvp == current_matrix) return;
current_matrix = mvp;
#endif
glUniformMatrix4fv(current->uMV, 1, 0, mvp.as_array());
}
else if(modelview != current_modelview) {
2018-11-17 16:59:57 +00:00
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]);
}
EX void id_modelview() {
2019-07-12 21:16:54 +00:00
#if CAP_NOSHADER
2019-07-03 05:51:30 +00:00
if(noshaders) {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
return;
}
2019-07-12 21:16:54 +00:00
#endif
if(!current) return;
2019-05-12 12:35:14 +00:00
if(!uses_mvp(current_shader_projection)) { 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
glUniformMatrix4fv(current->uMVP, 1, 0, projection.as_array());
}
2019-08-09 20:07:03 +00:00
EX void color2(color_t color, ld scale IS(1)) {
2018-02-10 17:21:19 +00:00
GLfloat cols[4];
for(int i=0; i<4; i++)
2019-02-06 17:39:53 +00:00
cols[i] = part(color, 3-i) / 255.0 * scale;
2019-07-03 05:51:30 +00:00
WITHSHADER({
if(!current) return;
glUniform4f(current->uColor, cols[0], cols[1], cols[2], cols[3]);
}, {
glColor4f(cols[0], cols[1], cols[2], cols[3]);
}
)
}
EX 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);
}
2018-02-09 00:46:14 +00:00
2019-08-09 20:07:03 +00:00
EX void be_nontextured(shader_projection sp IS(new_shader_projection)) { switch_mode(gmColored, sp); }
EX void be_textured(shader_projection sp IS(new_shader_projection)) { switch_mode(gmTextured, sp); }
EX void use_projection(shader_projection sp IS(new_shader_projection)) { switch_mode(mode, sp); }
2018-02-09 00:46:14 +00:00
2019-08-25 17:14:28 +00:00
EX pair<string, string> get_shaders() {
auto p = programs[mode][int(current_shader_projection)];
return make_pair(p->_vsh, p->_fsh);
}
EX void install_shaders(string vsh, string fsh) {
delete programs[mode][int(current_shader_projection)];
programs[mode][int(current_shader_projection)] = new GLprogram(vsh, fsh);
mode = eMode(-1);
}
2018-11-17 16:59:57 +00:00
void switch_mode(eMode m, shader_projection sp) {
if(m == mode && current_shader_projection == sp) return;
2019-04-23 13:03:17 +00:00
reset_projection();
2018-02-11 01:19:49 +00:00
GLERR("pre_switch_mode");
2019-07-03 05:51:30 +00:00
WITHSHADER({
programs[m][int(sp)]->enable();
GLERR("after_enable");
}, {})
2018-02-09 00:46:14 +00:00
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");
2019-07-03 05:51:30 +00:00
WITHSHADER({
glEnableVertexAttribArray(aTexture);
GLERR("xsm");
}, {
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
GLERR("xsm");
})
2018-02-09 00:46:14 +00:00
}
if(oldflags & GF_TEXTURE) {
2018-02-11 01:19:49 +00:00
GLERR("xsm");
2019-07-03 05:51:30 +00:00
WITHSHADER({
glDisableVertexAttribArray(aTexture);
GLERR("xsm");
}, {
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
GLERR("xsm");
2019-07-12 21:16:54 +00:00
})
2018-02-09 00:46:14 +00:00
}
2018-02-10 17:21:19 +00:00
if(newflags & GF_VARCOLOR) {
2019-07-03 05:51:30 +00:00
WITHSHADER({
GLERR("xsm");
glEnableVertexAttribArray(aColor);
}, {
GLERR("xsm");
glEnableClientState(GL_COLOR_ARRAY);
GLERR("xsm");
2019-07-12 21:16:54 +00:00
})
2018-02-10 17:21:19 +00:00
}
if(oldflags & GF_VARCOLOR) {
2019-07-03 05:51:30 +00:00
WITHSHADER({
glDisableVertexAttribArray(aColor);
GLERR("xsm");
}, {
glDisableClientState(GL_COLOR_ARRAY);
GLERR("xsm");
2019-07-12 21:16:54 +00:00
})
2018-02-10 17:21:19 +00:00
}
2018-02-09 00:46:14 +00:00
if(newflags & GF_LIGHTFOG) {
2019-09-13 18:23:43 +00:00
#ifdef GLES_ONLY
#define glFogi glFogx
#endif
2019-07-03 05:51:30 +00:00
WITHSHADER({}, {
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);
glFogi(GL_FOG_MODE, GL_LINEAR);
glFogf(GL_FOG_START, 0);
2019-07-12 21:16:54 +00:00
})
2018-02-09 00:46:14 +00:00
}
if(oldflags & GF_LIGHTFOG) {
2019-07-12 21:16:54 +00:00
WITHSHADER({}, {glDisable(GL_FOG);})
2018-02-09 00:46:14 +00:00
}
2019-07-03 05:51:30 +00:00
WITHSHADER({
glUniform1f(current->uFogBase, 1); fogbase = 1;
2019-07-12 21:16:54 +00:00
}, {})
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;
2019-07-03 05:51:30 +00:00
WITHSHADER({
current_matrix[0][0] = -1e8; // invalid
current_modelview[0][0] = -1e8;
current_projection[0][0] = -1e8;
2019-07-12 21:16:54 +00:00
}, {})
id_modelview();
current_linewidth = -1;
/* if(current_depthwrite) glDepthMask(GL_TRUE);
else glDepthMask(GL_FALSE);
if(current_depthtest) glEnable(GL_DEPTH_TEST);
else glDisable(GL_DEPTH_TEST); */
2018-02-09 00:46:14 +00:00
}
EX void fog_max(ld fogmax, color_t fogcolor) {
2019-07-03 05:51:30 +00:00
WITHSHADER({
glUniform1f(current->uFog, 1 / fogmax);
GLfloat cols[4];
for(int i=0; i<4; i++) cols[i] = part(fogcolor, 3-i) / 255.0;
glUniform4f(current->uFogColor, cols[0], cols[1], cols[2], cols[3]);
}, {
glFogf(GL_FOG_END, fogmax);
2019-07-12 21:16:54 +00:00
})
2018-02-09 00:46:14 +00:00
}
EX void set_fogbase(ld _fogbase) {
2019-07-03 05:51:30 +00:00
WITHSHADER({
if(fogbase != _fogbase) {
fogbase = _fogbase;
glUniform1f(current->uFogBase, fogbase);
}
2019-07-12 21:16:54 +00:00
}, {})
2019-05-20 11:40:56 +00:00
}
EX void set_ualpha(ld alpha) {
2019-07-03 05:51:30 +00:00
WITHSHADER({
glUniform1f(current->uAlpha, alpha);
2019-07-12 21:16:54 +00:00
}, {})
}
2018-02-10 14:18:44 +00:00
void init() {
2019-07-03 05:51:30 +00:00
2018-02-10 14:18:44 +00:00
#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;
}
2019-07-03 05:51:30 +00:00
printf("CreateProgram = %p\n", __glewCreateProgram);
if(!__glewCreateProgram) noshaders = true;
2018-02-10 14:18:44 +00:00
}
#endif
#if CAP_SHADER
projection = id;
2019-07-03 05:51:30 +00:00
if(!noshaders)
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);
2019-05-12 12:35:14 +00:00
bool mps = !uses_mvp(sp);
bool band = among(sp, shader_projection::band, shader_projection::band3);
bool hp = among(sp, shader_projection::halfplane, shader_projection::halfplane3);
2019-02-25 03:04:26 +00:00
bool sh3 = (sp == shader_projection::standardH3);
2019-07-28 09:07:21 +00:00
bool ssol = (sp == shader_projection::standardSolv);
bool snil = (sp == shader_projection::standardNil);
2019-08-24 09:55:45 +00:00
bool ssl2 = (sp == shader_projection::standardSL2);
2019-02-25 03:04:26 +00:00
bool sr3 = (sp == shader_projection::standardR3);
2019-02-25 12:17:10 +00:00
bool ss30 = (sp == shader_projection::standardS30);
bool ss31 = (sp == shader_projection::standardS31);
bool ss32 = (sp == shader_projection::standardS32);
bool ss33 = (sp == shader_projection::standardS33);
2019-08-18 17:05:09 +00:00
bool seh2 = (sp == shader_projection::standardEH2);
2019-02-25 12:17:10 +00:00
bool ss3 = ss30 || ss31 || ss32 || ss33;
2019-02-25 03:04:26 +00:00
2019-08-24 09:55:45 +00:00
bool s3 = (sh3 || sr3 || ss3 || ssol || snil || seh2 || ssl2);
bool dim3 = s3 || among(sp, shader_projection::ball, shader_projection::halfplane3, shader_projection::band3);
bool dim2 = !dim3;
bool ball = (sp == shader_projection::ball);
2019-05-12 12:35:14 +00:00
bool flatten = (sp == shader_projection::flatten);
2018-11-17 16:59:57 +00:00
2019-09-13 15:45:31 +00:00
if(ssol && !CAP_SOLV) continue;
2019-09-13 01:47:55 +00:00
2018-11-17 16:59:57 +00:00
programs[i][j] = new GLprogram(stringbuilder(
1, "#define PI 3.14159265358979324\n",
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;",
2019-05-20 11:40:56 +00:00
1, "uniform mediump float uFogBase;",
1, "uniform mediump vec4 uFogColor;",
ball, "uniform mediump float uAlpha;",
2018-02-11 01:19:49 +00:00
!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, " }",
1, "float atanh(float x) { return (log(1.+x)-log(1.-x))/2.; }",
2019-02-22 20:01:01 +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, " }",
2019-07-28 09:07:21 +00:00
2019-09-13 15:45:31 +00:00
#if CAP_SOLV
ssol, solv::solshader,
#endif
snil, nilv::nilshader,
2019-08-24 09:55:45 +00:00
ssl2, slr::slshader,
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, "float fogx = clamp(1.0 + aPosition.z * uFog, 0.0, 1.0);",
lfog, "vColor = vColor * fogx + uFogColor * (1.0-fogx);",
2019-05-12 12:35:14 +00:00
!mps && !flatten, "gl_Position = uMVP * aPosition;",
!mps && flatten, "vec4 pos = aPosition; pos[3] = 1.0; gl_Position = uMVP * pos;",
ball, "vec4 t = uMV * aPosition; t /= (t[3] + uAlpha); ",
2019-05-12 12:35:14 +00:00
mps&&!(band||hp||s3||ball||flatten),"gl_Position = uP * (uMV * aPosition);",
mps&&flatten, "vec4 pos = aPosition; pos[3] = 1.0; gl_Position = uP * (uMV * pos);",
band||hp, "vec4 t = uMV * aPosition;",
(band||hp) && dim2, "float zlev = zlevel(t);",
(band||hp) && dim2, "t /= zlev;",
band&&dim3,"float r = sqrt(t.y*t.y+t.z*t.z); float ty = asinh(r);",
band&&dim2,"float ty = asinh(t.y);",
2018-11-17 16:59:57 +00:00
band, "float tx = asinh(t.x / cosh(ty));",
band, "ty = 2.0 * atan(tanh(ty/2.0));",
band&&dim2,"t[0] = tx; t[1] = ty; t[2] = 1.0; t[3] = 1.0;",
band&&dim3,"t[0] = tx; t[1] = ty*t.y/r; t[2] = ty*t.z/r; t[3] = 1.0;",
hp && dim2, "t.x /= t.z; t.y /= t.z; t.y = t.y + 1.0; ",
hp && dim2, "float rads = t.x * t.x + t.y * t.y; ",
hp && dim2, "t.x /= -rads; t.y /= -rads; t.z = 1.0; t[3] = 1.0;",
hp && dim3, "t.x /= (1.0+t.w); t.y /= (1.0+t.w); t.z /= (1.0+t.w); t.y = t.y + 1.0; ",
hp && dim3, "float rads = t.x * t.x + t.y * t.y + t.z * t.z; ",
hp && dim3, "t.x /= -rads; t.y /= -rads; t.z /= -rads; t[3] = 1.0;",
2019-02-22 20:01:01 +00:00
s3, "vec4 t = uMV * aPosition;",
ssol, "t = inverse_exp(t);",
2019-07-30 10:56:18 +00:00
ssol, "float d = sqrt(t[0] * t[0] + t[1] * t[1] + t[2] * t[2]);",
ssol, "float ad = (d == 0.) ? 0. : (d < 1.) ? min(atanh(d), 10.) : 10.; ",
ssol, "float m = ad / d / 11.; t[0] *= m; t[1] *= m; t[2] *= m; ",
snil, "t = inverse_exp(t);",
2019-08-24 09:55:45 +00:00
ssl2, "t = inverse_exp(t);",
2019-08-18 17:05:09 +00:00
seh2, "float z = log(t[2] * t[2] - t[0] * t[0] - t[1] * t[1]) / 2.;",
seh2, "float r = sqrt(t[0] * t[0] + t[1] * t[1]);",
seh2, "float t2 = t[2] / exp(z);",
seh2, "float d = t2 >= 1. ? acosh(t2) : 0.;",
seh2, "if(r != 0.) r = d / r;",
seh2, "t[0] = t[0] * r;",
seh2, "t[1] = t[1] * r;",
seh2, "t[2] = z;",
sh3, "float fogs = (uFogBase - acosh(t[3]) / uFog);",
2019-08-24 09:55:45 +00:00
sr3||snil||ssl2, "float fogs = (uFogBase - sqrt(t[0]*t[0] + t[1]*t[1] + t[2]*t[2]) / uFog);",
2019-07-30 10:56:18 +00:00
ssol, "float fogs = (uFogBase - ad / uFog);",
2019-08-18 17:05:09 +00:00
seh2, "float fogs = (uFogBase - sqrt(z*z+d*d) / uFog);",
2019-02-25 12:17:10 +00:00
ss30, "float fogs = (uFogBase - (6.284 - acos(t[3])) / uFog); t = -t; ",
ss31, "float fogs = (uFogBase - (6.284 - acos(t[3])) / uFog); t.xyz = -t.xyz; ",
ss32, "float fogs = (uFogBase - acos(t[3]) / uFog); t.w = -t.w; ", // 2pi
ss33, "float fogs = (uFogBase - acos(t[3]) / uFog); ",
s3, "vColor.xyz = vColor.xyz * fogs + uFogColor.xyz * (1.0-fogs);",
2019-08-18 17:05:09 +00:00
sh3 || sr3 || ssol || ball || seh2,"t[3] = 1.0;",
2019-02-22 20:01:01 +00:00
band || hp || s3 || ball,"gl_Position = uP * t;",
dim3 && !s3, "vColor.xyz = vColor.xyz * (0.5 - gl_Position.z / 2.0) + uFogColor.xyz * (0.5 + gl_Position.z / 2.0);",
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);
2019-07-03 05:51:30 +00:00
if(!noshaders) programs[gmColored][0]->enable();
2018-02-10 14:18:44 +00:00
#endif
#if !CAP_SHADER
2019-07-03 05:51:30 +00:00
switch_mode(gmColored, shader_projection::standard);
2018-02-10 14:18:44 +00:00
#endif
2019-07-03 05:51:30 +00:00
WITHSHADER(glEnableVertexAttribArray(aPosition);, glEnableClientState(GL_VERTEX_ARRAY);)
2018-02-10 17:21:19 +00:00
// #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
}
2019-08-09 20:07:03 +00:00
EX hyperpoint gltopoint(const glvertex& t) {
2018-02-11 18:08:17 +00:00
hyperpoint h;
h[0] = t[0]; h[1] = t[1]; h[2] = t[2];
if(SHDIM == 4 && MAXMDIM == 4) h[3] = t[3];
2018-02-11 18:08:17 +00:00
return h;
}
2019-08-09 20:07:03 +00:00
EX glvertex pointtogl(const hyperpoint& t) {
2018-02-11 18:08:17 +00:00
glvertex h;
h[0] = t[0]; h[1] = t[1]; h[2] = t[2];
2019-08-17 23:31:37 +00:00
if(SHDIM == 4) h[3] = (MDIM == 4) ? 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
EX void vertices(const vector<glvertex>& v, int vshift IS(0)) {
2018-02-11 18:08:17 +00:00
#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
2019-03-11 17:46:34 +00:00
if(current_vertices == &v[vshift]) return;
current_vertices = &v[vshift];
2019-07-03 05:51:30 +00:00
WITHSHADER(
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), &v[vshift]);,
glVertexPointer(SHDIM, GL_FLOAT, sizeof(glvertex), &v[0]);
)
2018-02-11 18:08:17 +00:00
#endif
}
EX void vertices_texture(const vector<glvertex>& v, const vector<glvertex>& t, int vshift IS(0), int tshift IS(0)) {
2018-02-12 15:21:42 +00:00
#if CAP_VERTEXBUFFER
int q = min(isize(v)-vshift, isize(t)-tshift);
vector<textured_vertex> tv(q);
for(int i=0; i<q; i++)
tv[i].coords = v[vshift+i],
tv[i].texture[0] = t[tshift+i][0],
tv[i].texture[1] = t[tshift+i][1];
prepare(tv);
2018-02-12 15:21:42 +00:00
#else
2019-03-11 17:46:34 +00:00
vertices(v, vshift);
2019-07-03 05:51:30 +00:00
WITHSHADER(
glVertexAttribPointer(aTexture, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), &t[tshift]);,
glTexCoordPointer(SHDIM, GL_FLOAT, 0, &t[tshift]);
)
2018-02-11 18:08:17 +00:00
#endif
}
2019-08-09 20:07:03 +00:00
EX void prepare(vector<colored_vertex>& v) {
2018-02-11 18:08:17 +00:00
#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];
2019-07-03 05:51:30 +00:00
WITHSHADER({
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(colored_vertex), &v[0].coords);
glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, sizeof(colored_vertex), &v[0].color);
}, {
glVertexPointer(SHDIM, GL_FLOAT, sizeof(colored_vertex), &v[0].coords);
glColorPointer(4, GL_FLOAT, sizeof(colored_vertex), &v[0].color);
})
2018-02-11 18:08:17 +00:00
#endif
}
2019-08-09 20:07:03 +00:00
EX void prepare(vector<textured_vertex>& v) {
2018-02-11 18:08:17 +00:00
#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];
2019-07-03 05:51:30 +00:00
WITHSHADER({
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);
}, {
glVertexPointer(SHDIM, GL_FLOAT, sizeof(textured_vertex), &v[0].coords);
glTexCoordPointer(2, GL_FLOAT, sizeof(textured_vertex), &v[0].texture);
2019-07-12 21:16:54 +00:00
})
2018-02-11 18:08:17 +00:00
#endif
// color2(col);
}
2019-08-09 20:07:03 +00:00
EX void prepare(vector<ct_vertex>& v) {
2018-02-11 18:08:17 +00:00
#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];
2019-07-03 05:51:30 +00:00
WITHSHADER({
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(ct_vertex), &v[0].coords);
glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, sizeof(ct_vertex), &v[0].color);
glVertexAttribPointer(aTexture, 2, GL_FLOAT, GL_FALSE, sizeof(ct_vertex), &v[0].texture);
}, {
glVertexPointer(SHDIM, GL_FLOAT, sizeof(ct_vertex), &v[0].coords);
glTexCoordPointer(2, GL_FLOAT, sizeof(ct_vertex), &v[0].texture);
glColorPointer(4, GL_FLOAT, sizeof(ct_vertex), &v[0].color);
})
2018-02-11 18:08:17 +00:00
#endif
}
EX void store_in_buffer(vector<glvertex>& v) {
2018-02-11 18:08:17 +00:00
#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
2019-08-09 20:07:03 +00:00
EX void set_depthtest(bool b) {
if(b != current_depthtest) {
current_depthtest = b;
if(b) glEnable(GL_DEPTH_TEST);
else glDisable(GL_DEPTH_TEST);
}
}
2019-05-13 11:39:43 +00:00
2019-08-09 20:07:03 +00:00
EX void set_depthwrite(bool b) {
2019-05-15 08:49:54 +00:00
if(b != current_depthwrite) { // <- this does not work ask intended for some reason...
2019-05-13 11:39:43 +00:00
current_depthwrite = b;
if(b) glDepthMask(GL_TRUE);
2019-05-13 13:24:06 +00:00
else glDepthMask(GL_FALSE);
2019-05-15 08:49:54 +00:00
}
2019-05-13 11:39:43 +00:00
}
2019-08-09 20:07:03 +00:00
EX void set_linewidth(ld lw) {
if(lw != current_linewidth) {
current_linewidth = lw;
glLineWidth(lw);
}
}
2019-08-09 20:07:03 +00:00
EX void switch_to_text(const vector<glvertex>& v, const vector<glvertex>& t) {
2019-07-03 03:02:00 +00:00
glhr::be_textured();
dynamicval<eModel> pm(pmodel, mdUnchanged);
if(!svg::in) current_display->set_all(0);
vertices_texture(v, t, 0, 0);
}
EX }
EX vector<glhr::textured_vertex> text_vertices;
EX void texture_vertices(GLfloat *f, int qty, int stride IS(2)) {
WITHSHADER(
glVertexAttribPointer(glhr::aTexture, stride, GL_FLOAT, GL_FALSE, stride * sizeof(GLfloat), f);,
glTexCoordPointer(stride, GL_FLOAT, 0, f);
)
}
EX void oldvertices(GLfloat *f, int qty) {
WITHSHADER(
glVertexAttribPointer(glhr::aPosition, SHDIM, GL_FLOAT, GL_FALSE, SHDIM * sizeof(GLfloat), f);,
glVertexPointer(SHDIM, GL_FLOAT, 0, f);
)
}
}
2019-07-03 05:51:30 +00:00
#define glMatrixMode DISABLED
#define glLoadIdentity DISABLED
#define glMultMatrixf DISABLED
#define glScalef DISABLED
#define glTranslatef DISABLED
#define glPushMatrix DISABLED
#define glPopMatrix DISABLED