1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-10-31 19:36:16 +00:00
hyperrogue/glhr.cpp

952 lines
26 KiB
C++
Raw Normal View History

2019-10-21 20:34:20 +00:00
// Hyperbolic Rogue -- low-level OpenGL routines
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
/** \file glhr.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 {
2020-11-22 11:59:56 +00:00
EX bool detailed_shader = false;
2020-07-03 12:42:33 +00:00
EX namespace glhr {
EX glvertex pointtogl(const hyperpoint& t) {
glvertex h;
h[0] = t[0]; h[1] = t[1]; h[2] = t[2];
if(SHDIM == 4) h[3] = (MDIM == 4) ? t[3] : 1;
return h;
}
EX hyperpoint gltopoint(const glvertex& t) {
hyperpoint h;
h[0] = t[0]; h[1] = t[1]; h[2] = t[2];
if(SHDIM == 4 && MAXMDIM == 4) h[3] = t[3];
return h;
}
#if CAP_SHADER
EX bool noshaders = false;
#endif
#if !CAP_SHADER
EX bool noshaders = true;
#endif
#if HDR
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
}
#endif
EX }
#if CAP_GL
2019-10-21 20:34:20 +00:00
#ifndef DEBUG_GL
#define DEBUG_GL 0
#endif
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
EX void glError(const char* GLcall, const char* file, const int line) {
GLenum errCode = glGetError();
if(errCode!=GL_NO_ERROR) {
2020-08-01 14:43:05 +00:00
println(hlog, format("OPENGL ERROR #%i: in file %s on line %i :: %s",errCode,file, line, GLcall));
2019-10-21 20:34:20 +00:00
}
}
2020-11-08 10:48:36 +00:00
#if HDR
struct glwrap {
const char* msg;
int line;
void act(const char *when);
glwrap(const char *m, int l) : msg(m), line(l) { act("before"); }
~glwrap() { act("after"); }
};
#define GLWRAP glwrap w##__line(__FILE__, __LINE__)
#endif
void glwrap::act(const char *when) {
GLenum errCode = glGetError();
if(errCode!=GL_NO_ERROR) {
println(hlog, format("GL error %i %s: %s:%i", errCode, when, msg, line));
}
}
2019-10-21 20:34:20 +00:00
#if HDR
#if CAP_SHADER && CAP_NOSHADER
#define WITHSHADER(x, y) if(glhr::noshaders) y else x
#else
#if CAP_NOSHADER
#define WITHSHADER(x, y) if(1) y
#else
#define WITHSHADER(x, y) if(1) x
#endif
#endif
#endif
EX namespace glhr {
EX string to_glsl(ld x) {
char buf[64];
snprintf(buf, 64, "float(%.10e)", x);
return buf;
}
2019-10-21 20:34:20 +00:00
#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]; }
array<float, 16>& as_stdarray() { return *(array<float, 16>*)this; }
2019-10-26 12:34:44 +00:00
const array<float, 16>& as_stdarray() const { return *(array<float, 16>*)this; }
2019-10-21 20:34:20 +00:00
};
struct colored_vertex {
glvertex coords;
glvec4 color;
2021-06-16 13:01:14 +00:00
colored_vertex() {}
2019-10-21 20:34:20 +00:00
colored_vertex(GLfloat x, GLfloat y, GLfloat r, GLfloat g, GLfloat b) {
coords[0] = x;
coords[1] = y;
coords[2] = 0;
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;
2020-12-24 21:19:26 +00:00
/* texture uses the 'z' for shading with POLY_SHADE_TEXTURE */
glvec3 texture;
2019-10-21 20:34:20 +00:00
};
struct ct_vertex {
glvertex coords;
glvec4 color;
glvec2 texture;
2020-09-13 13:38:41 +00:00
ct_vertex() {}
2019-10-21 20:34:20 +00:00
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
2022-06-10 16:45:15 +00:00
EX bool glew = false;
2019-10-21 20:34:20 +00:00
bool current_depthtest, current_depthwrite;
ld fogbase;
#if HDR
typedef const void *constvoidptr;
#endif
EX constvoidptr current_vertices, buffered_vertices;
EX ld current_linewidth;
2019-10-21 20:34:20 +00:00
GLuint buf_current, buf_buffered;
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");
}
2020-11-01 20:20:54 +00:00
EX glmatrix operator * (glmatrix m1, glmatrix m2) {
2019-10-21 20:34:20 +00:00
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}}};
EX 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;
}
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) {
glmatrix tmp;
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
tmp[i][j] = T[j][i];
return tmp;
}
2019-10-28 16:19:30 +00:00
EX glmatrix tmtogl_transpose3(const transmatrix& T) {
glmatrix tmp;
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
tmp[i][j] = T[j][i];
if(MDIM == 3)
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
if(i == 3 || j == 3) tmp[j][i] = 0;
return tmp;
}
2019-10-21 20:34:20 +00:00
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;
}
#if HDR
constexpr ld vnear_default = 1e-3;
constexpr ld vfar_default = 1e9;
#endif
EX glmatrix frustum(ld x, ld y, ld vnear IS(vnear_default), ld vfar IS(vfar_default)) {
2019-10-21 20:34:20 +00:00
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);
}
EX 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 **
// /* shaders */
glmatrix projection;
EX void new_projection() {
WITHSHADER({
projection = id;
}, {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
return;
})
}
EX void projection_multiply(const glmatrix& m) {
WITHSHADER({
projection = m * projection;
}, {
glMatrixMode(GL_PROJECTION);
glMultMatrixf(m.as_array());
})
}
EX void init();
#if HDR
2019-10-21 22:36:44 +00:00
struct GLprogram {
2019-10-21 20:34:20 +00:00
GLuint _program;
GLuint vertShader, fragShader;
2020-08-01 11:59:53 +00:00
GLint uFog, uFogColor, uColor, tTexture, tInvExpTable, tAirMap, uMV, uProjection, uAlpha, uFogBase, uPP;
GLint uPRECX, uPRECY, uPRECZ, uIndexSL, uIterations, uLevelLines, uSV, uRadarTransform;
GLint uRotSin, uRotCos, uRotNil;
2020-12-28 21:00:56 +00:00
GLint uDepthScaling, uCamera, uDepth;
2019-10-21 20:34:20 +00:00
flagtype shader_flags;
string _vsh, _fsh;
GLprogram(string vsh, string fsh);
~GLprogram();
};
#endif
EX shared_ptr<GLprogram> current_glprogram = nullptr;
2019-10-28 16:18:59 +00:00
EX bool debug_gl;
2019-10-21 20:34:20 +00:00
EX int compileShader(int type, const string& s) {
GLint status;
2019-10-28 16:18:59 +00:00
if(debug_gl) {
println(hlog, "===\n");
int lineno = 1;
string cline = "";
for(char c: s+"\n") {
if(c == '\n') println(hlog, format("%4d : ", lineno), cline), lineno++, cline = "";
else cline += c;
}
println(hlog, "===");
}
2019-10-21 20:34:20 +00:00
GLint shader = glCreateShader(type);
const char *ss = s.c_str();
glShaderSource(shader, 1, &ss, NULL);
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());
string s = log.data();
2019-10-21 20:34:20 +00:00
if(logLength > 0)
println(hlog, "compiler log (", logLength, "): \n", s);
if(debug_gl) {
println(hlog, "failed to compile shader -- exit called");
exit(1);
}
2019-10-21 20:34:20 +00:00
}
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == 0) {
glDeleteShader(shader);
printf("failed to compile shader\n");
println(hlog, s);
shader = 0;
}
return shader;
}
GLprogram::GLprogram(string vsh, string fsh) {
if(noshaders || !vid.usingGL) {
2019-10-21 20:34:20 +00:00
uFog = -1;
uProjection = -1;
uPP = -1;
uMV = -1;
uPRECX = -1;
uIterations = -1;
uAlpha = -1;
2019-11-03 12:36:06 +00:00
uLevelLines = -1;
uFogColor = -1;
2020-12-28 21:00:56 +00:00
uDepthScaling = uCamera = uDepth = -1;
2020-11-07 18:26:11 +00:00
uColor = tTexture = tInvExpTable = tAirMap = -1;
uFogBase = -1;
uPRECX = uPRECY = uPRECZ = uIndexSL = -1;
uSV = uRadarTransform = -1;
uRotCos = -1;
uRotSin = -1;
uRotNil = -1;
2019-11-03 12:36:06 +00:00
return;
2019-10-21 20:34:20 +00:00
}
_vsh = vsh; _fsh = fsh;
_program = glCreateProgram();
add_fixed_functions(vsh);
add_fixed_functions(fsh);
// printf("creating program %d\n", _program);
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);
glBindAttribLocation(_program, aPosition, "aPosition");
glBindAttribLocation(_program, aTexture, "aTexture");
glBindAttribLocation(_program, aColor, "aColor");
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());
if(logLength > 0)
printf("linking log (%d): %s\n", logLength, log.data());
}
glGetProgramiv(_program, GL_LINK_STATUS, &status);
if (status == 0) {
printf("failed to link shader\n");
exit(1);
}
uMV = glGetUniformLocation(_program, "uMV");
uProjection = glGetUniformLocation(_program, "uP");
uPP = glGetUniformLocation(_program, "uPP");
uFog = glGetUniformLocation(_program, "uFog");
uFogColor = glGetUniformLocation(_program, "uFogColor");
uFogBase = glGetUniformLocation(_program, "uFogBase");
uAlpha = glGetUniformLocation(_program, "uAlpha");
uColor = glGetUniformLocation(_program, "uColor");
tTexture = glGetUniformLocation(_program, "tTexture");
tInvExpTable = glGetUniformLocation(_program, "tInvExpTable");
2020-08-01 11:59:53 +00:00
tAirMap = glGetUniformLocation(_program, "tAirMap");
2019-10-21 20:34:20 +00:00
2020-12-28 21:00:56 +00:00
uDepth = glGetUniformLocation(_program, "uDepth");
uDepthScaling = glGetUniformLocation(_program, "uDepthScaling");
uCamera = glGetUniformLocation(_program, "uCamera");
2019-10-21 20:34:20 +00:00
uPRECX = glGetUniformLocation(_program, "PRECX");
uPRECY = glGetUniformLocation(_program, "PRECY");
uPRECZ = glGetUniformLocation(_program, "PRECZ");
uIndexSL = glGetUniformLocation(_program, "uIndexSL");
uSV = glGetUniformLocation(_program, "uSV");
2019-10-21 20:34:20 +00:00
uIterations = glGetUniformLocation(_program, "uIterations");
2019-11-03 12:36:06 +00:00
uLevelLines = glGetUniformLocation(_program, "uLevelLines");
2020-08-01 11:59:53 +00:00
uRadarTransform = glGetUniformLocation(_program, "uRadarTransform");
uRotCos = glGetUniformLocation(_program, "uRotCos");
uRotSin = glGetUniformLocation(_program, "uRotSin");
uRotNil = glGetUniformLocation(_program, "uRotNil");
2019-10-21 20:34:20 +00:00
}
GLprogram::~GLprogram() {
glDeleteProgram(_program);
if(vertShader) glDeleteShader(vertShader), vertShader = 0;
if(fragShader) glDeleteShader(fragShader), fragShader = 0;
}
EX void set_index_sl(ld x) {
glUniform1f(glhr::current_glprogram->uIndexSL, x);
}
EX void set_sv(ld x) {
glUniform1f(glhr::current_glprogram->uSV, x);
}
2019-10-21 20:34:20 +00:00
EX void set_sl_iterations(int steps) {
glUniform1i(glhr::current_glprogram->uIterations, steps);
}
EX void set_solv_prec(int x, int y, int z) {
glUniform1i(glhr::current_glprogram->tInvExpTable, INVERSE_EXP_BINDING);
glUniform1f(glhr::current_glprogram->uPRECX, x);
glUniform1f(glhr::current_glprogram->uPRECY, y);
glUniform1f(glhr::current_glprogram->uPRECZ, z);
}
EX glmatrix current_matrix, current_modelview, current_projection;
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;
}
bool operator != (const glmatrix& m1, const glmatrix& m2) {
return !(m1 == m2);
}
EX glmatrix eyeshift;
EX bool using_eyeshift;
EX void set_modelview(const glmatrix& modelview) {
#if CAP_NOSHADER
if(noshaders) {
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(modelview.as_array());
return;
}
#endif
auto& cur = current_glprogram;
if(!cur) return;
2020-11-22 11:59:56 +00:00
if(detailed_shader) println(hlog, "\n*** ENABLING MODELVIEW:\n", modelview.as_stdarray());
if(detailed_shader) println(hlog, "\n*** ENABLING PROJECTION:\n", projection.as_stdarray());
2019-10-21 20:34:20 +00:00
if(using_eyeshift) {
glmatrix mvp = modelview * eyeshift;
#if MINIMIZE_GL_CALLS
if(mvp == current_matrix) return;
current_matrix = mvp;
#endif
glUniformMatrix4fv(cur->uMV, 1, 0, mvp.as_array());
}
else if(modelview != current_modelview) {
current_modelview = modelview;
glUniformMatrix4fv(cur->uMV, 1, 0, modelview.as_array());
}
if(projection != current_projection) {
current_projection = projection;
glUniformMatrix4fv(cur->uProjection, 1, 0, projection.as_array());
}
}
EX void id_modelview() {
#if CAP_NOSHADER
if(noshaders) {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
return;
}
#endif
set_modelview(id);
}
EX array<GLfloat, 4> acolor(color_t color, ld scale IS(1)) {
array<GLfloat, 4> cols;
for(int i=0; i<4; i++)
cols[i] = part(color, 3-i) / 255.0 * scale;
return cols;
}
EX void color2(color_t color, ld scale IS(1)) {
auto cols = acolor(color, scale);
WITHSHADER({
if(!current_glprogram) return;
glUniform4f(current_glprogram->uColor, cols[0], cols[1], cols[2], cols[3]);
}, {
glColor4f(cols[0], cols[1], cols[2], cols[3]);
}
)
}
EX void colorClear(color_t color) {
glClearColor(part(color, 3) / 255.0, part(color, 2) / 255.0, part(color, 1) / 255.0, part(color, 0) / 255.0);
}
2019-10-21 22:36:44 +00:00
EX void full_enable(shared_ptr<GLprogram> p) {
2019-10-21 20:34:20 +00:00
auto& cur = current_glprogram;
flagtype oldflags = cur ? cur->shader_flags : 0;
2019-10-21 22:36:44 +00:00
if(p == cur) return;
2020-03-05 21:35:06 +00:00
if(!vid.usingGL) return;
2019-10-21 22:36:44 +00:00
cur = p;
2019-10-21 20:34:20 +00:00
GLERR("pre_switch_mode");
WITHSHADER({
2020-11-22 11:59:56 +00:00
if(detailed_shader) println(hlog, "\n*** ENABLING VERTEX SHADER:\n", cur->_vsh, "\n\nENABLING FRAGMENT SHADER:\n", cur->_fsh, "\n");
2019-10-21 20:34:20 +00:00
glUseProgram(cur->_program);
GLERR("after_enable");
}, {
});
reset_projection();
flagtype newflags = cur->shader_flags;
tie(oldflags, newflags) = make_pair(oldflags & ~newflags, newflags & ~oldflags);
if(newflags & GF_TEXTURE) {
GLERR("xsm");
WITHSHADER({
glEnableVertexAttribArray(aTexture);
GLERR("xsm");
}, {
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
GLERR("xsm");
})
}
if(oldflags & GF_TEXTURE) {
GLERR("xsm");
WITHSHADER({
glDisableVertexAttribArray(aTexture);
GLERR("xsm");
}, {
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
GLERR("xsm");
})
}
if(newflags & GF_VARCOLOR) {
WITHSHADER({
GLERR("xsm");
glEnableVertexAttribArray(aColor);
}, {
GLERR("xsm");
glEnableClientState(GL_COLOR_ARRAY);
GLERR("xsm");
})
}
if(oldflags & GF_VARCOLOR) {
WITHSHADER({
glDisableVertexAttribArray(aColor);
GLERR("xsm");
}, {
glDisableClientState(GL_COLOR_ARRAY);
GLERR("xsm");
})
}
if(newflags & GF_LIGHTFOG) {
#ifdef GLES_ONLY
#define glFogi glFogx
#endif
WITHSHADER({}, {
/*GLfloat light_ambient[] = { 3.5, 3.5, 3.5, 1.0 };
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);
glEnable(GL_LIGHT0); */
glEnable(GL_FOG);
glFogi(GL_FOG_MODE, GL_LINEAR);
glFogf(GL_FOG_START, 0);
})
}
if(oldflags & GF_LIGHTFOG) {
WITHSHADER({}, {glDisable(GL_FOG);})
}
WITHSHADER({
glUniform1f(cur->uFogBase, 1); fogbase = 1;
}, {})
GLERR("after_switch_mode");
current_vertices = NULL;
WITHSHADER({
current_matrix[0][0] = -1e8; // invalid
current_modelview[0][0] = -1e8;
current_projection[0][0] = -1e8;
}, {})
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); */
}
EX void fog_max(ld fogmax, color_t fogcolor) {
WITHSHADER({
2019-11-03 12:36:06 +00:00
if(current_glprogram->uFog != -1)
glUniform1f(current_glprogram->uFog, 1 / fogmax);
2019-10-21 20:34:20 +00:00
2019-11-03 12:36:06 +00:00
if(current_glprogram->uFogColor != -1) {
GLfloat cols[4];
for(int i=0; i<4; i++) cols[i] = part(fogcolor, 3-i) / 255.0;
glUniform4f(current_glprogram->uFogColor, cols[0], cols[1], cols[2], cols[3]);
}
2019-10-21 20:34:20 +00:00
}, {
glFogf(GL_FOG_END, fogmax);
})
}
EX void set_fogbase(ld _fogbase) {
WITHSHADER({
if(fogbase != _fogbase) {
fogbase = _fogbase;
glUniform1f(current_glprogram->uFogBase, fogbase);
}
}, {})
}
EX void set_ualpha(ld alpha) {
WITHSHADER({
glUniform1f(current_glprogram->uAlpha, alpha);
}, {})
}
void init() {
#if CAP_GLEW
if(!glew) {
glew = true;
2022-06-10 16:45:15 +00:00
glewExperimental = GL_TRUE;
2019-10-21 20:34:20 +00:00
printf("Initializing GLEW\n");
GLenum err = glewInit();
if (GLEW_OK != err) {
addMessage("Failed to initialize GLEW");
printf("Failed to initialize GLEW\n");
return;
}
printf("CreateProgram = %p\n", reinterpret_cast<void*>(__glewCreateProgram));
2019-10-21 20:34:20 +00:00
if(!__glewCreateProgram) noshaders = true;
}
#endif
projection = id;
WITHSHADER(glEnableVertexAttribArray(aPosition);, glEnableClientState(GL_VERTEX_ARRAY);)
2019-10-26 15:02:54 +00:00
GLERR("aPosition");
2019-10-21 20:34:20 +00:00
// #endif
glDisableVertexAttribArray(aTexture);
glDisableVertexAttribArray(aColor);
2019-10-21 20:34:20 +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
}
#if CAP_VERTEXBUFFER
template<class T> void bindbuffer(T& v) {
if(current_vertices == buffered_vertices || current_vertices == nullptr) {
glBindBuffer(GL_ARRAY_BUFFER, buf_current);
}
current_vertices = &v[0];
glBufferData(GL_ARRAY_BUFFER, isize(v) * sizeof(v[0]), &v[0], GL_DYNAMIC_DRAW);
}
#define PTR(attrib, q, field) \
glVertexAttribPointer(attrib, q, GL_FLOAT, GL_FALSE, sizeof(v[0]), (void*) ((char*) &v[0].field - (char*) &v[0]));
2020-10-15 14:37:43 +00:00
EX void bindbuffer_vertex(vector<glvertex>& v) {
bindbuffer(v);
}
2019-10-21 20:34:20 +00:00
#endif
EX void vertices(const vector<glvertex>& v, int vshift IS(0)) {
#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-11-03 13:19:37 +00:00
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), 0);
2019-10-21 20:34:20 +00:00
return;
}
bindbuffer(v);
2019-11-03 13:19:37 +00:00
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), 0);
2019-10-21 20:34:20 +00:00
#else
if(current_vertices == &v[vshift]) return;
current_vertices = &v[vshift];
WITHSHADER(
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), &v[vshift]);,
glVertexPointer(SHDIM, GL_FLOAT, sizeof(glvertex), &v[0]);
)
#endif
}
EX void vertices_texture(const vector<glvertex>& v, const vector<glvertex>& t, int vshift IS(0), int tshift IS(0)) {
#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],
tv[i].texture[2] = t[tshift+i][2];
2019-10-21 20:34:20 +00:00
prepare(tv);
#else
vertices(v, vshift);
WITHSHADER(
glVertexAttribPointer(aTexture, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), &t[tshift]);,
glTexCoordPointer(SHDIM, GL_FLOAT, 0, &t[tshift]);
)
#endif
}
2020-09-11 09:08:27 +00:00
EX void vertices_texture_color(const vector<glvertex>& v, const vector<glvertex>& t, const vector<glvertex>& c, int vshift IS(0), int tshift IS(0)) {
#if CAP_VERTEXBUFFER
int q = min(isize(v)-vshift, isize(t)-tshift);
vector<ct_vertex> tv(q);
2020-09-13 12:22:13 +00:00
for(int i=0; i<q; i++) {
2020-09-11 09:08:27 +00:00
tv[i].coords = v[vshift+i],
tv[i].texture[0] = t[tshift+i][0],
2020-09-13 12:22:13 +00:00
tv[i].texture[1] = t[tshift+i][1];
for(int i=0; i<SHDIM; i++)
tv[i].color[i] = c[tshift+i][i];
if(SHDIM == 3) tv[i].color[3] = 1;
}
2020-09-11 09:08:27 +00:00
prepare(tv);
#else
vertices(v, vshift);
WITHSHADER({
glVertexAttribPointer(aTexture, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), &t[tshift]);
glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, sizeof(glvertex), &c[tshift]);
}, {
glTexCoordPointer(SHDIM, GL_FLOAT, 0, &t[tshift]);
glColorPointer(4, GL_FLOAT, sizeof(colored_vertex), &c[0]);
}
)
#endif
}
2019-10-21 20:34:20 +00:00
EX void prepare(vector<colored_vertex>& v) {
#if CAP_VERTEXBUFFER
bindbuffer(v);
2019-11-03 13:19:37 +00:00
PTR(aPosition, SHDIM, coords);
PTR(aColor, 4, color);
2019-10-21 20:34:20 +00:00
#else
if(current_vertices == &v[0]) return;
current_vertices = &v[0];
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);
})
#endif
}
EX void prepare(vector<textured_vertex>& v) {
#if CAP_VERTEXBUFFER
bindbuffer(v);
2019-11-03 13:19:37 +00:00
PTR(aPosition, SHDIM, coords);
PTR(aTexture, 3, texture);
2019-10-21 20:34:20 +00:00
#else
if(current_vertices == &v[0]) return;
current_vertices = &v[0];
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(3, GL_FLOAT, sizeof(textured_vertex), &v[0].texture);
2019-10-21 20:34:20 +00:00
})
#endif
// color2(col);
}
EX void prepare(vector<ct_vertex>& v) {
#if CAP_VERTEXBUFFER
bindbuffer(v);
2019-11-03 13:19:37 +00:00
PTR(aPosition, SHDIM, coords);
PTR(aColor, 4, color);
PTR(aTexture, 2, texture);
2019-10-21 20:34:20 +00:00
#else
if(current_vertices == &v[0]) return;
current_vertices = &v[0];
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);
})
#endif
}
EX void store_in_buffer(vector<glvertex>& v) {
#if CAP_VERTEXBUFFER
if(!buf_buffered) {
printf("no buffer yet\n");
return;
}
printf("storing %d in buffer: %p\n", isize(v), &v[0]);
current_vertices = buffered_vertices = &v[0];
glBindBuffer(GL_ARRAY_BUFFER, buf_buffered);
2019-11-03 13:19:37 +00:00
glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), 0);
2019-10-21 20:34:20 +00:00
glBufferData(GL_ARRAY_BUFFER, isize(v) * sizeof(glvertex), &v[0], GL_STATIC_DRAW);
printf("Stored.\n");
#endif
}
EX void set_depthtest(bool b) {
if(b != current_depthtest) {
current_depthtest = b;
if(b) glEnable(GL_DEPTH_TEST);
else glDisable(GL_DEPTH_TEST);
}
}
EX void set_depthwrite(bool b) {
if(b != current_depthwrite) { // <- this does not work ask intended for some reason...
current_depthwrite = b;
if(b) glDepthMask(GL_TRUE);
else glDepthMask(GL_FALSE);
}
}
EX void set_linewidth(ld lw) {
if(lw != current_linewidth) {
current_linewidth = lw;
glLineWidth(lw);
}
}
EX void switch_to_text(const vector<glvertex>& v, const vector<glvertex>& t) {
current_display->next_shader_flags = GF_TEXTURE;
dynamicval<eModel> pm(pmodel, mdPixel);
if(!svg::in) current_display->set_all(0, 0);
2019-10-21 20:34:20 +00:00
vertices_texture(v, t, 0, 0);
}
EX void be_nontextured() { current_display->next_shader_flags = 0; }
EX void be_textured() { current_display->next_shader_flags = GF_TEXTURE; }
2020-09-11 09:08:27 +00:00
EX void be_color_textured() { current_display->next_shader_flags = GF_TEXTURE | GF_VARCOLOR; }
2019-10-21 20:34:20 +00:00
EX }
EX vector<glhr::textured_vertex> text_vertices;
EX void texture_vertices(GLfloat *f, int qty, int stride IS(2)) {
WITHSHADER(
glVertexAttribPointer(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(aPosition, SHDIM, GL_FLOAT, GL_FALSE, SHDIM * sizeof(GLfloat), f);,
glVertexPointer(SHDIM, GL_FLOAT, 0, f);
)
}
2020-07-03 12:42:33 +00:00
#endif
2019-10-21 20:34:20 +00:00
}
#define glMatrixMode DISABLED
#define glLoadIdentity DISABLED
#define glMultMatrixf DISABLED
#define glScalef DISABLED
#define glTranslatef DISABLED
#define glPushMatrix DISABLED
#define glPopMatrix DISABLED