nuclear@11: /* nuclear@11: SaneGL - a small library to bring back sanity to OpenGL ES 2.x nuclear@11: Copyright (C) 2011-2013 John Tsiombikas nuclear@11: nuclear@11: This program is free software: you can redistribute it and/or modify nuclear@11: it under the terms of the GNU General Public License as published by nuclear@11: the Free Software Foundation, either version 3 of the License, or nuclear@11: (at your option) any later version. nuclear@11: nuclear@11: This program is distributed in the hope that it will be useful, nuclear@11: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@11: GNU General Public License for more details. nuclear@11: nuclear@11: You should have received a copy of the GNU General Public License nuclear@11: along with this program. If not, see . nuclear@11: */ nuclear@11: nuclear@11: #include nuclear@11: #include nuclear@11: #include nuclear@11: #include nuclear@11: #include nuclear@11: #include "sanegl.h" nuclear@11: nuclear@11: #define MMODE_IDX(x) ((x) - GL_MODELVIEW) nuclear@11: #define MAT_STACK_SIZE 32 nuclear@11: #define MAT_IDENT {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1} nuclear@11: nuclear@11: #define MAX_VERTS 512 nuclear@11: nuclear@11: static void gl_draw_immediate(void); nuclear@11: static void m4_transpose(double *res, double *m); nuclear@11: static double m4_determinant(double *m); nuclear@11: static void m4_adjoint(double *res, double *m); nuclear@11: static void m4_inverse(double *res, double *m); nuclear@11: nuclear@11: nuclear@11: typedef struct { float x, y; } vec2_t; nuclear@11: typedef struct { float x, y, z; } vec3_t; nuclear@11: typedef struct { float x, y, z, w; } vec4_t; nuclear@11: nuclear@11: static int mm_idx = 0; nuclear@11: static float mat_stack[3][MAT_STACK_SIZE][16] = {{MAT_IDENT}, {MAT_IDENT}, {MAT_IDENT}}; nuclear@11: static int stack_top[3]; nuclear@11: static float mat_mvp[16]; nuclear@11: static int mvp_valid; nuclear@11: static int prim = -1; nuclear@11: nuclear@11: static vec3_t cur_normal; nuclear@11: static vec4_t cur_color, cur_attrib; nuclear@11: static vec2_t cur_texcoord; nuclear@11: nuclear@11: static vec4_t *vert_arr, *col_arr, *attr_arr; nuclear@11: static vec3_t *norm_arr; nuclear@11: static vec2_t *texc_arr; nuclear@11: /*static unsigned int vbuf, cbuf, nbuf, tbuf, abuf;*/ nuclear@11: static int vloc, nloc, cloc, tloc, aloc = -1; nuclear@11: nuclear@11: static int num_verts, vert_calls; nuclear@11: static int cur_prog; nuclear@11: nuclear@11: #ifdef GLDEF nuclear@11: #undef glEnable nuclear@11: #undef glDisable nuclear@11: #endif nuclear@11: nuclear@11: void gl_enable(int state) nuclear@11: { nuclear@11: switch(state) { nuclear@11: case GL_TEXTURE_2D: nuclear@11: break; nuclear@11: nuclear@11: default: nuclear@11: glEnable(state); nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: void gl_disable(int state) nuclear@11: { nuclear@11: switch(state) { nuclear@11: case GL_TEXTURE_2D: nuclear@11: glBindTexture(state, 0); nuclear@11: break; nuclear@11: nuclear@11: default: nuclear@11: glDisable(state); nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: void gl_matrix_mode(int mm) nuclear@11: { nuclear@11: mm_idx = MMODE_IDX(mm); nuclear@11: } nuclear@11: nuclear@11: void gl_push_matrix(void) nuclear@11: { nuclear@11: int top = stack_top[mm_idx]; nuclear@11: nuclear@11: memcpy(mat_stack[mm_idx][top + 1], mat_stack[mm_idx][top], 16 * sizeof(float)); nuclear@11: stack_top[mm_idx]++; nuclear@11: mvp_valid = 0; nuclear@11: } nuclear@11: nuclear@11: void gl_pop_matrix(void) nuclear@11: { nuclear@11: stack_top[mm_idx]--; nuclear@11: mvp_valid = 0; nuclear@11: } nuclear@11: nuclear@11: void gl_load_identity(void) nuclear@11: { nuclear@11: static const float idmat[] = MAT_IDENT; nuclear@11: int top = stack_top[mm_idx]; nuclear@11: float *mat = mat_stack[mm_idx][top]; nuclear@11: nuclear@11: memcpy(mat, idmat, sizeof idmat); nuclear@11: mvp_valid = 0; nuclear@11: } nuclear@11: nuclear@11: void gl_load_matrixf(const float *m) nuclear@11: { nuclear@11: int top = stack_top[mm_idx]; nuclear@11: float *mat = mat_stack[mm_idx][top]; nuclear@11: nuclear@11: memcpy(mat, m, 16 * sizeof *mat); nuclear@11: mvp_valid = 0; nuclear@11: } nuclear@11: nuclear@11: void gl_load_matrixd(const double *m) nuclear@11: { nuclear@11: int i; nuclear@11: float mf[16]; nuclear@11: nuclear@11: for(i=0; i<16; i++) { nuclear@11: mf[i] = (float)m[i]; nuclear@11: } nuclear@11: gl_load_matrixf(mf); nuclear@11: } nuclear@11: nuclear@11: #define M(i, j) ((i << 2) + j) nuclear@11: nuclear@11: void gl_mult_matrixf(const float *m2) nuclear@11: { nuclear@11: int i, j; nuclear@11: int top = stack_top[mm_idx]; nuclear@11: float *m1 = mat_stack[mm_idx][top]; nuclear@11: float res[16]; nuclear@11: nuclear@11: for(i=0; i<4; i++) { nuclear@11: for(j=0; j<4; j++) { nuclear@11: res[M(i,j)] = m2[M(i,0)] * m1[M(0,j)] + nuclear@11: m2[M(i,1)] * m1[M(1,j)] + nuclear@11: m2[M(i,2)] * m1[M(2,j)] + nuclear@11: m2[M(i,3)] * m1[M(3,j)]; nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: memcpy(m1, res, sizeof res); nuclear@11: mvp_valid = 0; nuclear@11: } nuclear@11: nuclear@11: void gl_mult_matrixd(const double *m) nuclear@11: { nuclear@11: int i; nuclear@11: float mf[16]; nuclear@11: nuclear@11: for(i=0; i<16; i++) { nuclear@11: mf[i] = (float)m[i]; nuclear@11: } nuclear@11: gl_mult_matrixf(mf); nuclear@11: } nuclear@11: nuclear@11: void gl_translatef(float x, float y, float z) nuclear@11: { nuclear@11: float mat[] = MAT_IDENT; nuclear@11: nuclear@11: mat[12] = x; nuclear@11: mat[13] = y; nuclear@11: mat[14] = z; nuclear@11: nuclear@11: gl_mult_matrixf(mat); nuclear@11: } nuclear@11: nuclear@11: void gl_rotatef(float angle, float x, float y, float z) nuclear@11: { nuclear@11: float mat[] = MAT_IDENT; nuclear@11: nuclear@11: float angle_rad = M_PI * angle / 180.0; nuclear@11: float sina = sin(angle_rad); nuclear@11: float cosa = cos(angle_rad); nuclear@11: float one_minus_cosa = 1.0 - cosa; nuclear@11: float nxsq = x * x; nuclear@11: float nysq = y * y; nuclear@11: float nzsq = z * z; nuclear@11: nuclear@11: mat[0] = nxsq + (1.0 - nxsq) * cosa; nuclear@11: mat[4] = x * y * one_minus_cosa - z * sina; nuclear@11: mat[8] = x * z * one_minus_cosa + y * sina; nuclear@11: mat[1] = x * y * one_minus_cosa + z * sina; nuclear@11: mat[5] = nysq + (1.0 - nysq) * cosa; nuclear@11: mat[9] = y * z * one_minus_cosa - x * sina; nuclear@11: mat[2] = x * z * one_minus_cosa - y * sina; nuclear@11: mat[6] = y * z * one_minus_cosa + x * sina; nuclear@11: mat[10] = nzsq + (1.0 - nzsq) * cosa; nuclear@11: nuclear@11: gl_mult_matrixf(mat); nuclear@11: } nuclear@11: nuclear@11: void gl_scalef(float x, float y, float z) nuclear@11: { nuclear@11: float mat[] = MAT_IDENT; nuclear@11: nuclear@11: mat[0] = x; nuclear@11: mat[5] = y; nuclear@11: mat[10] = z; nuclear@11: nuclear@11: gl_mult_matrixf(mat); nuclear@11: } nuclear@11: nuclear@11: void gl_ortho(float left, float right, float bottom, float top, float near, float far) nuclear@11: { nuclear@11: float mat[] = MAT_IDENT; nuclear@11: nuclear@11: float dx = right - left; nuclear@11: float dy = top - bottom; nuclear@11: float dz = far - near; nuclear@11: nuclear@11: float tx = -(right + left) / dx; nuclear@11: float ty = -(top + bottom) / dy; nuclear@11: float tz = -(far + near) / dz; nuclear@11: nuclear@11: float sx = 2.0 / dx; nuclear@11: float sy = 2.0 / dy; nuclear@11: float sz = -2.0 / dz; nuclear@11: nuclear@11: mat[0] = sx; nuclear@11: mat[5] = sy; nuclear@11: mat[10] = sz; nuclear@11: mat[12] = tx; nuclear@11: mat[13] = ty; nuclear@11: mat[14] = tz; nuclear@11: nuclear@11: gl_mult_matrixf(mat); nuclear@11: } nuclear@11: nuclear@11: void gl_frustum(float left, float right, float bottom, float top, float near, float far) nuclear@11: { nuclear@11: float mat[] = MAT_IDENT; nuclear@11: nuclear@11: float dx = right - left; nuclear@11: float dy = top - bottom; nuclear@11: float dz = far - near; nuclear@11: nuclear@11: float a = (right + left) / dx; nuclear@11: float b = (top + bottom) / dy; nuclear@11: float c = -(far + near) / dz; nuclear@11: float d = -2.0 * far * near / dz; nuclear@11: nuclear@11: mat[0] = 2.0 * near / dx; nuclear@11: mat[5] = 2.0 * near / dy; nuclear@11: mat[8] = a; nuclear@11: mat[9] = b; nuclear@11: mat[10] = c; nuclear@11: mat[11] = -1.0; nuclear@11: mat[14] = d; nuclear@11: mat[15] = 0.0; nuclear@11: nuclear@11: gl_mult_matrixf(mat); nuclear@11: } nuclear@11: nuclear@11: void glu_perspective(float vfov, float aspect, float near, float far) nuclear@11: { nuclear@11: float vfov_rad = M_PI * vfov / 180.0; nuclear@11: float x = near * tan(vfov_rad / 2.0); nuclear@11: gl_frustum(-aspect * x, aspect * x, -x, x, near, far); nuclear@11: } nuclear@11: nuclear@11: int glu_un_project(double winx, double winy, double winz, nuclear@11: const double *model, const double *proj, const int *viewp, nuclear@11: double *objx, double *objy, double *objz) nuclear@11: { nuclear@11: double mvp[16], inv_mvp[16]; nuclear@11: nuclear@11: double ndcx = 2.0 * (winx - viewp[0]) / viewp[2] - 1.0; nuclear@11: double ndcy = 2.0 * (winy - viewp[1]) / viewp[3] - 1.0; nuclear@11: double ndcz = 2.0 * winz - 1.0; nuclear@11: nuclear@11: // calculate modelviewprojection nuclear@11: gl_matrix_mode(GL_MODELVIEW); nuclear@11: gl_push_matrix(); nuclear@11: gl_load_matrixd(proj); nuclear@11: gl_mult_matrixd(model); nuclear@11: gl_get_doublev(GL_MODELVIEW_MATRIX, mvp); nuclear@11: gl_pop_matrix(); nuclear@11: nuclear@11: // invert modelviewprojection nuclear@11: m4_inverse(inv_mvp, mvp); nuclear@11: nuclear@11: // transform ndc by modelview -> obj nuclear@11: /**objx = inv_mvp[0] * ndcx + inv_mvp[4] * ndcy + inv_mvp[8] * ndcz + inv_mvp[12]; nuclear@11: *objy = inv_mvp[1] * ndcx + inv_mvp[5] * ndcy + inv_mvp[9] * ndcz + inv_mvp[13]; nuclear@11: *objz = inv_mvp[2] * ndcx + inv_mvp[6] * ndcy + inv_mvp[10] * ndcz + inv_mvp[14];*/ nuclear@11: *objx = inv_mvp[0] * ndcx + inv_mvp[1] * ndcy + inv_mvp[2] * ndcz + inv_mvp[3]; nuclear@11: *objy = inv_mvp[4] * ndcx + inv_mvp[5] * ndcy + inv_mvp[6] * ndcz + inv_mvp[7]; nuclear@11: *objz = inv_mvp[8] * ndcx + inv_mvp[9] * ndcy + inv_mvp[10] * ndcz + inv_mvp[11]; nuclear@11: return 0; nuclear@11: } nuclear@11: nuclear@11: void gl_apply_xform(unsigned int prog) nuclear@11: { nuclear@11: int loc, mvidx, pidx, tidx, mvtop, ptop, ttop; nuclear@11: nuclear@11: mvidx = MMODE_IDX(GL_MODELVIEW); nuclear@11: pidx = MMODE_IDX(GL_PROJECTION); nuclear@11: tidx = MMODE_IDX(GL_TEXTURE); nuclear@11: nuclear@11: mvtop = stack_top[mvidx]; nuclear@11: ptop = stack_top[pidx]; nuclear@11: ttop = stack_top[tidx]; nuclear@11: nuclear@11: assert(prog); nuclear@11: nuclear@11: /*printf("APPLY XFORM\n");*/ nuclear@11: nuclear@11: CHECK_GLERROR; nuclear@11: if((loc = glGetUniformLocation(prog, "matrix_modelview")) != -1) { nuclear@11: CHECK_GLERROR; nuclear@11: /*printf(" MODELVIEW:\n"); nuclear@11: for(i=0; i<16; i+=4) { nuclear@11: printf("%.2f %.2f %.2f %.2f\n", mat_stack[mvidx][mvtop][i], mat_stack[mvidx][mvtop][i + 1], mat_stack[mvidx][mvtop][i + 2], mat_stack[mvidx][mvtop][i + 3]); nuclear@11: }*/ nuclear@11: glUniformMatrix4fv(loc, 1, 0, mat_stack[mvidx][mvtop]); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: CHECK_GLERROR; nuclear@11: nuclear@11: if((loc = glGetUniformLocation(prog, "matrix_projection")) != -1) { nuclear@11: CHECK_GLERROR; nuclear@11: /*printf(" PROJECTION:\n"); nuclear@11: for(i=0; i<16; i+=4) { nuclear@11: printf("%.2f %.2f %.2f %.2f\n", mat_stack[pidx][ptop][i], mat_stack[pidx][ptop][i + 1], mat_stack[pidx][ptop][i + 2], mat_stack[pidx][ptop][i + 3]); nuclear@11: }*/ nuclear@11: glUniformMatrix4fv(loc, 1, 0, mat_stack[pidx][ptop]); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: CHECK_GLERROR; nuclear@11: nuclear@11: if((loc = glGetUniformLocation(prog, "matrix_texture")) != -1) { nuclear@11: CHECK_GLERROR; nuclear@11: glUniformMatrix4fv(loc, 1, 0, mat_stack[tidx][ttop]); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: CHECK_GLERROR; nuclear@11: nuclear@11: if((loc = glGetUniformLocation(prog, "matrix_normal")) != -1) { nuclear@11: float nmat[9]; nuclear@11: nuclear@11: CHECK_GLERROR; nuclear@11: nuclear@11: nmat[0] = mat_stack[mvidx][mvtop][0]; nuclear@11: nmat[1] = mat_stack[mvidx][mvtop][1]; nuclear@11: nmat[2] = mat_stack[mvidx][mvtop][2]; nuclear@11: nmat[3] = mat_stack[mvidx][mvtop][4]; nuclear@11: nmat[4] = mat_stack[mvidx][mvtop][5]; nuclear@11: nmat[5] = mat_stack[mvidx][mvtop][6]; nuclear@11: nmat[6] = mat_stack[mvidx][mvtop][8]; nuclear@11: nmat[7] = mat_stack[mvidx][mvtop][9]; nuclear@11: nmat[8] = mat_stack[mvidx][mvtop][10]; nuclear@11: glUniformMatrix3fv(loc, 1, 0, nmat); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: CHECK_GLERROR; nuclear@11: nuclear@11: if((loc = glGetUniformLocation(prog, "matrix_modelview_projection")) != -1) { nuclear@11: CHECK_GLERROR; nuclear@11: if(!mvp_valid) { nuclear@11: /* TODO calc mvp */ nuclear@11: } nuclear@11: glUniformMatrix4fv(loc, 1, 0, mat_mvp); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: nuclear@11: nuclear@11: /* immediate mode rendering */ nuclear@11: void gl_begin(int p) nuclear@11: { nuclear@11: if(!vert_arr) { nuclear@11: vert_arr = malloc(MAX_VERTS * sizeof *vert_arr); nuclear@11: norm_arr = malloc(MAX_VERTS * sizeof *norm_arr); nuclear@11: texc_arr = malloc(MAX_VERTS * sizeof *texc_arr); nuclear@11: col_arr = malloc(MAX_VERTS * sizeof *col_arr); nuclear@11: attr_arr = malloc(MAX_VERTS * sizeof *attr_arr); nuclear@11: assert(vert_arr && norm_arr && texc_arr && col_arr && attr_arr); nuclear@11: } nuclear@11: nuclear@11: prim = p; nuclear@11: num_verts = vert_calls = 0; nuclear@11: nuclear@11: glGetIntegerv(GL_CURRENT_PROGRAM, &cur_prog); nuclear@11: CHECK_GLERROR; nuclear@11: assert(cur_prog); nuclear@11: nuclear@11: gl_apply_xform(cur_prog); nuclear@11: CHECK_GLERROR; nuclear@11: nuclear@11: vloc = glGetAttribLocation(cur_prog, "attr_vertex"); nuclear@11: CHECK_GLERROR; nuclear@11: nloc = glGetAttribLocation(cur_prog, "attr_normal"); nuclear@11: CHECK_GLERROR; nuclear@11: cloc = glGetAttribLocation(cur_prog, "attr_color"); nuclear@11: CHECK_GLERROR; nuclear@11: tloc = glGetAttribLocation(cur_prog, "attr_texcoord"); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: nuclear@11: void gl_end(void) nuclear@11: { nuclear@11: if(num_verts > 0) { nuclear@11: gl_draw_immediate(); nuclear@11: } nuclear@11: aloc = -1; nuclear@11: } nuclear@11: nuclear@11: static void gl_draw_immediate(void) nuclear@11: { nuclear@11: int glprim; nuclear@11: nuclear@11: if(vloc == -1) { nuclear@11: fprintf(stderr, "gl_draw_immediate call with vloc == -1\n"); nuclear@11: return; nuclear@11: } nuclear@11: nuclear@11: glprim = prim == GL_QUADS ? GL_TRIANGLES : prim; nuclear@11: nuclear@11: CHECK_GLERROR; nuclear@11: glVertexAttribPointer(vloc, 4, GL_FLOAT, 0, 0, vert_arr); nuclear@11: CHECK_GLERROR; nuclear@11: glEnableVertexAttribArray(vloc); nuclear@11: CHECK_GLERROR; nuclear@11: nuclear@11: if(nloc != -1) { nuclear@11: glVertexAttribPointer(nloc, 3, GL_FLOAT, 0, 0, norm_arr); nuclear@11: CHECK_GLERROR; nuclear@11: glEnableVertexAttribArray(nloc); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: nuclear@11: if(cloc != -1) { nuclear@11: glVertexAttribPointer(cloc, 4, GL_FLOAT, 1, 0, col_arr); nuclear@11: CHECK_GLERROR; nuclear@11: glEnableVertexAttribArray(cloc); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: nuclear@11: if(tloc != -1) { nuclear@11: glVertexAttribPointer(tloc, 2, GL_FLOAT, 0, 0, texc_arr); nuclear@11: CHECK_GLERROR; nuclear@11: glEnableVertexAttribArray(tloc); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: nuclear@11: if(aloc != -1) { nuclear@11: glVertexAttribPointer(aloc, 4, GL_FLOAT, 0, 0, attr_arr); nuclear@11: CHECK_GLERROR; nuclear@11: glEnableVertexAttribArray(aloc); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: nuclear@11: glDrawArrays(glprim, 0, num_verts); nuclear@11: CHECK_GLERROR; nuclear@11: nuclear@11: glDisableVertexAttribArray(vloc); nuclear@11: CHECK_GLERROR; nuclear@11: if(nloc != -1) { nuclear@11: glDisableVertexAttribArray(nloc); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: if(cloc != -1) { nuclear@11: glDisableVertexAttribArray(cloc); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: if(tloc != -1) { nuclear@11: glDisableVertexAttribArray(tloc); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: if(aloc != -1) { nuclear@11: glDisableVertexAttribArray(aloc); nuclear@11: CHECK_GLERROR; nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: nuclear@11: void gl_vertex2f(float x, float y) nuclear@11: { nuclear@11: gl_vertex4f(x, y, 0.0f, 1.0f); nuclear@11: } nuclear@11: nuclear@11: void gl_vertex3f(float x, float y, float z) nuclear@11: { nuclear@11: gl_vertex4f(x, y, z, 1.0f); nuclear@11: } nuclear@11: nuclear@11: void gl_vertex4f(float x, float y, float z, float w) nuclear@11: { nuclear@11: int i, buffer_full; nuclear@11: nuclear@11: if(prim == GL_QUADS && vert_calls % 4 == 3) { nuclear@11: for(i=0; i<2; i++) { nuclear@11: if(aloc != -1) { nuclear@11: attr_arr[num_verts] = attr_arr[num_verts - 3 + i]; nuclear@11: } nuclear@11: if(cloc != -1) { nuclear@11: col_arr[num_verts] = col_arr[num_verts - 3 + i]; nuclear@11: } nuclear@11: if(tloc != -1) { nuclear@11: texc_arr[num_verts] = texc_arr[num_verts - 3 + i]; nuclear@11: } nuclear@11: if(nloc != -1) { nuclear@11: norm_arr[num_verts] = norm_arr[num_verts - 3 + i]; nuclear@11: } nuclear@11: vert_arr[num_verts] = vert_arr[num_verts - 3 + i]; nuclear@11: num_verts++; nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: vert_arr[num_verts].x = x; nuclear@11: vert_arr[num_verts].y = y; nuclear@11: vert_arr[num_verts].z = z; nuclear@11: vert_arr[num_verts].w = w; nuclear@11: nuclear@11: if(cloc != -1) { nuclear@11: col_arr[num_verts] = cur_color; nuclear@11: } nuclear@11: if(nloc != -1) { nuclear@11: norm_arr[num_verts] = cur_normal; nuclear@11: } nuclear@11: if(tloc != -1) { nuclear@11: texc_arr[num_verts] = cur_texcoord; nuclear@11: } nuclear@11: if(aloc != -1) { nuclear@11: attr_arr[num_verts] = cur_attrib; nuclear@11: } nuclear@11: nuclear@11: vert_calls++; nuclear@11: num_verts++; nuclear@11: nuclear@11: if(prim == GL_QUADS) { nuclear@11: /* leave space for 6 more worst-case and don't allow flushes mid-quad */ nuclear@11: buffer_full = num_verts >= MAX_VERTS - 6 && vert_calls % 4 == 0; nuclear@11: } else { nuclear@11: buffer_full = num_verts >= MAX_VERTS - prim; nuclear@11: } nuclear@11: nuclear@11: if(buffer_full) { nuclear@11: gl_draw_immediate(); nuclear@11: gl_begin(prim); /* reset everything */ nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: nuclear@11: void gl_normal3f(float x, float y, float z) nuclear@11: { nuclear@11: cur_normal.x = x; nuclear@11: cur_normal.y = y; nuclear@11: cur_normal.z = z; nuclear@11: } nuclear@11: nuclear@11: nuclear@11: void gl_color3f(float r, float g, float b) nuclear@11: { nuclear@11: cur_color.x = r; nuclear@11: cur_color.y = g; nuclear@11: cur_color.z = b; nuclear@11: cur_color.w = 1.0f; nuclear@11: } nuclear@11: nuclear@11: void gl_color4f(float r, float g, float b, float a) nuclear@11: { nuclear@11: cur_color.x = r; nuclear@11: cur_color.y = g; nuclear@11: cur_color.z = b; nuclear@11: cur_color.w = a; nuclear@11: } nuclear@11: nuclear@11: nuclear@11: void gl_texcoord1f(float s) nuclear@11: { nuclear@11: cur_texcoord.x = s; nuclear@11: cur_texcoord.y = 0.0f; nuclear@11: } nuclear@11: nuclear@11: void gl_texcoord2f(float s, float t) nuclear@11: { nuclear@11: cur_texcoord.x = s; nuclear@11: cur_texcoord.y = t; nuclear@11: } nuclear@11: nuclear@11: void gl_vertex_attrib2f(int loc, float x, float y) nuclear@11: { nuclear@11: aloc = loc; nuclear@11: cur_attrib.x = x; nuclear@11: cur_attrib.y = y; nuclear@11: cur_attrib.z = 0.0f; nuclear@11: cur_attrib.w = 1.0f; nuclear@11: } nuclear@11: nuclear@11: void gl_vertex_attrib3f(int loc, float x, float y, float z) nuclear@11: { nuclear@11: aloc = loc; nuclear@11: cur_attrib.x = x; nuclear@11: cur_attrib.y = y; nuclear@11: cur_attrib.z = z; nuclear@11: cur_attrib.w = 1.0f; nuclear@11: } nuclear@11: nuclear@11: void gl_vertex_attrib4f(int loc, float x, float y, float z, float w) nuclear@11: { nuclear@11: aloc = loc; nuclear@11: cur_attrib.x = x; nuclear@11: cur_attrib.y = y; nuclear@11: cur_attrib.z = z; nuclear@11: cur_attrib.w = w; nuclear@11: } nuclear@11: nuclear@11: #ifdef GLDEF nuclear@11: #undef glGetFloatv nuclear@11: #endif nuclear@11: nuclear@11: void gl_get_floatv(int what, float *res) nuclear@11: { nuclear@11: int idx; nuclear@11: nuclear@11: switch(what) { nuclear@11: case GL_MODELVIEW_MATRIX: nuclear@11: idx = MMODE_IDX(GL_MODELVIEW); nuclear@11: memcpy(res, mat_stack[idx][stack_top[idx]], 16 * sizeof *res); nuclear@11: break; nuclear@11: nuclear@11: case GL_PROJECTION_MATRIX: nuclear@11: idx = MMODE_IDX(GL_PROJECTION); nuclear@11: memcpy(res, mat_stack[idx][stack_top[idx]], 16 * sizeof *res); nuclear@11: break; nuclear@11: nuclear@11: default: nuclear@11: glGetFloatv(what, res); nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: void gl_get_doublev(int what, double *res) nuclear@11: { nuclear@11: int i, idx; nuclear@11: float tmp[16]; nuclear@11: nuclear@11: switch(what) { nuclear@11: case GL_MODELVIEW_MATRIX: nuclear@11: if(1) { nuclear@11: idx = MMODE_IDX(GL_MODELVIEW); nuclear@11: } else { nuclear@11: case GL_PROJECTION_MATRIX: nuclear@11: idx = MMODE_IDX(GL_PROJECTION); nuclear@11: } nuclear@11: for(i=0; i<16; i++) { nuclear@11: res[i] = mat_stack[idx][stack_top[idx]][i]; nuclear@11: } nuclear@11: break; nuclear@11: nuclear@11: default: nuclear@11: glGetFloatv(what, tmp); nuclear@11: for(i=0; i<16; i++) { nuclear@11: res[i] = tmp[i]; nuclear@11: } nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: nuclear@11: /* ---- matrix inversion stuff ---- */ nuclear@11: static void m4_transpose(double *res, double *m) nuclear@11: { nuclear@11: int i, j; nuclear@11: double tmp[16]; nuclear@11: nuclear@11: if(res == m) { nuclear@11: memcpy(tmp, m, 16 * sizeof *m); nuclear@11: m = tmp; nuclear@11: } nuclear@11: nuclear@11: for(i=0; i<4; i++) { nuclear@11: for(j=0; j<4; j++) { nuclear@11: res[M(i, j)] = m[M(j, i)]; nuclear@11: } nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: static double m4_determinant(double *m) nuclear@11: { nuclear@11: double det11, det12, det13, det14; nuclear@11: nuclear@11: det11 = (m[M(1, 1)] * (m[M(2, 2)] * m[M(3, 3)] - m[M(3, 2)] * m[M(2, 3)])) - nuclear@11: (m[M(1, 2)] * (m[M(2, 1)] * m[M(3, 3)] - m[M(3, 1)] * m[M(2, 3)])) + nuclear@11: (m[M(1, 3)] * (m[M(2, 1)] * m[M(3, 2)] - m[M(3, 1)] * m[M(2, 2)])); nuclear@11: nuclear@11: det12 = (m[M(1, 0)] * (m[M(2, 2)] * m[M(3, 3)] - m[M(3, 2)] * m[M(2, 3)])) - nuclear@11: (m[M(1, 2)] * (m[M(2, 0)] * m[M(3, 3)] - m[M(3, 0)] * m[M(2, 3)])) + nuclear@11: (m[M(1, 3)] * (m[M(2, 0)] * m[M(3, 2)] - m[M(3, 0)] * m[M(2, 2)])); nuclear@11: nuclear@11: det13 = (m[M(1, 0)] * (m[M(2, 1)] * m[M(3, 3)] - m[M(3, 1)] * m[M(2, 3)])) - nuclear@11: (m[M(1, 1)] * (m[M(2, 0)] * m[M(3, 3)] - m[M(3, 0)] * m[M(2, 3)])) + nuclear@11: (m[M(1, 3)] * (m[M(2, 0)] * m[M(3, 1)] - m[M(3, 0)] * m[M(2, 1)])); nuclear@11: nuclear@11: det14 = (m[M(1, 0)] * (m[M(2, 1)] * m[M(3, 2)] - m[M(3, 1)] * m[M(2, 2)])) - nuclear@11: (m[M(1, 1)] * (m[M(2, 0)] * m[M(3, 2)] - m[M(3, 0)] * m[M(2, 2)])) + nuclear@11: (m[M(1, 2)] * (m[M(2, 0)] * m[M(3, 1)] - m[M(3, 0)] * m[M(2, 1)])); nuclear@11: nuclear@11: return m[M(0, 0)] * det11 - m[M(0, 1)] * det12 + m[M(0, 2)] * det13 - m[M(0, 3)] * det14; nuclear@11: } nuclear@11: nuclear@11: static void m4_adjoint(double *res, double *m) nuclear@11: { nuclear@11: int i, j; nuclear@11: double coef[16]; nuclear@11: nuclear@11: coef[M(0, 0)] = (m[M(1, 1)] * (m[M(2, 2)] * m[M(3, 3)] - m[M(3, 2)] * m[M(2, 3)])) - nuclear@11: (m[M(1, 2)] * (m[M(2, 1)] * m[M(3, 3)] - m[M(3, 1)] * m[M(2, 3)])) + nuclear@11: (m[M(1, 3)] * (m[M(2, 1)] * m[M(3, 2)] - m[M(3, 1)] * m[M(2, 2)])); nuclear@11: coef[M(0, 1)] = (m[M(1, 0)] * (m[M(2, 2)] * m[M(3, 3)] - m[M(3, 2)] * m[M(2, 3)])) - nuclear@11: (m[M(1, 2)] * (m[M(2, 0)] * m[M(3, 3)] - m[M(3, 0)] * m[M(2, 3)])) + nuclear@11: (m[M(1, 3)] * (m[M(2, 0)] * m[M(3, 2)] - m[M(3, 0)] * m[M(2, 2)])); nuclear@11: coef[M(0, 2)] = (m[M(1, 0)] * (m[M(2, 1)] * m[M(3, 3)] - m[M(3, 1)] * m[M(2, 3)])) - nuclear@11: (m[M(1, 1)] * (m[M(2, 0)] * m[M(3, 3)] - m[M(3, 0)] * m[M(2, 3)])) + nuclear@11: (m[M(1, 3)] * (m[M(2, 0)] * m[M(3, 1)] - m[M(3, 0)] * m[M(2, 1)])); nuclear@11: coef[M(0, 3)] = (m[M(1, 0)] * (m[M(2, 1)] * m[M(3, 2)] - m[M(3, 1)] * m[M(2, 2)])) - nuclear@11: (m[M(1, 1)] * (m[M(2, 0)] * m[M(3, 2)] - m[M(3, 0)] * m[M(2, 2)])) + nuclear@11: (m[M(1, 2)] * (m[M(2, 0)] * m[M(3, 1)] - m[M(3, 0)] * m[M(2, 1)])); nuclear@11: nuclear@11: coef[M(1, 0)] = (m[M(0, 1)] * (m[M(2, 2)] * m[M(3, 3)] - m[M(3, 2)] * m[M(2, 3)])) - nuclear@11: (m[M(0, 2)] * (m[M(2, 1)] * m[M(3, 3)] - m[M(3, 1)] * m[M(2, 3)])) + nuclear@11: (m[M(0, 3)] * (m[M(2, 1)] * m[M(3, 2)] - m[M(3, 1)] * m[M(2, 2)])); nuclear@11: coef[M(1, 1)] = (m[M(0, 0)] * (m[M(2, 2)] * m[M(3, 3)] - m[M(3, 2)] * m[M(2, 3)])) - nuclear@11: (m[M(0, 2)] * (m[M(2, 0)] * m[M(3, 3)] - m[M(3, 0)] * m[M(2, 3)])) + nuclear@11: (m[M(0, 3)] * (m[M(2, 0)] * m[M(3, 2)] - m[M(3, 0)] * m[M(2, 2)])); nuclear@11: coef[M(1, 2)] = (m[M(0, 0)] * (m[M(2, 1)] * m[M(3, 3)] - m[M(3, 1)] * m[M(2, 3)])) - nuclear@11: (m[M(0, 1)] * (m[M(2, 0)] * m[M(3, 3)] - m[M(3, 0)] * m[M(2, 3)])) + nuclear@11: (m[M(0, 3)] * (m[M(2, 0)] * m[M(3, 1)] - m[M(3, 0)] * m[M(2, 1)])); nuclear@11: coef[M(1, 3)] = (m[M(0, 0)] * (m[M(2, 1)] * m[M(3, 2)] - m[M(3, 1)] * m[M(2, 2)])) - nuclear@11: (m[M(0, 1)] * (m[M(2, 0)] * m[M(3, 2)] - m[M(3, 0)] * m[M(2, 2)])) + nuclear@11: (m[M(0, 2)] * (m[M(2, 0)] * m[M(3, 1)] - m[M(3, 0)] * m[M(2, 1)])); nuclear@11: nuclear@11: coef[M(2, 0)] = (m[M(0, 1)] * (m[M(1, 2)] * m[M(3, 3)] - m[M(3, 2)] * m[M(1, 3)])) - nuclear@11: (m[M(0, 2)] * (m[M(1, 1)] * m[M(3, 3)] - m[M(3, 1)] * m[M(1, 3)])) + nuclear@11: (m[M(0, 3)] * (m[M(1, 1)] * m[M(3, 2)] - m[M(3, 1)] * m[M(1, 2)])); nuclear@11: coef[M(2, 1)] = (m[M(0, 0)] * (m[M(1, 2)] * m[M(3, 3)] - m[M(3, 2)] * m[M(1, 3)])) - nuclear@11: (m[M(0, 2)] * (m[M(1, 0)] * m[M(3, 3)] - m[M(3, 0)] * m[M(1, 3)])) + nuclear@11: (m[M(0, 3)] * (m[M(1, 0)] * m[M(3, 2)] - m[M(3, 0)] * m[M(1, 2)])); nuclear@11: coef[M(2, 2)] = (m[M(0, 0)] * (m[M(1, 1)] * m[M(3, 3)] - m[M(3, 1)] * m[M(1, 3)])) - nuclear@11: (m[M(0, 1)] * (m[M(1, 0)] * m[M(3, 3)] - m[M(3, 0)] * m[M(1, 3)])) + nuclear@11: (m[M(0, 3)] * (m[M(1, 0)] * m[M(3, 1)] - m[M(3, 0)] * m[M(1, 1)])); nuclear@11: coef[M(2, 3)] = (m[M(0, 0)] * (m[M(1, 1)] * m[M(3, 2)] - m[M(3, 1)] * m[M(1, 2)])) - nuclear@11: (m[M(0, 1)] * (m[M(1, 0)] * m[M(3, 2)] - m[M(3, 0)] * m[M(1, 2)])) + nuclear@11: (m[M(0, 2)] * (m[M(1, 0)] * m[M(3, 1)] - m[M(3, 0)] * m[M(1, 1)])); nuclear@11: nuclear@11: coef[M(3, 0)] = (m[M(0, 1)] * (m[M(1, 2)] * m[M(2, 3)] - m[M(2, 2)] * m[M(1, 3)])) - nuclear@11: (m[M(0, 2)] * (m[M(1, 1)] * m[M(2, 3)] - m[M(2, 1)] * m[M(1, 3)])) + nuclear@11: (m[M(0, 3)] * (m[M(1, 1)] * m[M(2, 2)] - m[M(2, 1)] * m[M(1, 2)])); nuclear@11: coef[M(3, 1)] = (m[M(0, 0)] * (m[M(1, 2)] * m[M(2, 3)] - m[M(2, 2)] * m[M(1, 3)])) - nuclear@11: (m[M(0, 2)] * (m[M(1, 0)] * m[M(2, 3)] - m[M(2, 0)] * m[M(1, 3)])) + nuclear@11: (m[M(0, 3)] * (m[M(1, 0)] * m[M(2, 2)] - m[M(2, 0)] * m[M(1, 2)])); nuclear@11: coef[M(3, 2)] = (m[M(0, 0)] * (m[M(1, 1)] * m[M(2, 3)] - m[M(2, 1)] * m[M(1, 3)])) - nuclear@11: (m[M(0, 1)] * (m[M(1, 0)] * m[M(2, 3)] - m[M(2, 0)] * m[M(1, 3)])) + nuclear@11: (m[M(0, 3)] * (m[M(1, 0)] * m[M(2, 1)] - m[M(2, 0)] * m[M(1, 1)])); nuclear@11: coef[M(3, 3)] = (m[M(0, 0)] * (m[M(1, 1)] * m[M(2, 2)] - m[M(2, 1)] * m[M(1, 2)])) - nuclear@11: (m[M(0, 1)] * (m[M(1, 0)] * m[M(2, 2)] - m[M(2, 0)] * m[M(1, 2)])) + nuclear@11: (m[M(0, 2)] * (m[M(1, 0)] * m[M(2, 1)] - m[M(2, 0)] * m[M(1, 1)])); nuclear@11: nuclear@11: m4_transpose(res, coef); nuclear@11: nuclear@11: for(i=0; i<4; i++) { nuclear@11: for(j=0; j<4; j++) { nuclear@11: res[M(i, j)] = j % 2 ? -res[M(i, j)] : res[M(i, j)]; nuclear@11: if(i % 2) res[M(i, j)] = -res[M(i, j)]; nuclear@11: } nuclear@11: } nuclear@11: } nuclear@11: nuclear@11: static void m4_inverse(double *res, double *m) nuclear@11: { nuclear@11: int i, j; nuclear@11: double adj[16]; nuclear@11: double det; nuclear@11: nuclear@11: m4_adjoint(adj, m); nuclear@11: det = m4_determinant(m); nuclear@11: nuclear@11: for(i=0; i<4; i++) { nuclear@11: for(j=0; j<4; j++) { nuclear@11: res[M(i, j)] = adj[M(i, j)] / det; nuclear@11: } nuclear@11: } nuclear@11: } nuclear@11: