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